实践Spring Enable系列之EnableAspectJAutoProxy

1
2
3
4
5
6
7
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
//...
}

切面:切点的容器,使用@Aspect定义

切点(PointCut):拦截规则,一般分为基于方法(execution)或基于注解(@annotation),可以被复用

建言(Advice):拦截植入的时机及动作,@Before、@After、@Around、@AfterReturing和@AfterThrowing,需指定切点,可以直接基于方法或基于PointCut指定

连接点(JoinPoint):符合拦截规则的每一个被拦截处

Enables support for handling components marked with AspectJ’s @Aspect annotation, similar to functionality found in Spring’s <aop:aspectj-autoproxy> XML element. To be used on @Configuration classes as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
 @Configuration
 @EnableAspectJAutoProxy
 public class AppConfig {
     @Bean
     public FooService fooService() {
         return new FooService();
     }

     @Bean
     public MyAspect myAspect() {
         return new MyAspect();
     }
 }

Where FooService is a typical POJO component and MyAspect is an @Aspect-style aspect:

1
2
3
 public class FooService {
     // various methods
 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 @Aspect
 public class MyAspect {
     @Before("execution(* FooService+.*(..))")
     public void advice() {
         // advise FooService methods as appropriate
     }
     
     //在该无参无内容的方法上添加一个@Poincut()来声明切入点,在后来的@Around("pc()")直接写入该方法的名字就能在自动使用这些切点
	@Pointcut("execution(* com.service..*.add*(..)) || execution(* com.service..*.modify*(..)) || execution(* com.service..*.drop*(..))")
    public void pc() {}
     
     @After("pc()")
     public void advice() {
         // advise FooService methods as appropriate
     }
 }

In the scenario above, @EnableAspectJAutoProxy ensures that MyAspect will be properly processed and that FooService will be proxied mixing in the advice that it contributes. Users can control the type of proxy that gets created for FooService using the proxyTargetClass()attribute. The following enables CGLIB-style ‘subclass’ proxies as opposed to the default interface-based JDK proxy approach.

1
2
3
4
5
 @Configuration
 @EnableAspectJAutoProxy(proxyTargetClass=true)
 public class AppConfig {
     // ...
 }

Note that @Aspect beans may be component-scanned like any other. Simply mark the aspect with both @Aspect and @Component:

1
2
3
4
5
6
7
8
 package com.foo;

 @Component
 public class FooService { ... }

 @Aspect
 @Component
 public class MyAspect { ... }

Then use the @ComponentScan annotation to pick both up:

1
2
3
4
5
6
 @Configuration
 @ComponentScan("com.foo")
 @EnableAspectJAutoProxy
 public class AppConfig {
     // no explicit @Bean definitions required
 }