• 简述 AOP 动态代理


    一、AopAutoConfiguration 源码:

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
    public class AopAutoConfiguration {
    
    	@Configuration(proxyBeanMethods = false)
    	@ConditionalOnClass(Advice.class)
    	static class AspectJAutoProxyingConfiguration {
    
    		@Configuration(proxyBeanMethods = false)
    		@EnableAspectJAutoProxy(proxyTargetClass = false)
    		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
    				matchIfMissing = false)
    		static class JdkDynamicAutoProxyConfiguration {
    
    		}
    
    		@Configuration(proxyBeanMethods = false)
    		@EnableAspectJAutoProxy(proxyTargetClass = true)
    		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
    				matchIfMissing = true)
    		static class CglibAutoProxyConfiguration {
    
    		}
    
    	}
    
    	@Configuration(proxyBeanMethods = false)
    	@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
    	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
    			matchIfMissing = true)
    	static class ClassProxyingConfiguration {
    
    		ClassProxyingConfiguration(BeanFactory beanFactory) {
    			if (beanFactory instanceof BeanDefinitionRegistry) {
    				BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
    				AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
    				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
    			}
    		}
    
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    1. CglibAutoProxyConfiguration 类 matchIfMissing = true,所以默认使用 cglib 动态代理
    2. application.properties 里配置如下:spring.aop.auto=false,整个 AOP 都不会生效了
    3. application.properties 里配置如下:spring.aop.proxy-target-class=false,使用 jdk 动态代理

    JDK 动态代理的限制在于,它只能代理实现了接口的类,如果一个类没有实现任何接口,JDK 动态代理就无法代理它,这是因为 JDK 动态代理是基于接口的代理,它生成的代理对象会实现指定接口,然后通过该接口来调用被代理类的方法。

    需要注意的是,如果接口有多个实现类,并且你使用 @Autowired 注解注入时, Spring 会抛出异常,因为它无法确定应该注入哪个实现类的代理对象,在这种情况下,你需要明确指定要注入的实现类,可以使用 @Qualifier 注解或者在实现类上使用 @Primary 注解来解决这个问题

    二、不使用 springboot,手动写 JDK 动态代理案例

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public interface MyInterface {
        void myMethod();
    }
    
    public class MyInterfaceImpl implements MyInterface {
        public void myMethod() {
            System.out.println("Real object's method is called.");
        }
    }
    
    public class MyInvocationHandler implements InvocationHandler {
        private MyInterface target;
    
        public MyInvocationHandler(MyInterface target) {
            this.target = target;
        }
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Proxy object's method is called before real object's method.");
            Object result = method.invoke(target, args);
            System.out.println("Proxy object's method is called after real object's method.");
            return result;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            MyInterface realObject = new MyInterfaceImpl();
            MyInvocationHandler handler = new MyInvocationHandler(realObject);
    
            MyInterface proxyObject = (MyInterface) Proxy.newProxyInstance(
                    MyInterface.class.getClassLoader(),
                    new Class[]{MyInterface.class},
                    handler
            );
    
            proxyObject.myMethod();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在JDK动态代理中,代理对象实现了指定接口,并且在运行时动态生成代理实例。被代理的类必须实现至少一个接口,而代理对象会实现这个接口,并且在方法调用时会委托给InvocationHandler中的逻辑

    在这个例子中,proxyObject是MyInterface接口的代理对象。代理对象实现了MyInterface接口,并且在invoke方法中执行了额外的逻辑。当proxyObject.myMethod()被调用时,代理对象会先执行invoke方法中的逻辑,然后再调用MyInterfaceImpl实现类的myMethod方法

    三、不使用 springboot,手动写 CGLIB 动态代理案例

    CGLIB(Code Generation Library)是一个功能强大的字节码生成库,它可以在运行时动态生成类的子类,常用于代理那些没有实现接口的类。以下是一个简单的CGLIB动态代理的使用案例:

    1. pom 文件
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.3.0</version>
    </dependency>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 然后,考虑以下的被代理类 UserService:
    public class UserService {
        public void saveUser() {
            System.out.println("Saving user...");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 现在,我们会使用CGLIB为它生成一个代理对象,并在方法调用前后添加额外的逻辑:
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class UserServiceProxy implements MethodInterceptor {
    
        public Object createProxy(Object target) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(target.getClass());
            enhancer.setCallback(this);
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("Before method execution");
            Object result = methodProxy.invokeSuper(proxy, args);
            System.out.println("After method execution");
            return result;
        }
    
        public static void main(String[] args) {
            UserServiceProxy userServiceProxy = new UserServiceProxy();
            UserService userServiceProxyInstance = (UserService) userServiceProxy.createProxy(new UserService());
            userServiceProxyInstance.saveUser();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    1. 在上述代码中,MethodInterceptor 接口用于定义拦截器的逻辑。在 intercept
      方法中,我们在方法调用前后添加了额外的逻辑。Enhancer 类用于生成代理类,它设置了被代理类的父类和拦截器。createProxy
      方法接受一个目标对象,返回一个代理对象。

      运行上述代码会输出以下结果:

    Before method execution
    Saving user...
    After method execution
    
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    9月5日关键点检测学习笔记——人体骨骼点检测:自顶向下
    20220705图床搭建:阿里云OSS+PicGo + typora
    掌动智能性能压力测试优势有哪些
    程序都不知道的代码
    mybatis批量插入
    Java代码审计-SQL注入
    search——Bloom Filter
    【MM32F5270开发板试用】定制MicroPython及读取MPU6050数据到OLED1306
    [深度学习]基于yolov10+streamlit目标检测演示系统设计
    利用python批量读取大量Excel表格文件中指定内容并汇总
  • 原文地址:https://blog.csdn.net/qq_34486648/article/details/133607243