前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring AOP与AspectJ的对比及应用

Spring AOP与AspectJ的对比及应用

作者头像
Jensen_97
发布2023-07-20 14:36:38
4590
发布2023-07-20 14:36:38
举报
文章被收录于专栏:技术客栈

1、简介

AOP,即面向切面编程是很常用的技术,特别是在Java Web开发中。而最流行的AOP框架分别是Spring AOP和AspectJ。

2、Spring AOP vs AspectJ

Spring AOP是基于Spring IoC实现的,它解决大部分常见的需求,但它并不是一个完整的AOP解决方案。对于非Spring容器管理的对象,它更没有办法了。而AspectJ旨在提供完整的AOP方案,因此也会更复杂。

2.1、织入方式

两者织入方式有极大的不同,这也是它们的本质区别,它们实现代理的方式不同。

AspectJ是在运行前织入的,分为三类:

  • 编译时织入
  • 编译后织入
  • 加载时织入

因此需要AspectJ编译器(ajc)的支持。

而Spring AOP是运行时织入的,主要使用了两种技术:JDK动态代理和CGLIB代理。对于接口使用JDK Proxy,而继承的使用CGLIB。

2.2、Joinpoints

因为织入方式的区别,两者所支持的Joinpoint也是不同的。像final的方法和静态方法,无法通过动态代理来改变,所以Spring AOP无法支持。但AspectJ是直接在运行前织入实际的代码,所以功能会强大很多

Joinpoint

Spring AOP Supported

AspectJ Supported

Method Call

No

Yes

Method Execution

Yes

Yes

Constructor Call

No

Yes

Constructor Execution

No

Yes

Static initializer execution

No

Yes

Object initialization

No

Yes

Field reference

No

Yes

Field assignment

No

Yes

Handler execution

No

Yes

Advice execution

No

Yes

2.3、性能

编译织入会比较运行时织入快很多,Spring AOP是使用代理模式在运行时才创建对应的代理类,效率没有AspectJ高。

3、Spring Boot使用AspectJ

因为AspectJ比较强大,在项目中应用会更多,所以这里只介绍它与Spring Boot的集成。

3.1 、引入依赖

引入以下依赖,在Spring Boot基础上加了Lombok和aspectj:

代码语言:javascript
复制
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspectj.version}</version>
  </dependency>
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${aspectj.version}</version>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>${lombok.version}</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

3.2、被AOP的对象

为了验证AOP的功能,我们添加一个TestController,它有一个处理Get请求的方法,同时会调用private的成员方法和静态方法:

代码语言:javascript
复制
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
    @GetMapping("/hello")
    public String hello() {
        log.info("------hello() start---");
        test();
        staticTest();
        log.info("------hello() end---");
        return "Hello, pkslow.";
    }

    private void test() {
        log.info("------test() start---");
        log.info("test");
        log.info("------test() end---");
    }

    private static void staticTest() {
        log.info("------staticTest() start---");
        log.info("staticTest");
        log.info("------staticTest() end---");
    }
}

3.3、配置Aspect

配置切面如下:

代码语言:javascript
复制
@Aspect
@Component
@Slf4j
//@EnableAspectJAutoProxy
public class ControllerAspect {

    @Pointcut("execution(* com.pkslow.springboot.controller..*.*(..))")
    private void testControllerPointcut() {

    }

    @Before("testControllerPointcut()")
    public void doBefore(JoinPoint joinPoint){
        log.info("------pkslow aop doBefore start------");
        String method = joinPoint.getSignature().getName();
        String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
        log.info("Method: {}.{}" ,declaringTypeName, method);
        log.info("------pkslow aop doBefore end------");
    }

    @Around("testControllerPointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("------pkslow aop doAround start------");
        long start = System.nanoTime();
        Object obj = joinPoint.proceed();
        long end = System.nanoTime();
        log.info("Execution Time: " + (end - start) + " ns");
        log.info("------pkslow aop doAround end------");

        return obj;
    }
}

@Pointcut 定义哪些类和方法会被捕抓来代理,这里配置的是controller下的所有方法。

@Before@Around 则定义了一些处理逻辑。@Before 是打印了方法名,而 @Around 是做了一个计时。

注意:是不需要配置 @EnableAspectJAutoProxy 的。

3.4、maven插件

因为是需要编译时织入代码,所以需要maven插件的支持:https://github.com/mojohaus/aspectj-maven-plugin

