请问哪个为知笔记网页版软件支持给本地和网页文章同1篇文中的各个片断分别加1或多个标签?谢谢

热门搜索:
(dfs)POJ1321 棋盘问题。
python将文本分每两行一组。
网络安全的第二道防线:区块链。在网络安全第一部分中,我们将AI作为网络安全的第一道防线,目标是让网络犯罪分子受到AI的困境,然后落网,但如果他们设法进入并渗透到网络中,我们需要启动第二道防线:区块链。事实上,网络犯罪和网络安全攻击经常出现。
请注意:这是一款史上最流氓的QQ营销病毒。在“流量为王”的时代,流量从某种意义上来讲,就意味着金钱。一条依附在流量上的营销产业链条正暗流涌动,他们依靠社交软件这个平台,疯狂加好友、加群,来散播广告、色情、赌博等内容,从而获取流量。
Spring JDBC RowMapper接口。
简单计算程序运行时间 and 解决模板实例重复链接问题。
数字货币正在全世界范围持续火爆,除了资本的激烈角逐和普通玩家的关注,许多不法分子也趁机抢搭上数字货币“致富”的列车,发起网络攻击活动,对相关机构及用户的信息财产安全造成极大威胁。
Wooden Sticks(贪心)问题解析。
字符串计数 (后缀自动机+二分答案+矩阵快速幂)。
区块链的数字账本能让商业交易的安全性迈上空前新高度,因而区块链技术如今正受到热捧,重视安全的新解决方案寻求者无不对区块链技术大感兴趣。然而,大部分人,甚至资深IT专家和业界观察家,都对已出现10年之久的区块链概念不甚了解。
新型银行木马Anubis来袭,集合勒索软件、键盘记录器、远程木马于一身。根据网络安全公司PhishLabs的说法,他们在本月5日发现了银行木马BankBot的一个新变种,正通过伪装成合法应用Adobe Flash Player、Avito和HD Video Player进行传播。
近500万部安卓手机感染恶意广告病毒 这些手机统统中招。最近,安全公司CheckPoint发现了中国多款主流安卓手机,正遭受同一个团伙制造的手机恶意广告推送,中招的有荣耀、华为、小米、OPPO、vivo等。
本编对小马激活Oem7F7情有独钟,因为是我第一个使用的win7激活工具,并且我利用该win7激活工具帮助过很多朋友,那么现在就由我来教大家如何使用小马激活工具。
最好用的win7激活工具,最新小马win7激活工具,小马激活工具大全,win7旗舰版激活工具使用教程,win7激活工具64位,win7激活工具32位,win7激活工具由2cto com提供教程说明及下载地址大全。
1、红黑联盟首页改版。
Android/IOS
php/jsp/asp
微信公众开发平台
电子书下载
友情链接(首页PR,BR>=5、alexa排名1万以内、日IP大于10万,子频道另谈!)
版权所有: 红黑联盟--IT精英由此起航
内容来自互联网,仅供用于技术学习,请遵循相关法律法规.黑客不作恶.博客分类:
之前虽然会用JDK的动态代理,但是有些问题却一直没有搞明白。比如说:InvocationHandler的invoke方法是由谁来调用的,代理对象是怎么生成的,直到前几个星期才把这些问题全部搞明白了。
&&& 废话不多说了,先来看一下JDK的动态是怎么用的。
package dynamic.
import java.lang.reflect.InvocationH
import java.lang.reflect.M
import java.lang.reflect.P
* 实现自己的InvocationHandler
* @author zyb
public class MyInvocationHandler implements InvocationHandler {
// 目标对象
* 构造方法
* @param target 目标对象
public MyInvocationHandler(Object target) {
this.target =
* 执行目标对象的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在目标对象的方法执行之前简单的打印一下
System.out.println("------------------before------------------");
// 执行目标对象的方法
Object result = method.invoke(target, args);
// 在目标对象的方法执行之后简单的打印一下
System.out.println("-------------------after------------------");
* 获取目标对象的代理对象
* @return 代理对象
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(), this);
package dynamic.
* 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口
* @author zyb
public interface UserService {
* 目标方法
public abstract void add();
package dynamic.
* 目标对象
* @author zyb
public class UserServiceImpl implements UserService {
/* (non-Javadoc)
* @see dynamic.proxy.UserService#add()
public void add() {
System.out.println("--------------------add---------------");
package dynamic.
import org.junit.T
* 动态代理测试类
* @author zyb
public class ProxyTest {
public void testProxy() throws Throwable {
// 实例化目标对象
UserService userService = new UserServiceImpl();
// 实例化InvocationHandler
MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
// 根据目标对象生成代理对象
UserService proxy = (UserService) invocationHandler.getProxy();
// 调用代理对象的方法
proxy.add();
执行结果如下:
------------------before------------------
--------------------add---------------
-------------------after------------------
&& 用起来是很简单吧,其实这里基本上就是AOP的一个简单实现了,在目标对象的方法执行之前和执行之后进行了增强。Spring的AOP实现其实也是用了Proxy和InvocationHandler这两个东西的。
&&& 用起来是比较简单,但是如果能知道它背后做了些什么手脚,那就更好不过了。首先来看一下JDK是怎样生成代理对象的。既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么?
* loader:类加载器
* interfaces:目标对象实现的接口
* h:InvocationHandler的实现类
public static Object newProxyInstance(ClassLoader loader,
Class&?&[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
if (h == null) {
throw new NullPointerException();
* Look up or generate the designated proxy class.
Class cl = getProxyClass(loader, interfaces);
* Invoke its constructor with the designated invocation handler.
// 调用代理对象的构造方法(也就是$Proxy0(InvocationHandler h))
Constructor cons = cl.getConstructor(constructorParams);
// 生成代理类的实例并把MyInvocationHandler的实例传给它的构造方法
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
throw new InternalError(e.toString());
&& 我们再进去getProxyClass方法看一下
public static Class&?& getProxyClass(ClassLoader loader,
Class&?&... interfaces)
throws IllegalArgumentException
// 如果目标类实现的接口数大于65535个则抛出异常(我XX,谁会写这么NB的代码啊?)
if (interfaces.length & 65535) {
throw new IllegalArgumentException("interface limit exceeded");
// 声明代理对象所代表的Class对象(有点拗口)
Class proxyClass =
String[] interfaceNames = new String[interfaces.length];
Set interfaceSet = new HashSet(); // for detecting duplicates
// 遍历目标类所实现的接口
for (int i = 0; i & interfaces. i++) {
// 拿到目标类实现的接口的名称
String interfaceName = interfaces[i].getName();
Class interfaceClass =
// 加载目标类实现的接口到内存中
interfaceClass = Class.forName(interfaceName, false, loader);
} catch (ClassNotFoundException e) {
if (interfaceClass != interfaces[i]) {
throw new IllegalArgumentException(
interfaces[i] + " is not visible from class loader");
// 中间省略了一些无关紧要的代码 .......
// 把目标类实现的接口代表的Class对象放到Set中
interfaceSet.add(interfaceClass);
interfaceNames[i] = interfaceN
// 把目标类实现的接口名称作为缓存(Map)中的key
Object key = Arrays.asList(interfaceNames);
synchronized (loaderToCache) {
// 从缓存中获取cache
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
// 如果获取不到,则新建地个HashMap实例
cache = new HashMap();
// 把HashMap实例和当前加载器放到缓存中
loaderToCache.put(loader, cache);
synchronized (cache) {
// 根据接口的名称从缓存中获取对象
Object value = cache.get(key);
if (value instanceof Reference) {
proxyClass = (Class) ((Reference) value).get();
if (proxyClass != null) {
// 如果代理对象的Class实例已经存在,则直接返回
return proxyC
} else if (value == pendingGenerationMarker) {
cache.wait();
} catch (InterruptedException e) {
cache.put(key, pendingGenerationMarker);
} while (true);
// 中间省略了一些代码 .......
// 这里就是动态生成代理对象的最关键的地方
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
// 根据代理类的字节码生成代理类的实例
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
// add to set of all generated proxy classes, for isProxyClass
proxyClasses.put(proxyClass, null);
// 中间省略了一些代码 .......
return proxyC
进去ProxyGenerator类的静态方法generateProxyClass,这里是真正生成代理类class字节码的地方。
public static byte[] generateProxyClass(final String name,
Class[] interfaces)
ProxyGenerator gen = new ProxyGenerator(name, interfaces);
// 这里动态生成代理类的字节码,由于比较复杂就不进去看了
final byte[] classFile = gen.generateClassFile();
// 如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上
if (saveGeneratedFiles) {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction&Void&() {
public Void run() {
FileOutputStream file =
new FileOutputStream(dotToSlash(name) + ".class");
file.write(classFile);
file.close();
} catch (IOException e) {
throw new InternalError(
"I/O exception saving generated file: " + e);
// 返回代理类的字节码
return classF
现在,JDK是怎样动态生成代理类的字节的原理已经一目了然了。
好了,再来解决另外一个问题,那就是由谁来调用InvocationHandler的invoke方法的。要解决这个问题就要看一下JDK到底为我们生成了一个什么东西。用以下代码可以获取到JDK为我们生成的字节码并写到硬盘中。
package dynamic.
import java.io.FileOutputS
import java.io.IOE
import sun.misc.ProxyG
* 代理类的生成工具
* @author zyb
public class ProxyGeneratorUtils {
* 把代理类的字节码写到硬盘上
* @param path 保存路径
public static void writeProxyClassToHardDisk(String path) {
// 第一种方法,这种方式在刚才分析ProxyGenerator时已经知道了
// System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", true);
// 第二种方法
// 获取代理类的字节码
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", UserServiceImpl.class.getInterfaces());
FileOutputStream out =
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
} catch (IOException e) {
e.printStackTrace();
package dynamic.
import org.junit.T
* 动态代理测试类
* @author zyb
public class ProxyTest {
public void testProxy() throws Throwable {
// 实例化目标对象
UserService userService = new UserServiceImpl();
// 实例化InvocationHandler
MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
// 根据目标对象生成代理对象
UserService proxy = (UserService) invocationHandler.getProxy();
// 调用代理对象的方法
proxy.add();
public void testGenerateProxyClass() {
ProxyGeneratorUtils.writeProxyClassToHardDisk("F:/$Proxy11.class");
通过以上代码,就可以在F盘上生成一个$Proxy.class文件了,现在用反编译工具来看一下这个class文件里面的内容。
// Decompiled by DJ v3.11.11.95 Copyright 2009 Atanas Neshkov
// Home Page: http://members.fortunecity.com/neshkov/dj.html
http://www.neshkov.com/dj.html - Check often for new version!
// Decompiler options: packimports(3)
import dynamic.proxy.UserS
import java.lang.reflect.*;
public final class $Proxy11 extends Proxy
implements UserService
// 构造方法,参数就是刚才传过来的MyInvocationHandler类的实例
public $Proxy11(InvocationHandler invocationhandler)
super(invocationhandler);
public final boolean equals(Object obj)
return ((Boolean)super.h.invoke(this, m1, new Object[] {
})).booleanValue();
catch(Error _ex) { }
catch(Throwable throwable)
throw new UndeclaredThrowableException(throwable);
* 这个方法是关键部分
public final void add()
// 实际上就是调用MyInvocationHandler的public Object invoke(Object proxy, Method method, Object[] args)方法,第二个问题就解决了
super.h.invoke(this, m3, null);
catch(Error _ex) { }
catch(Throwable throwable)
throw new UndeclaredThrowableException(throwable);
public final int hashCode()
return ((Integer)super.h.invoke(this, m0, null)).intValue();
catch(Error _ex) { }
catch(Throwable throwable)
throw new UndeclaredThrowableException(throwable);
public final String toString()
return (String)super.h.invoke(this, m2, null);
catch(Error _ex) { }
catch(Throwable throwable)
throw new UndeclaredThrowableException(throwable);
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
// 在静态代码块中获取了4个方法:Object中的equals方法、UserService中的add方法、Object中的hashCode方法、Object中toString方法
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
catch(NoSuchMethodException nosuchmethodexception)
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
catch(ClassNotFoundException classnotfoundexception)
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
好了,到目前为止,前面 的两个问题都已经知道回事了,现在再用JDK动态代理的时候就不只会用而已了,真正的达到了“知其然,知其所以然”的目的。。。&&
就写到这了,累死了。。&
67 顶15 踩
浏览 117462
jdk动态代理之所以只能代理接口是因为代理类本身已经extends了Proxy,而java是不允许多重继承的,但是允许实现多个接口,因此才有cglib的需要吧楼上一语道破天机,终于知道为什么说“jdk动态代理局限于接口是因为java只支持单继承”,还真只有看了原理才知道啊!
多谢楼主分享jdk的代理是利用反射生成字节码,并生成对象,cglib是直接修改目标类的字节码生成对象,这两个性能为什么是jdk的代理好一点呢?难不成是修改字节码比反射慢?没有说JDK动态代理的性能好点啊
& 上一页 1
浏览: 144972 次
来自: 广州
写的很好啊!踩那些人是什么心态啊?[b][/b]
写的非常好
特意登陆账号上来顶,好文章,把动态代理的底层机制都讲清楚了,赞 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'-12日,第九届中国数据库技术大会(DTCC2018)将如约而至。本届大会以“数领先机o智赢未来”为主题,设定
最新活动&&&&&&&&&&&&&&&&&
领域:Linux操作系统
北京大型外企公司架构师,项目主管。从事软件开发及项目管理11年,在软件的企业应用方面有丰富的经验。曾经服务于多家美国金融保...
领域:linux
CU论坛嵌入式开发版主,2003年开始接触Linux程序设计,多年从事嵌入式Linux开发与移植经验,对glusterfs与ffmpeg有深入研究,有多年glusterfs与ffmpeg开发经验,...
现任华为PaaS平台架构师,8年Java NIO通信框架、平台中间件架构设计和开发经验,主导设计和开发的华为分布式服务框架已经在全球数十个国家成功商用。...
魅族系统架构师。2011年加入魅族,主要从事服务端后台开发工作,专注于系统高并发,分布式等解决方案。
一周热点关注
| 社区精选
热帖排行榜
博文排行榜
| 程序开发
数据库技术拒绝访问 | www.eeff.net | 百度云加速
请打开cookies.
此网站 (www.eeff.net) 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(3fdf8c8737fb43dd-ua98).
重新安装浏览器,或使用别的浏览器金额总计:
去购物车并结算
您好,欢迎来到新东方
H杭州呼和浩特邯郸
S沈阳石家庄苏州十堰
返回当前城市
Hi,欢迎来到新东方
请输入班号,最多支持10个班号联报,班号间用“,”隔开。
报名倒计时
课程简介:
每天进行TOFEL经典篇章提升听说能力。
适应学员:
全面提升英语能力的学生。
课程简介:
每天进行TOFEL经典篇章提升听说能力。
适应学员:
全面提升英语能力的学生。
课程简介:
每天进行TOFEL经典篇章提升听说能力。
适应学员:
全面提升英语能力的学生。
课程简介:
每天进行TOFEL经典篇章提升听说能力。
适应学员:
全面提升英语能力的学生。
课程简介:
每天进行TOFEL经典篇章提升听说能力。
适应学员:
全面提升英语能力的学生。
课程简介:
每天进行TOFEL经典篇章提升听说能力。
适应学员:
全面提升英语能力的学生。
新东方网留学频道倾力打造2018留学考试备考规划系列,涵盖托福雅思GRE等10项考试50余位一线名师激昂指导,为同学们的备考提供建议...
为帮助大家顺利申请,新东方网独家整理了最新澳大利亚研究生申请雅思成绩最低要求,和去年相比,澳洲各校语言成绩要求有一定变动...
同学们总是由于词汇量小、语法基础薄弱、论点找不准而徘徊在一个分数段停滞不前,该怎么办…
语言成绩是国际学生申请的第一道门槛。托福如何才能突破100,且看新东方独家秘笈…
2018小升初备考从何时开始呢?五升六的同学及家长们也许早已开始做好筹划小升初,但是一直没有明确的时 间规划。新东方网带领大家一起进入2018小升初时代,共同经历择校、备考的过程...
广州市教育局公布了学年的义务教学学校校历。根据最新的校历安排表,有以下关键时间节点。建议小升初家长根据关键时间节点,安排好时间,为孩子的择校事项做好准备...
为大家提供了最新的小学生必读书籍推荐及读后感等,更加全面的指导小学生学习和生活。
为大家提供有关描写四季的好句好短美文,供各位参考,希望对大家的写作有所帮助!
高考专题:
高考路上,优能与你一起努力。
如何克服“开学综合症”,成为很多家长和孩子担心的问题。
新东方四六级真题解析 ——12月16日锁定新东方网四六级频道,最强名师阵容带你看懂四六级考试!12月16日四六级考试结束当天,新东方四六级老师分题型直播...
2018考研国家线3月16日公布,新东方网考研频道为您提供国家复试分数线内容,其中包含专业硕士2017考研国家分数线、学术硕士国家复试分数线等...
把握命题规律,帮助学员快速提高应试能力,为冲刺阶段的学习打好基础。
通过强化班的学习,强化各项知识,提高阅读、翻译等各种题型解题技巧。
最近《中国有嘻哈》爆红,打败一众选秀节目,稳居人气、话题第一,还刮起了一阵hip-pop风。但相信看节目的很多人都和小编一样,之前对hip-pop是完全不懂的,就是看个热闹,在《中国有嘻哈》这个舞台上经常听到的rap, diss,love & peace等词儿都是什么意思?...
表达“tipping point”指的是“事情即将发生重大变化的转折点”,意思是“某种状况或局面从量变到质变时一触即发的临界点”,一旦越过这一时间点,将无法挽回。比如,科学家们会使用这个概念来谈论气象学、社会学和经济学相关的现象...
掌握英语核心词汇,阅读词汇和考试高频词汇;巩固基础语法。
掌握英语核心词汇,阅读词汇和考试高频词汇;巩固基础语法。
微信公众号
小学资讯 备考辅导
中考快讯 专业辅导
新东方高考更快更专业
四六级精彩一网打尽
考研资讯干货提供平台
托福机经预测先知道
雅思预测解析备考指导
备考资料 应有尽有
最新资讯 名师辅导
这一刻,爱上学习!
让你爱上英文阅读
精品文字 在线互动 专家答疑
让你爱上说口语
一大波新东方牛人教你背单词!
学前儿童家庭教育指南
新东方留学考试互动学习平台APP
新东方集团
权威官方教育机构
专注教育20余年
60余所城市800多家学习中心
累计培训学员超过2000万人次
最好专业教研团队
名师为你保驾护航
关于新东方 发展历程 管理团队 企业文化 旗下品牌 企业微博
新手帮助 注册流程 选课流程 网报流程 校区和报名点查询
常见问题 学员号 一卡通 会员积分制度 积分消费密码
支付方式 网上支付 现场支付 电话支付 汇款支付 手机支付
联系我们 校区电话 意见建议 联系邮箱
企业官网 法律声明 社会责任
经营许可证编号:京ICP备 | 京ICP证060601号| 京网文(0号 | 京公网安备 90号
Neworiental Corporation, All Rights Reserved
绑定学员号
约课后会有专业老师给您回电,请保持电话畅通。
欢迎来到新东方,请选择合适的新东方学校所在地
猜你所在 北京确定
北京住宿班

我要回帖

更多关于 网页笔记软件 的文章

 

随机推荐