Spring两种动态代理原理分析+AOP的坑

Posted 结构化思维wz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring两种动态代理原理分析+AOP的坑相关的知识,希望对你有一定的参考价值。

AOP原理分析

AOP(面向切面编程)的本质就是Spring的动态代理开发,通过代理类为原始类增加额外功能。

文章目录

AOP的开发方式

MethodInterceptor

MethodInterceptor方法拦截器接口---->实现类–>invoke方法(书写额外功能)

参数:MethodInvocation: 额外功能所增加给的原始方法

//object为原始方法的返回值
public Object invoke(MethodInvocation invocation)throws Throwable
    //前置额外方法(befor)
    ----
    Object ret = invocation.proceed(); //目标(原始)方法运行
    ----
    //后置额外方法
    return ret;

@Aspect

@Order(0) //优先级
@Aspect //切面类
@Component
public class DataBaseAop 
    @Around("@annotation(database)") //切入点
    public Object setWrite(ProceedingJoinPoint joinPoint, Database database) throws Throwable 
            DbContextHolder.setDbType(database.databaseName());
            return joinPoint.proceed(); //原始方法运行
    

AOP如何创建动态代理类动态字节码技术

JDK动态代理

代码实例:

    public void TestProxy()
        //1.创建原始方法
        ApiOaService apiOaService = new ApiOaServiceImpl();
        //2.JDK创建动态代理
        InvocationHandler handler = new InvocationHandler() 
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
                System.out.println("--------log-----------");
                //1.原始方法运行
                Object ret = method.invoke(apiOaService, args);
                //2.添加额外功能
                System.out.println("----------log----------");
                return ret;
            
        ;
        ApiOaService proxyApiOAService = (ApiOaService) Proxy.newProxyInstance(apiOaService.getClass().getClassLoader(), apiOaService.getClass().getInterfaces(), handler);
        //调用被代理的方法
        proxyApiOAService.applyOA();

    

图解分析:

代理类和原始类实现相同接口的原因:

CGLIB动态代理

如果目标类(原始类)没有实现接口,这时候JDK的方法就无法创建动态代理。CGLIB会已继承的方式创建动态代理。

CGLIB创建动态代理的原理:父子继承关系创建代理对象,原始类作为父类,代理类作为子类,这样既可以保证2者方法一致,同时在代理中提供新的实现。

代码实例:

    public void CglibTestProxy()
        //1.原始对象
        WechatServiceImpl wechatService = new WechatServiceImpl();
        //2.通过cglib创建代理对象
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(wechatService.getClass().getClassLoader());
        enhancer.setSuperclass(wechatService.getClass());
        enhancer.setCallback(new MethodInterceptor() 
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable 
                System.out.println("-----------log------------");
                Object ret = method.invoke(wechatService, args); //原始方法运行
                System.out.println("-----------log------------");
                return ret;
            
        );
        WechatServiceImpl proxy = (WechatServiceImpl) enhancer.create();
        proxy.getAccessToken();
    

总结

- 1.JDK实现动态代理    Proxy.newProxyInstance(); //通过接口创建动态代理
- 2.CGLIB实现动态代理  Enhancer      //通过父子继承的方式创建动态代理

底层默认是JDK的方式,如果需要切换CGlib

@EnableAspectJAutoProxy(proxyTargetClass = true)

Spring工厂如何加工创建代理对象

BeanPostProcessor

AOP的坑

同一个service中,不同方法之间会有调用的情况。

举个栗子:

  1. 首先创建一个切面类

    /**
     * @ClassName: TestAop
     * @Description:
     * @author: wangz48
     * @date: 2022-1-12 14:50
     */
    @Aspect
    @Component
    public class TestAop 
        @Around("@annotation(Log)")
        public Object setLog(ProceedingJoinPoint joinPoint) throws Throwable 
            System.out.println("======log=======");
            Object ret = joinPoint.proceed();
            System.out.println("=======log======");
            return ret;
        
    
    
    @Target(ElementType.METHOD, ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface Log 
    
    
    
    
  2. 正常情况:

  3. 不同方法间调用的情况:

    可以发现,a并没有调用b的代理方法,而是调用了原始方法。

如何才能获取到代理对象呢??

这里提供两种解决方案:

  • 启用类加入 @EnableAspectJAutoProxy(exposeProxy = true)

  • 从ApplicationContext获取当前Service对象

    - 1.实现 ApplicationContextAware接口
    - 2. 重写setApplicationConetext方法获取工厂
    - 3. 用工厂的getBean()方法创建对象,创建的对象几位代理对象。
    

以上是关于Spring两种动态代理原理分析+AOP的坑的主要内容,如果未能解决你的问题,请参考以下文章

分析动态代理给 Spring 事务埋下的坑

Spring5学习笔记 — “Spring AOP底层原理(动态代理)”

Spring5学习笔记 — “Spring AOP底层原理(动态代理)”

[Spring5]AOP底层原理

动态代理3--Spring AOP分析

Spring的AOP