动态代理是为了实现Aop编程(不修改类源码,类方法执行前后,自定义增强处理, 日志 拦截等等),代理的是类对象
一、jdk动态代理
被代理的类需要实现接口,针对接口的代理,通过生成一个实现了接口的动态类实现代理
- ServiceImpl是被代理类,实现接口ServiceInterface
- JDKProxy是代理处理方法类,实现接口InvocationHandler
- 通过JDKProxy.bind()得到jdk【动态生成】代理类ServiceProxy (ServiceInterface),当你调用ServiceProxy.doService()会执行JDKProxy的invoke()方法,实现代理
public interface ServiceInterface {public void doService();
}
public class ServiceImpl implements ServiceInterface {public void doService() {System.out
.println("ServiceImpl");}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class JDKProxy implements InvocationHandler {private Object target
= null;public Object bind(Object target
) {this.target
= target
;return Proxy.newProxyInstance(target
.getClass().getClassLoader(),target
.getClass().getInterfaces(),this);}public Object invoke(Object proxy
, Method method
, Object[] args
) throws Throwable {System.out
.println("before method:"+method
.getName());Object res
= method
.invoke(target
,args
);System.out
.println("after method");return res
;}public static void main(String[] args
) {ServiceInterface service
= (ServiceInterface) new JDKProxy().bind(new ServiceImpl());service
.doService();}}
二、cglib动态代理
通过生成被代理类的【子类】实现代理,所以 Cglib是无法代理final修饰的方法或类
- ServiceImpl是被代理类
- ServiceProxy是代理处理类,实现接口MethodInterceptor
- 通过ServiceProxy.getProxy()动态生成被代理类子类ServiceImpl_SubClass (ServiceImpl)当你调ServiceImpl_SubClass.doService()会执行ServiceProxy.Intercept()方法,实现代理
public interface ServiceInterface {public void doService();
}
public class ServiceImpl implements ServiceInterface{public void doService() {System.out
.println("ServiceImpl");}
}
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class ServiceProxy implements MethodInterceptor {private Enhancer enhancer
= new Enhancer();public Object getProxy(Class clazz
) {enhancer
.setSuperclass(clazz
);enhancer
.setCallback(this);return enhancer
.create();}public Object intercept(Object o
, Method method
, Object[] objects
, MethodProxy methodProxy
) throws Throwable {System.out
.println("before method:" + method
.getName());Object res
= methodProxy
.invokeSuper(o
, objects
);System.out
.println("after method");return res
;}public static void main(String[] args
) {ServiceInterface service
= (ServiceImpl) new ServiceProxy().getProxy(ServiceImpl.class);service
.doService();}
}
//pom.xml
<dependency><groupId>cglib
</groupId><artifactId>cglib
</artifactId><version>2.2.2
</version></dependency>
上面的jdk与cglib动态代理例子,没有改变ServiceInterface接口与ServiceImpl实现类代码,通过一个代理处理类实现动态对ServiceImpl的代理,方法执行前后增强处理,打印日志,也可以通过try catch捕获方法中的异常实现事务控制等等
三、两者的切换
JDK动态代理 Proxy.newProxyInstance() 通过接口创建代理的实现类Cglib动态代理 Enhancer 通过继承父类创建的代理类 (没有实现接口的话spring底层就切换成CGLib的方式)
四、Spring动态代理用JDK还是用CGLIB
动态代理又有两种实现方式:
- 一种方法是直接实现JDK中的InvocationHandler接口
- 另一种方法是继承CGLIB。
那么问题来了,这两种方法有啥区别呢,分别适用于什么情况呢?
首先如果不是很清楚两者的区别的话,记住一般情况下InvocationHandler要比CGLIB要好就行了。
如果目标对象的代理至少实现了一个接口,那么就用JDK动态代理,所有由目标对象实现的接口将全部都被代理。如果目标对象没有实现任何接口,那么就用CGLIB代理。
但是如果非要使用CGLIB的话,那么CGLIB可能有下面的问题:
刚才提到了,InvocationHandler是实现的接口,而CGLIB则是继承的父类,那么由于继承的限制,如果父类中有final的成员,那么是继承不到的。
还有从Spring 3.2以后不再将CGLIB放在项目的classpath下,而是将CGLIB类打包放在spring-core下面的org.springframework中。这个就意味着基于CGLIB的动态代理与JDK的动态代理在支持“just works”就一样了。
在Spring 4.0中,因为CGLIB代理实例是通过Objenesis创建的,所以代理对象的构造器不再有两次调用。
想要强制使用CGLIB,那么就设置aop:config下面的proxy-target-class属性为true:
<aop
:config proxy
-target
-class="true"><!-- other beans defined here
... -->
</aop
:config
>
要是使用@AspectJ强制使用CGLIB的话,可以配置aop:aspectj-autoproxy下的proxy-target-class属性为true:
<aop
:aspectj
-autoproxy proxy
-target
-class="true"/>
注意: Spring AOP 代理默认实现 JDK SpringBOOT AOP 代理默认实现 Cglib
参考文章1
参考文章2
总结
以上是生活随笔为你收集整理的jdk动态代理与cglib动态代理--InvocationHandler--MethodInterceptor的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。