配置好pom.xml文件即可。

然后执行命令打包:

代码语言:javascript
复制
mvn clean package

这时会显示一些织入信息,大致如下:

代码语言:javascript
复制
[INFO] Join point 'method-execution(java.lang.String com.pkslow.springboot.controller.TestController.hello())' in Type 'com.pkslow.springboot.controller.TestController' (TestController.java:14) advised by around advice from 'com.pkslow.springboot.aop.ControllerAspect' (ControllerAspect.class(from ControllerAspect.java))
[INFO] Join point 'method-execution(java.lang.String com.pkslow.springboot.controller.TestController.hello())' in Type 'com.pkslow.springboot.controller.TestController' (TestController.java:14) advised by before advice from 'com.pkslow.springboot.aop.ControllerAspect' (ControllerAspect.class(from ControllerAspect.java))
[INFO] Join point 'method-execution(void com.pkslow.springboot.controller.TestController.test())' in Type 'com.pkslow.springboot.controller.TestController' (TestController.java:22) advised by around advice from 'com.pkslow.springboot.aop.ControllerAspect' (ControllerAspect.class(from ControllerAspect.java))
[INFO] Join point 'method-execution(void com.pkslow.springboot.controller.TestController.test())' in Type 'com.pkslow.springboot.controller.TestController' (TestController.java:22) advised by before advice from 'com.pkslow.springboot.aop.ControllerAspect' (ControllerAspect.class(from ControllerAspect.java))
[INFO] Join point 'method-execution(void com.pkslow.springboot.controller.TestController.staticTest())' in Type 'com.pkslow.springboot.controller.TestController' (TestController.java:28) advised by around advice from 'com.pkslow.springboot.aop.ControllerAspect' (ControllerAspect.class(from ControllerAspect.java))
[INFO] Join point 'method-execution(void com.pkslow.springboot.controller.TestController.staticTest())' in Type 'com.pkslow.springboot.controller.TestController' (TestController.java:28) advised by before advice from 'com.pkslow.springboot.aop.ControllerAspect' (ControllerAspect.class(from ControllerAspect.java))

看到以上信息,说明成功织入了代码,具体可以查看生成的class文件。

可以看到有许多代码都不是我们写的,而是织入生成。

3.5 执行及测试

编译成功后,我们就执行代码。如果是通过IDEA来执行,则在运行前不需要再build了,因为已经通过maven build过了包。通过IDEA自带的编译器build,可能无法织入。或者选择ajc作为编译器。具体请参考:《Idea启动SpringBoot AOP失效的解决方法

访问如下:

代码语言:javascript
复制
GET http://localhost:8080/test/hello

则日志如下,成功实现AOP功能:

3.6、一些遇到的错误

遇到错误:

代码语言:javascript
复制
ajc Syntax error, annotations are only available if source level is 1.5 or greater

需要配置插件:

代码语言:javascript
复制
<complianceLevel>${java.version}</complianceLevel>
<source>${java.version}</source>
<target>${java.version}</target>

可能还会遇到无法识别Lombok的错误,配置如下则解决该问题:

代码语言:javascript
复制
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>aspectj-maven-plugin</artifactId>
  <version>1.14.0</version>
  <configuration>
    <complianceLevel>${java.version}</complianceLevel>
    <source>${java.version}</source>
    <target>${java.version}</target>
    <proc>none</proc>
    <showWeaveInfo>true</showWeaveInfo>
    <forceAjcCompile>true</forceAjcCompile>
    <sources/>
    <weaveDirectories>
      <weaveDirectory>${project.build.directory}/classes</weaveDirectory>
    </weaveDirectories>
  </configuration>
  <executions>
    <execution>
      <goals>
        <goal>compile</goal>
      </goals>
    </execution>
  </executions>
</plugin>

4、总结

AOP场景应用特别多,还是需要掌握的。

本文转载自: https://www.pkslow.com/archives/spring-aop-vs-aspectj

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、简介
  • 2、Spring AOP vs AspectJ
    • 2.1、织入方式
      • 2.2、Joinpoints
        • 2.3、性能
        • 3、Spring Boot使用AspectJ
          • 3.1 、引入依赖
            • 3.2、被AOP的对象
              • 3.3、配置Aspect
                • 3.4、maven插件
                  • 3.5 执行及测试
                    • 3.6、一些遇到的错误
                    • 4、总结
                    相关产品与服务
                    容器服务
                    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档