栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

AOP原理分析

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

文章目录

AOP原理分析

AOP的开发方式JDK动态代理CGLIB动态代理AOP的坑

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中,不同方法之间会有调用的情况。

举个栗子:

    首先创建一个切面类

    @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 {
    
    }
    
    

    正常情况:

    不同方法间调用的情况:

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

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

这里提供两种解决方案:

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

从ApplicationContext获取当前Service对象

- 1.实现 ApplicationContextAware接口
- 2. 重写setApplicationConetext方法获取工厂
- 3. 用工厂的getBean()方法创建对象,创建的对象几位代理对象。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/703386.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号