• Spring之CGLIB和JDK动态代理底层实现


    目录

    CGLIB

    使用示例-支持创建代理对象,执行代理逻辑

    使用示例-多个方法,走不同的代理逻辑

    JDK动态代理

    使用示例-支持创建代理对象,执行代理逻辑

    ProxyFactory

    如何自动在CGLIB和JDK动态代理转换

    使用示例-使用CGLIB代理方式

    使用示例-使用JDK动态代理方式


    Spring会自动在JDK动态代理和CGLIB之间转换:

    1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP

    2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP

    3、如果目标对象没有实现了接口,必须采用CGLIB库

    本文主要讲解CGLIB和JDK动态代理的使用和底层原理,以及Spring如何自动在JDK动态代理和CGLIB之间转换

    CGLIB

    CGLIB动态代理是利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

    使用示例-支持创建代理对象,执行代理逻辑

    新建一个UserService类,这个类是目标类,后续会被代理

    1. public class UserService {
    2. public void test() {
    3. System.out.println("userService execute test....");
    4. }
    5. }

    使用Enhancer类设置代理类UserService,设置代理逻辑,创建代理对象

    1. public class CylTest {
    2. public static void main(String[] args) {
    3. UserService target = new UserService();
    4. Enhancer enhancer = new Enhancer();
    5. enhancer.setSuperclass(UserService.class);
    6. //设置代理逻辑
    7. enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
    8. @Override
    9. public Object intercept(/*目标对象*/Object o,
    10. /*目标对象方法*/Method method,
    11. /*参数*/Object[] args,
    12. /*代理对象方法*/MethodProxy methodProxy)
    13. throws Throwable {
    14. System.out.println("before");
    15. Object result = method.invoke(target, args);
    16. System.out.println("after");
    17. return result;
    18. }
    19. }});
    20. //创建代理对象=>类型是UserService,但却是代理对象
    21. UserService userService = (UserService) enhancer.create();
    22. userService.test();
    23. }
    24. }

    这个阶段会产生三个对象:

    1.目标对象-targetUserService

    2.负责创建代理对象的工厂对象enhancer

    3.代理对象-proxyUserService

    最终执行效果:

    before

    userService execute test....

    after

    使用示例-多个方法,走不同的代理逻辑

    新建一个UserService类,设置两个方法

    1. public void test() {
    2. System.out.println("userService execute test....");
    3. }
    4. public void a() {
    5. System.out.println("userService execute a....");
    6. }

    在enhancer对象中设置两个代理逻辑,test方法走代理逻辑1,a方法走代理逻辑2

    1. public static void main(String[] args) {
    2. UserService targetUserService = new UserService();
    3. Enhancer enhancer = new Enhancer();
    4. enhancer.setSuperclass(UserService.class);
    5. //代理逻辑:1
    6. MethodInterceptor firstCallback = new MethodInterceptor() {
    7. @Override
    8. public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    9. System.out.println("before");
    10. Object result = method.invoke(targetUserService, args);
    11. System.out.println("after");
    12. return result;
    13. }
    14. };
    15. //代理逻辑:2
    16. NoOp secondCallback = NoOp.INSTANCE;
    17. enhancer.setCallbacks(new Callback[]{firstCallback, secondCallback});
    18. enhancer.setCallbackFilter(new CallbackFilter() {
    19. @Override
    20. public int accept(Method method) {
    21. //方法test执行=》firstCallback代理逻辑:1
    22. if (method.getName().equals("test")) {
    23. return 0;
    24. }
    25. //其他执行=》secondCallback代理逻辑:2
    26. return 1;
    27. }
    28. });
    29. UserService proxyUserService = (UserService) enhancer.create();
    30. System.out.println("执行proxyUserService.test:");
    31. proxyUserService.test();
    32. System.out.println("--------------------------------------------------------");
    33. System.out.println("执行proxyUserService.a:");
    34. proxyUserService.a();
    35. }

    最终执行效果:

    执行proxyUserService.test:

    before

    userService execute test....

    after

    --------------------------------------------------------

    执行proxyUserService.a:

    userService execute a....

    JDK动态代理

    JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

    使用示例-支持创建代理对象,执行代理逻辑

    1. //接口
    2. public interface UserInterface {
    3. void test();
    4. void a();
    5. }
    6. //实现类
    7. public class UserService implements UserInterface {
    8. @Override
    9. public void test() {
    10. System.out.println("userService execute test....");
    11. }
    12. @Override
    13. public void a() {
    14. System.out.println("userService execute a....");
    15. }
    16. }

    使用Proxy.newProxyInstance创建一个代理接口,InvocationHandler制定代理逻辑

    1. public class CylTest {
    2. public static void main(String[] args) {
    3. UserService targetUserService = new UserService();
    4. UserInterface proxyUserInterface = (UserInterface) Proxy.newProxyInstance(
    5. UserInterface.class.getClassLoader(),
    6. new Class[]{UserInterface.class},
    7. new InvocationHandler() {
    8. @Override
    9. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    10. System.out.println("before");
    11. Object result = method.invoke(targetUserService, args);
    12. System.out.println("after");
    13. return result;
    14. }
    15. });
    16. proxyUserInterface.test();
    17. }
    18. }

    最终执行效果:

    before

    userService execute test....

    after

    ProxyFactory

    如何自动在CGLIB和JDK动态代理转换

    ProxyFactory是Spring封装的代理工厂,对目标对象使用CGLIB或者JDK动态代理有处理逻辑。

    代理方式
    CGLIBisProxyTargetClass属性=true
    只实现了SpringProxy接口
    被代理对象没有实现接口
    JDK动态代理被代理类只实现了接口,且实现了非SpringProxy接口

    org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy

    1. @Override
    2. public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    3. // 如果ProxyFactory的isOptimize为true,Spring认为cglib比jdk动态代理要快
    4. // 或者isProxyTargetClass为true,
    5. // 或者被代理对象没有实现接口,
    6. // 或者只实现了SpringProxy这个接口
    7. // 那么则利用Cglib进行动态代理,但如果被代理类是接口,或者被代理类已经是进行过JDK动态代理而生成的代理类了则只能进行JDK动态代理
    8. // 其他情况都会进行JDK动态代理,比如被代理类实现了除SpringProxy接口之外的其他接口
    9. // 是不是在GraalVM虚拟机上运行
    10. if (!NativeDetector.inNativeImage() &&
    11. (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
    12. Class targetClass = config.getTargetClass();
    13. if (targetClass == null) {
    14. throw new AopConfigException("TargetSource cannot determine target class: " +
    15. "Either an interface or a target is required for proxy creation.");
    16. }
    17. if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    18. return new JdkDynamicAopProxy(config);
    19. }
    20. return new ObjenesisCglibAopProxy(config);
    21. }
    22. else {
    23. return new JdkDynamicAopProxy(config);
    24. }
    25. }

    使用示例-使用CGLIB代理方式

    设置目标类 

    1. public class UserService {
    2. public void test() {
    3. System.out.println("test...");
    4. }
    5. }
    1. public static void main(String[] args) {
    2. UserService userService = new UserService();
    3. ProxyFactory proxyFactory = new ProxyFactory();
    4. //
    5. proxyFactory.setTarget(userService);
    6. //代理逻辑1
    7. MethodBeforeAdvice methodBeforeAdvice = new MethodBeforeAdvice() {
    8. @Override
    9. public void before(Method method, Object[] args, Object target) throws Throwable {
    10. System.out.println("begin");
    11. }
    12. };
    13. //代理逻辑2
    14. AfterReturningAdvice afterReturningAdvice = new AfterReturningAdvice() {
    15. @Override
    16. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    17. System.out.println("end");
    18. }
    19. };
    20. //添加多个代理逻辑
    21. proxyFactory.addAdvice(0, methodBeforeAdvice);
    22. proxyFactory.addAdvice(1, afterReturningAdvice);
    23. UserService proxyUserService = (UserService) proxyFactory.getProxy();
    24. proxyUserService.test();
    25. }

    使用示例-使用JDK动态代理方式

    设置目标接口

    1. //UserInterface
    2. public interface UserInterface {
    3. void test();
    4. }
    5. //UserService
    6. public class UserService implements UserInterface {
    7. @Override
    8. public void test() {
    9. System.out.println("test...");
    10. }
    11. }
    1. public static void main(String[] args) {
    2. UserService userService = new UserService();
    3. ProxyFactory proxyFactory = new ProxyFactory();
    4. proxyFactory.setTarget(userService);
    5. proxyFactory.setInterfaces(UserInterface.class);
    6. //代理逻辑1
    7. MethodBeforeAdvice methodBeforeAdvice = new MethodBeforeAdvice() {
    8. @Override
    9. public void before(Method method, Object[] args, Object target) throws Throwable {
    10. System.out.println("begin");
    11. }
    12. };
    13. //代理逻辑2
    14. AfterReturningAdvice afterReturningAdvice = new AfterReturningAdvice() {
    15. @Override
    16. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    17. System.out.println("end");
    18. }
    19. };
    20. //添加多个代理逻辑
    21. proxyFactory.addAdvice(0, methodBeforeAdvice);
    22. proxyFactory.addAdvice(1, afterReturningAdvice);
    23. UserInterface proxyUserService = (UserInterface) proxyFactory.getProxy();
    24. proxyUserService.test();
    25. }

  • 相关阅读:
    (蓝桥杯C/C++)——常用库函数
    堆叠、集群技术
    Redis-事物
    MongoDB - 事务支持
    DDD落地实践-架构师眼中的餐厅 | 京东云技术团队
    JVM_沙箱安全机制与Java安全模型
    ELK集群搭建流程(实践可用)
    为什么我们在写java 代码的时候一定要public static关键字的作用?
    11.从架构设计角度分析AAC源码-Room源码解析第0篇:开篇
    Docker swarm --集群和编排
  • 原文地址:https://blog.csdn.net/changyinling520/article/details/137893727