AspectJ框架的解析及应用
1、AspectJ和SpringAOP的区别
(1)面向对象不同:AspectJ是Java的独立框架,不依赖于任何框架或容器;SpringAOP依赖Spring框架实现,依赖于 Spring 框架进行实施和管理;
(2)实现方式不同:AspectJ支持编译时织入(CTW)和类加载时织入(LTW);SpringAOP通过动态代理在运行时织入;这意味着运行时AspectJ的性能会更好;
(3)支持的切面类型不同:AspectJ支持更多的切面类型,包括字段拦截器切面、构造器调用切面、注解切面。
2、AspectJ的CTW和LTW
2.1、CTW
CTW是 AspectJ 中一种将切面织入目标类的字节码的技术。相比于加载时织入和运行时织入,编译时织入在编译阶段就将切面织入到目标类的字节码中,这样在程序运行时就无需再进行切面的织入操作。
CTW的优势:
- 性能:由于切面是在编译时加入,运行时性能较好,因为没有动态代理和反射的开销。
- 类型安全:编译时织入可以在编译阶段检测到某些类型的错误。
CTW的过程:
- 开发者编写包含切面定义的AspectJ源代码。
- 使用AspectJ编译器(ajc)编译源代码,编译器将切面逻辑织入到目标类的字节码中。
- 生成的字节码包含了原始的业务逻辑和切面逻辑。
具体的使用方法可以在Maven的项目构建中进行配置,默认是LTW。
<build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.11</version> <configuration> <source>1.8</source> <target>1.8</target> <complianceLevel>1.8</complianceLevel> </configuration> <executions> <execution> <goals> <goal>compile</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
2.2、LTW
LTW是一种在类加载时织入切面的方式。与CTW和RTW相比,加载时织入提供了更大的灵活性,并且可以在不修改原始源代码的情况下,将切面逻辑应用到已编译的类中。
LTW 的优势:
- 非侵入性:不需要修改原始源代码,可以在已编译的类中动态地织入切面,因此具有非侵入性。
- 灵活性:可以在运行时动态选择和配置切面,具有更大的灵活性,可以根据需要选择在哪些类上应用切面,以及应用哪些切面逻辑。
- 运行时检测:与 CTW 不同,LTW 可以在运行时动态地选择和配置切面,因此更适合需要在运行时动态适配和调整切面逻辑的情况。
LTW 的过程:
- 配置 LTW 机制:在应用程序的配置中启用 AspectJ 的 LTW 机制。这可以通过 Java 代理机制或者专用的 LTW 框架来实现。
- 运行时织入切面:当类加载器加载类的时候,LTW 框架会拦截类加载事件,并根据配置将切面逻辑织入到目标类的字节码中。通常,LTW 框架会使用字节码增强技术来修改类的字节码,将切面逻辑动态地织入到目标类中。
- 生成的字节码包含了切面逻辑:最终生成的字节码包含了原始的业务逻辑和动态织入的切面逻辑。
参考:https://blog.csdn.net/wenbingoon/article/details/
3、应用代码
AspectJ的使用和SpringAOP并没有很大区别,这里仅做简单展示。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Import({MetricsConfiguration.class}) public @interface EnableMetrics { }
@Target表示注解的应用场景,后面参数表示表示应用在类上;@Retention(RetentionPolicy.RUNTIME)表示该注解运行时保留;@Import({MetricsConfiguration.class})表示import这个类,这个配置类会进行一些初始化操作,也是@EnableXXX这类注解的关键。
@Retention(RetentionPolicy.RUNTIME) @Target({
ElementType.METHOD}) public @interface MetricsLog {
String path() default ""; }
用来标记的切点,AspectJ和SpringAOP的注解写法都是一样的,可以携带一个属性,默认为""。
@Pointcut("@annotation(com.test.MetricsLog)") public void pointcut() {
} @Around("pointcut()") public Object returnDataHandler(ProceedingJoinPoint point) throws Throwable {
long start = System.currentTimeMillis(); Object[] args = point.getArgs(); String className = point.getSignature().getDeclaringType().getSimpleName(); String methodName = point.getSignature().getName(); MetricsLog metricsLog = (MetricsLog)((MethodSignature)point.getSignature()).getMethod().getAnnotation(MetricsLog.class); String path = metricsLog.path(); if (!StringUtils.isBlank(path)) {
path = path.substring(0, 1).equals("/") ? path.replaceFirst("/", "") : path; } else {
path = methodName; } long end; //执行方法 Object proceed = point.proceed(args); end = System.currentTimeMillis(); log.info("{},{}.{} cost time:{}", new Object[]{
path, className, methodName, end - start}); this.metricsClient.simpleReport(path, end - start, 200, true); return proceed; }
切面的代码,@Pointcut来标记切点,@Around标记通知,point.proceed(args);执行方法。
今天的文章 AspectJ框架的解析及应用分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/83320.html