当前位置: 首页 > 后端技术 > Java

SpringAOP、AspectJ、CGLIB是什么鬼?它们有什么关系?

时间:2023-04-01 15:07:02 Java

作者:海豚大叔链接:https://www.jianshu.com/p/fe8...AOP(AspectOrientProgramming)作为面向对象编程的补充,被广泛用于处理一些交叉切属性系统级服务,如事务管理、安全检查、缓存、对象池管理等。AOP实现的关键在于AOP框架自动创建的AOP代理。AOP代理可以分为两大类:静态代理和动态代理。静态代理是指用AOP框架提供的命令进行编译,这样就可以在编译阶段生成。AOP代理类,所以又叫编译时增强;而动态代理则是在运行时借助JDK动态代理、CGLIB等在内存中“临时”生成AOP动态代理类,因此也称为运行时增强。先说AspectJ。在今天之前,我认为AspectJ是Spring的一部分,因为我们一般在讲SpringAOP的时候都会提到AspectJ。事实证明,AspectJ是面向方面编程的独立解决方案。我们先抛开Spring,简单看一下AspectJ。1.AspectJ安装下载AspectJjar包,然后双击安装。安装的目录结构为:bin:存放aj、aj5、ajc、ajdoc、ajbrowser等命令,其中ajc命令最常用,其作用类似于javacdoc:存放AspectJ说明、参考手册、API文档等文件lib:该路径下的4个JAR文件是AspectJ2的核心类库,AspectJHelloWorld实现业务组件SayHelloService:packagecom.ywsc.fenfenzhong.aspectj.learn;publicclassSayHelloService{publicvoidsay(){系统输出。print("你好AspectJ");}}需要来,调用say()方法后,需要记录日志。那就是通过AspectJ的后期增强。LogAspect日志组件,实现com.ywsc.fenfenzhong.aspectj.learn.SayHelloService的后期增强:packagecom.ywsc.fenfenzhong.aspectj.learn;公共方面LogAspect{切入点logPointcut():execution(voidSayHelloService.say());after():logPointcut(){System.out.println("Logging...");}}3.编译SayHelloService,执行命令ajc-d。SayHelloService.javaLogAspect.java生成SayHelloService.class并执行命令javaSayHelloService输出HelloAspectJ日志记录。ajc.exe可以理解为javac.exe命令,用于编译Java程序。区别在于ajc.exe命令可以识别AspectJ语法;我们可以把ajc.exe看作是javac.exe命令的增强版。执行完ajc命令后的SayHelloService.class文件并不是由原来的SayHelloService.java文件编译而来的。打印日志的内容被添加到SayHelloService.class——这表明AspectJ“自动”编译了一个新类,增强了原SayHelloService.java类的功能,所以AspectJ常被称为编译时增强AOP框架。相对于AspectJ,还有另外一种AOP框架,它不需要在编译时增强目标类,而是在运行时生成目标类的代理类。代理类要么实现与目标类相同的接口,要么就是目标类。类的子类——简而言之,代理类的实例可以用作目标类的实例。一般来说,在编译时增强的AOP框架具有性能优势——因为在运行时动态增强的AOP框架在每次运行时都需要动态增强。再说说SpringAOPSpringAOP也增强了目标类,生成了代理类。但是与AspectJ最大的区别是---SpringAOP的运行时增强,而AspectJ是编译时增强。之前一直认为AspectJ是SpringAOP的一部分,因为SpringAOP使用了AspectJ的Annotation。Aspect用于定义切面,Pointcut用于定义入口点,Advice用于定义增强处理。虽然用到了Aspect的Annotation,但是并没有用到它的compiler和weaver。它的实现原理是JDK动态代理,在运行时生成代理类。为了开启Spring对@AspectJ切面配置的支持,保证Spring容器中的目标bean自动增强一个或多个切面,需要在Spring配置文件中添加如下配置@AspectJ启动支持后,在Spring容器中配置一个带有@Aspect注解的bean,Spring会自动识别该bean,并将该bean视为切面bean。方面bean和普通bean之间没有区别。它还使用元素进行配置,并且还支持依赖注入来配置属性值。使用SpringAOP重写HelloWorld示例。业务组件SayHelloService:packagecom.ywsc.fenfenzhong.aspectj.learn;importorg.springframework.stereotype.Component;@ComponentpublicclassSayHelloService{publicvoidsay(){System.out.print("HelloAspectJ");}}做后期增强日志处理。packagecom.ywsc.fenfenzhong.aspectj.learn;importorg.aspectj.lang.annotation.After;importorg.aspectj.lang.annotation.Aspect;importorg.springframework.stereotype.Component;@Aspect@Componentpublic类LogAspect{@After("execution(*com.ywsc.fenfenzhong.aspectj.learn.SayHelloService.*(..))")publicvoidlog(){System.out.println("记录日志...");}}packagecom.ywsc.fenfenzhong.mongodb;importcom.ywsc.fenfenzhong.aspectj.learn.SayHelloService;publicclassTestCase{publicstaticvoidmain(String[]args){SayHelloServicesayHelloService=ApplicationUtil.getContext().getBean(SayHelloService.class);sayHelloService.say();}}输出结果:HelloAspectJrecordslogs...总结AOP代理=原始业务类+增强处理。这一代AOP代理是由Spring的IoC容器来完成的。也由IoC容器管理。因此,AOP代理可以直接以容器中的其他bean实例为目标,这是IoC容器的依赖注入提供的一种关系。回顾HelloWorld的例子,程序员参与的只有3个部分:定义公共业务组件。定义切入点,一个切入点可以横切多个业务组件。定义增强处理,增强处理是在AOP框架中编织到普通业务组件中的处理动作。最后说一下CGLIBCGLIB(CodeGenerationLibrary),它是一个代码生成库。它可以在运行时动态生成一个类的子类。代理模式提供了一种访问目标对象的方式,它在访问对象时引入了一层间接。JDK从1.3版本开始就引入了动态代理,经常被用来动态创建代理。JDK的动态代理使用起来非常简单,唯一的限制是使用动态代理的对象必须实现一个或多个接口。CGLIB不必有此限制。如果想让SpringAOP通过CGLIB生成代理,只需要在Spring配置文件中引入即可。CGLIB包底层使用小而快的字节码框架ASM(Javabytecodemanipulationframework)进行处理,转换字节码并生成新的类。由于没学过class文件和字节码,所以写不下去了。或许学习最大的收获就是明白了AspectJ和SpringAOP在实现上几乎没有任何关系。近期热点文章推荐:1.1,000+Java面试题及答案(2021最新版)2.别在满屏的if/else中,试试策略模式,真的很好吃!!3.操!Java中xx≠null的新语法是什么?4、SpringBoot2.5发布,深色模式太炸了!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!