Spring AOP与AspectJ的对比及应用

科技资讯 投稿 5900 0 评论

Spring AOP与AspectJ的对比及应用

1 简介

2 Spring AOP vs AspectJ

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

2.1 织入方式

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

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

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

2.2 Joinpoints

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

3.1 引入依赖

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

<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的成员方法和静态方法:

@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

配置切面如下:

@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插件

配置好pom.xml文件即可。

mvn clean package

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

[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失效

GET http://localhost:8080/test/hello

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

3.6 一些遇到的错误

ajc Syntax error, annotations are only available if source level is 1.5 or greater

需要配置插件:

<complianceLevel>${java.version}</complianceLevel>
<source>${java.version}</source>
<target>${java.version}</target>

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

<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场景应用特别多,还是需要掌握的。

代码请看GitHub: https://github.com/LarryDpk/pkslow-samples

编程笔记 » Spring AOP与AspectJ的对比及应用

赞同 (28) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