基于Spring AOP和CGLIB代理实现引介增强(Introduction Advice)示例

一、Spring AOP相关概念

1. Spring AOP与AspectJ区别

Spring AOP提供跨Spring IOC的简单AOP实现,以解决程序员面临的最常见问题。它并不打算作为一个完整的AOP解决方案——它只能应用于由Spring容器管理的bean。

AspectJ是最初的AOP技术,提供完整的AOP解决方案。它比Spring AOP更健壮,但也明显更复杂。值得注意的是,AspectJ可以跨所有域对象应用。

Spring AOPAspectJ
用纯Java实现使用Java程序设计语言的扩展实现
不需要单独的编译过程需要AspectJ编译器(ajc),除非设置了LTW
只有运行时编织可用运行时编织不可用。支持编译时、编译后和加载时编织
只支持方法级编织可以编织字段,方法,构造函数,静态初始化器,最终类/方法等
只能在Spring容器管理的bean上实现可以在所有的域对象上实现
只支持方法执行切入点支持全部的切入点
为目标对象创建代理,并在这些代理上应用切面切面在应用程序执行之前(在运行之前)直接编织到代码中
比AspectJ慢得多更好的性能
易于学习和应用相对来说比Spring AOP更复杂
2. Spring AOP的过程

在运行时编织中,切面在应用程序执行期间使用目标对象的代理进行编织。

JDK动态代理:Spring AOP的首选方式。只要目标对象实现了一个接口,就会使用JDK动态代理。
CGLIB代理:如果目标对象没有实现接口,那么可以使用CGLIB代理。

请添加图片描述

3. 引介增强(Introduction Advice)概念

一个Java类,没有实现某个接口,在不修改Java类的情况下,使其具备该接口的功能。

二、实现引介增强(Introduction Advice)示例

1. 一个Java类Person,一个接口EnglishLanguageFun
public class Person {
    public void useChaineseLanguage(){
        System.out.println("useChaineseLanguage:你好!");
    }
}
public interface EnglishLanguageFun {
    public void useEnglishLanguage();
}
2. 实现IntroductionInterceptor

IntroductionInterceptor是AOP Alliance MethodInterceptor 的子接口,允许拦截器实现其他接口,并通过使用该拦截器的代理提供。这是一个基本的 AOP 概念,称为介绍。引入通常是混合的,支持构建复合对象,这些对象可以实现 Java 中多重继承的许多目标。

自定义一个PersonLanguageIntroductionInterceptor 实现IntroductionInterceptor。同时实现目标接口EnglishLanguageFun

public class PersonLanguageIntroductionInterceptor implements IntroductionInterceptor, EnglishLanguageFun {
    @Override
    public void useEnglishLanguage() {
      // 覆写接口方法
        System.out.println("useEnglishLanguage:hello!");
    }

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        if (implementsInterface(methodInvocation.getMethod().getDeclaringClass())) {
            // 判断类型是EnglishLanguageFun.class时,调用useEnglishLanguage方法
          return methodInvocation.getMethod().invoke(this, methodInvocation.getArguments());
        }
        return methodInvocation.proceed();
    }

    @Override
    public boolean implementsInterface(Class<?> aClass) {
        return aClass.isAssignableFrom(EnglishLanguageFun.class);
    }
}

3. 基于CGLIB进行引介增强
		@Test
    public void aopTest(){
      // 默认AopProxyFactory实现
        DefaultAopProxyFactory defaultAopProxyFactory = new DefaultAopProxyFactory();
        AdvisedSupport advisedSupport = new AdvisedSupport();

        advisedSupport.setTargetClass(Person.class);
        advisedSupport.setTarget(new Person());
        // true的目的:为给定类创建一个 CGLIB 代理
        advisedSupport.setProxyTargetClass(true);

        DefaultIntroductionAdvisor introductionAdvisor = new DefaultIntroductionAdvisor(new PersonLanguageIntroductionInterceptor(), EnglishLanguageFun.class);
        advisedSupport.addAdvisor(introductionAdvisor);

        AopProxy aopProxy = defaultAopProxyFactory.createAopProxy(advisedSupport);
        Person person = (Person) aopProxy.getProxy();
        person.useChaineseLanguage();
        // 一个Person类,没有实现EnglishLanguageFun接口,在不修改Java类的情况下,使其具备了EnglishLanguageFun接口的功能。
        EnglishLanguageFun aopLanguageFun = (EnglishLanguageFun) aopProxy.getProxy();
        aopLanguageFun.useEnglishLanguage();
    }

单侧执行结果:

useChaineseLanguage:你好!
useEnglishLanguage:hello!

Process finished with exit code 0

其中,setProxyTargetClass需要设置为true,才是CGLIB代理。

advisedSupport.setProxyTargetClass(true);

setProxyTargetClass用来设置是否直接代理目标类,而不仅仅是代理特定接口。

默认值为“false”。将此设置为“true”以强制对 TargetSource 的公开目标类进行代理。

如果该目标类是接口,则将为给定接口创建一个 JDK 代理。如果该目标类是任何其他类,则将为给定类创建一个 CGLIB 代理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值