欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

jdk动态代理与cglib动态代理--InvocationHandler--MethodInterceptor

发布时间:2025/3/15 编程问答 34 豆豆
生活随笔 收集整理的这篇文章主要介绍了 jdk动态代理与cglib动态代理--InvocationHandler--MethodInterceptor 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

动态代理是为了实现Aop编程(不修改类源码,类方法执行前后,自定义增强处理, 日志 拦截等等),代理的是类对象

一、jdk动态代理

被代理的类需要实现接口,针对接口的代理,通过生成一个实现了接口的动态类实现代理

  • ServiceImpl是被代理类,实现接口ServiceInterface
  • JDKProxy是代理处理方法类,实现接口InvocationHandler
  • 通过JDKProxy.bind()得到jdk【动态生成】代理类ServiceProxy (ServiceInterface),当你调用ServiceProxy.doService()会执行JDKProxy的invoke()方法,实现代理
//ServiceInterface.java public interface ServiceInterface {public void doService(); }//ServiceImpl.java public class ServiceImpl implements ServiceInterface {public void doService() {System.out.println("ServiceImpl");} }//JDKProxy.java 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()方法,实现代理
//ServiceInterface.java public interface ServiceInterface {public void doService(); }//ServiceImpl.java public class ServiceImpl implements ServiceInterface{public void doService() {System.out.println("ServiceImpl");} }//ServiceProxy.java 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();/**通过cglib方式创建动态代理对象Enhancer.setClassLoader()Enhancer.setSuperClass()Enhancer.setCallback(); ---> MethodInterceptor(cglib)Enhancer.create() ---> 代理*/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的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。