作者:dolphin叔叔
链接:https://www.jianshu.com/p/fe8...
AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于解决一些具备横切性质的零碎级服务,如事务管理、安全检查、缓存、对象池治理等。
AOP 实现的要害就在于 AOP 框架主动创立的 AOP 代理,AOP 代理则可分为动态代理和动静代理两大类,其中动态代理是指应用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因而也称为编译时加强;而动静代理则在运行时借助于 JDK 动静代理、CGLIB 等在内存中“长期”生成 AOP 动静代理类,因而也被称为运行时加强。
先说说AspectJ
在明天之前,我还认为AspectJ 是Spring的一部分,因为咱们谈到Spring AOP个别都会提到AspectJ。原来AspectJ是一套独立的面向切面编程的解决方案。
上面咱们抛开Spring,单纯的看看AspectJ。
1、AspectJ 装置
下载AspectJ jar包,而后双击装置。装置好的目录构造为:
bin:寄存了 aj、aj5、ajc、ajdoc、ajbrowser 等命令,其中 ajc 命令最罕用,它的作用相似于 javac
doc:寄存了 AspectJ 的应用阐明、参考手册、API 文档等文档
lib:该门路下的 4 个 JAR 文件是 AspectJ 的外围类库
2、AspectJ HelloWorld 实现
业务组件 SayHelloService:
package com.ywsc.fenfenzhong.aspectj.learn;public class SayHelloService { public void say(){ System.out.print("Hello AspectJ"); }}
须要来了,在须要在调用say()办法之后,须要记录日志。那就是通过AspectJ的后置加强吧。
LogAspect 日志记录组件,实现对com.ywsc.fenfenzhong.aspectj.learn.SayHelloService 后置加强:
package com.ywsc.fenfenzhong.aspectj.learn;public aspect LogAspect{ pointcut logPointcut():execution(void SayHelloService.say()); after():logPointcut(){ System.out.println("记录日志 ..."); }}
3、编译SayHelloService
- 执行命令 ajc -d . SayHelloService.java LogAspect.java
- 生成 SayHelloService.class
- 执行命令 java SayHelloService
- 输入 Hello AspectJ 记录日志
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 框架须要每次运行时都进行动静加强。
再谈 Spring AOP
Spring AOP也是对指标类加强,生成代理类。然而与AspectJ的最大区别在于---Spring AOP的运行时加强,而AspectJ是编译时加强。
已经认为AspectJ是Spring AOP一部分,是因为Spring AOP应用了AspectJ的Annotation。应用了Aspect来定义切面,应用Pointcut来定义切入点,应用Advice来定义加强解决。尽管应用了Aspect的Annotation,然而并没有应用它的编译器和织入器。其实现原理是JDK 动静代理,在运行时生成代理类。
为了启用 Spring 对 @AspectJ 方面配置的反对,并保障 Spring 容器中的指标 Bean 被一个或多个方面主动加强,必须在 Spring 配置文件中增加如下配置
<aop:aspectj-autoproxy/>
当启动了 @AspectJ 反对后,在 Spring 容器中配置一个带 @Aspect 正文的 Bean,Spring 将会自动识别该 Bean,并将该 Bean 作为方面 Bean 解决。方面Bean与一般 Bean 没有任何区别,一样应用 <bean.../> 元素进行配置,一样反对应用依赖注入来配置属性值。
应用Spring AOP的改写 Hello World的例子。
业务组件 SayHelloService:
package com.ywsc.fenfenzhong.aspectj.learn;import org.springframework.stereotype.Component;@Componentpublic class SayHelloService { public void say(){ System.out.print("Hello AspectJ"); }}
做后置加强的日志解决。
package com.ywsc.fenfenzhong.aspectj.learn;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.springframework.stereotype.Component;@Aspect@Componentpublic class LogAspect { @After("execution(* com.ywsc.fenfenzhong.aspectj.learn.SayHelloService.*(..))") public void log(){ System.out.println("记录日志 ..."); }}
package com.ywsc.fenfenzhong.mongodb;import com.ywsc.fenfenzhong.aspectj.learn.SayHelloService;public class TestCase { public static void main(String[] args) { SayHelloService sayHelloService = ApplicationUtil.getContext().getBean(SayHelloService.class); sayHelloService.say(); }}
输入后果:
Hello AspectJ记录日志...
总结
AOP 代理 = 原来的业务类+加强解决。
这个生成AOP 代理由 Spring 的 IoC 容器负责生成。也由 IoC 容器负责管理。因而,AOP 代理能够间接应用容器中的其余 Bean 实例作为指标,这种关系可由 IoC 容器的依赖注入提供。回顾Hello World的例子,其中程序员参
与的只有 3 个局部:
- 定义一般业务组件。
- 定义切入点,一个切入点可能横切多个业务组件。
- 定义加强解决,加强解决就是在 AOP 框架为一般业务组件织入的解决动作。
最初说说CGLIB
CGLIB(Code Generation Library)它是一个代码生成类库。它能够在运行时候动静是生成某个类的子类。代理模式为要拜访的指标对象提供了一种路径,当拜访对象时,它引入了一个间接的层。
JDK自从1.3版本开始,就引入了动静代理,并且常常被用来动静地创立代理。JDK的动静代理用起来非常简单,惟一限度便是应用动静代理的对象必须实现一个或多个接口。而CGLIB缺不用有此限度。要想Spring AOP 通过CGLIB生成代理,只须要在Spring 的配置文件引入
<aop:aspectj-autoproxy proxy-target-class="true"/>
CGLIB包的底层是通过应用一个小而快的字节码解决框架ASM(Java字节码操控框架),来转换字节码并生成新的类。因为没有理解过class 文件和字节码,因此也就写不上来了。
兴许学习下来最大的播种便是弄清楚了 AspectJ 和 Spring AOP 在实现上简直无关。
近期热文举荐:
1.1,000+ 道 Java面试题及答案整顿(2021最新版)
2.别在再满屏的 if/ else 了,试试策略模式,真香!!
3.卧槽!Java 中的 xx ≠ null 是什么新语法?
4.Spring Boot 2.5 重磅公布,光明模式太炸了!
5.《Java开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!