目录
动态代理的实现
Java动态代理是动态地创建代理并动态地处理对所代理方法的调用。
实现动态代理需要实现InvocationHandler接口,实现其invoke(object, method, args[])函数,传递的是一个代理实例(通常不管(Proxy类库的$Proxy0),参见),方法,和参数。
动态代理对象是用Proxy.newProxyInstance()方法创建的,参数列表为:
第一个参数是希望代理的接口的类加载器(或者该接口的实现类的类加载器通过getClass().getClassLoader()可以获取);
第二个参数是希望该代理实现的接口列表(Class对象数组);
第三个参数是InvocationHandler接口的一个实现(Proxy.newProxyInstance()返回值可以强制转换成接口,不能强制转换成实现类,因此Java动态代理,只能代理接口,不能代理类【只能代理接口的意思是,创建代理后,只能通过接口的方式来调用代理的实现。】)。
动态代理代理的方法都会经过第三个参数的对象所实现的invoke方法来进行代理调用,因此会向调用处理器传递一个“实际对象”的引用(如下面的readObject对象),从而使得调用处理器可以将请求转发。
dynamic proxy
其中,
代理类实例proxy的类名是:$Proxy0
proxy中的属性有:m1, m0, m3, m4, m2,
proxy中的方法有:equals, toString, hashCode, doSomething, somethingElse,
proxy的父类是:class java.lang.reflect.Proxy
proxy实现的接口是:opensource.Test$Interface,
动态代理的作用:
动态代理主要用来做方法的增强,就像静态代理一样,我们传入一个要代理的对象,然后所有的处理逻辑都写在代理方法里面。但是动态代理是动态的创建代理,使得我们可以在不修改源码的情况下,增强一些方法,比如在方法执行前后加上我们额外编写的一些逻辑处理,甚至还可以不处理任何事情。
在实现动态代理时,我们在InvocationHandler的invoke方法中,我们可以获取到要被代理的那个方法的Method对象,然后我们就可以添加日志处理、事务等等。另外,我们还可以利用动态代理来实现远程调用,例如现有Java接口的实现部署在远程服务器上,然后就可以引入接口,动态创建要调用的远程服务的代理,通过Proxy.newProxyInstance()方法创建该接口对应的InvocationHandler对象代理,然后,我们在InvocationHandler的invoke方法内部封装通讯细节和远程调用等内容,从而使得调用远程服务就像调用本地接口一样简单。其实很多的远程调用框架实现比如RMI、hessian、dubbo、各种webservice框架等等都是使用类似方法实现的。
动态代理示例
我们来看一下动态代理的示例,首先,我们创建一个要被代理的接口:
interface
其次,创建该接口的一个实现:
interface实现
然后,我们实现InvocationHandler接口来创建我们的动态代理:
invocationhandler
这样,我们就完成了动态代理的创建,最后,我们测试一下动态代理:
dynamicproxy
输出:
登录前处理
欢迎 张三 登录系统
登录后处理
Spring AOP动态代理
Spring AOP通过代理模式实现,目前支持两种代理方式:JDK动态代理、CGLIB代理来创建AOP代理,Spring建议优先使用JDK动态代理。当然,在使用Spring的时候,也可以引入AspectJ来实现代理。
JDK动态代理如上面所述:使用Proxy.newProxyInstance()方法来动态的创建被代理类的代理实现,即提取目标对象的接口,然后对接口创建代理,该创建的代理对象的类关系与被代理接口的实现类平级。
CGLIB代理:CGLIB代理不仅能进行接口代理,也能进行类代理,CGLIB代理需要注意以下问题:
不能代理final方法,因为final方法不能被覆盖(CGLIB通过生成子类来创建代理)。
会产生两次构造器调用,第一次是目标类的构造器调用,第二次是CGLIB生成的代理类的构造器调用。如果需要CGLIB代理方法,请确保两次构造器调用不影响应用。
Spring AOP默认首先使用JDK动态代理来代理目标对象,如果目标对象没有实现任何接口将使用CGLIB代理,如果需要强制使用CGLIB代理,请使用如下方式指定:
对于Schema风格配置切面使用如下方式来指定使用CGLIB代理:<aop:config proxy-target-class="true"></aop:config>
而如果使用@AspectJ风格使用如下方式来指定使用CGLIB代理:<aop:aspectj-autoproxy proxy-target-class="true"/>
Spring AOP代理示例
首先,我们创建接口和实现,如:
interface and implement
其次,我们使用AspectJ风格来创建切面、切点等代理,如:
pointcut
然后,我们运行:
使用Spring获取bean,会自动的创建代理
最后,查看结果:
aop 结果
更多文章
Java复习拾遗之sql、util等日期完全详解和高级用法
Spring源码之JdbcTemplate中的坑,你中招了吗
Java中最重要的并发编程抽象工具类
爬虫进阶:CrawlSpider爬取169ee全站美女图片
Python网络爬虫requests、bs4爬取空姐网图片
Java序列化进阶:Java内置序列化的三种方式
Java高并发多线程之读写锁完全解析