Spring 使用 @EnableAspectJAutoProxy 注解启用 AOP


#Spring#


示例1

项目结构

.
├── build.gradle
└── src
    └── main
        ├── java
        │   └── demo
        │       ├── Main.java
        │       ├── TestAspect.java
        │       └── TestBean.java
        └── resources

build.gradle

gradle 中引入了如下依赖:

dependencies {

    compile group: 'org.springframework', name: 'spring-core', version: '5.0.6.RELEASE'
    compile group: 'org.springframework', name: 'spring-context', version: '5.0.6.RELEASE'
    compile group: 'org.springframework', name: 'spring-aop', version: '5.0.6.RELEASE'
    compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.1'

    compile group: 'junit', name: 'junit', version: '4.12'

}

TestBean.java

TestBean 类内容如下:

package demo;

import org.springframework.stereotype.Component;

@Component
public class TestBean {

    public void hello() {
        System.out.println("hello");
    }
}

TestAspect.java

TestAspect 类定义了切面,内容如下:

package demo;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @Aspect 和 @Component 都要有
 */
@Aspect
@Component
public class TestAspect {

    // 定义切点(切入位置)
    @Pointcut("execution(* demo.TestBean.*(..))")
    private void pointcut(){}


    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
        System.out.println("我是前置通知");
    }

}

Main.java

Main 类内容:

package demo;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy // 要加上这个
public class Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Main.class);
        TestBean testBean = ctx.getBean(TestBean.class);
        testBean.hello();
    }

}

执行结果

Main 类执行结果:

我是前置通知
hello

示例2:如果切面类没有 @Component

如果没有 @Component ,那么切面无效;如果切面类无法被扫描到,切面也是无效的。

项目结构

.
├── build.gradle
└── src
    └── main
        ├── java
        │   ├── demo01
        │   │   ├── Main.java
        │   │   └── TestBean.java
        │   └── demo02
        │       └── TestAspect.java
        └── resources

TestBean.java

TestBean 类内容如下:

package demo01;

import org.springframework.stereotype.Component;

@Component
public class TestBean {

    public void hello() {
        System.out.println("hello");
    }
}

TestAspect.java

TestAspect 类挪到了 demo02 包,并去掉了 @Component:

package demo02;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
public class TestAspect {

    // 定义切点(切入位置)
    @Pointcut("execution(* demo01.TestBean.*(..))")
    private void pointcut(){}


    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
        System.out.println("我是前置通知");
    }

}

Main.java

如果 Main 类内容如下,切面是无效的:

package demo01;

import demo02.TestAspect;
import org.springframework.context.annotation.*;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Main.class);
        TestBean testBean = ctx.getBean(TestBean.class);
        testBean.hello();
    }

}

改成下面这样子,就行了:

package demo01;

import demo02.TestAspect;
import org.springframework.context.annotation.*;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class Main {

    // 让切面类生成bean,以让切面生效
    @Bean
    public TestAspect testAspect() {
        return new TestAspect();
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Main.class);
        TestBean testBean = ctx.getBean(TestBean.class);
        testBean.hello();
    }

}

运行结果:

我是前置通知
hello

( 本文完 )