Spring AOP使用整理:使用@AspectJ风格的切面声明
要启用基于@AspectJ风格的切面声明,需要进行以下的配置:
- <!-- 启用@AspectJ风格的切面声明 -->
- <aop:aspectj-autoproxy proxy-target-class="true"/>
- <!-- 通过注解定义bean。默认同时也通过注解自动注入 -->
- <context:component-scan base-package="com.cjm"/>
<!-- 启用@AspectJ风格的切面声明 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 通过注解定义bean。默认同时也通过注解自动注入 -->
<context:component-scan base-package="com.cjm"/>
基于@AspectJ风格的切面声明的源码:
- /**
- * 声明本类为一个切面
- */
- @Component
- @Aspect
- public class MyAspectJ {
- /**
- * 声明一个切入点(包括切入点表达式和切入点签名)
- */
- @Pointcut("execution(* com.cjm.model..*.*(..))")
- public void pointcut1(){}
- /**
- * 声明一个前置通知
- */
- @Before("pointcut1()")
- public void beforeAdvide(JoinPoint point){
- System.out.println("触发了前置通知!");
- }
- /**
- * 声明一个后置通知
- */
- @After("pointcut1()")
- public void afterAdvie(JoinPoint point){
- System.out.println("触发了后置通知,抛出异常也会被触发!");
- }
- /**
- * 声明一个返回后通知
- */
- @AfterReturning(pointcut="pointcut1()", returning="ret")
- public void afterReturningAdvice(JoinPoint point, Object ret){
- System.out.println("触发了返回后通知,抛出异常时不被触发,返回值为:" + ret);
- }
- /**
- * 声明一个异常通知
- */
- @AfterThrowing(pointcut="pointcut1()", throwing="throwing")
- public void afterThrowsAdvice(JoinPoint point, RuntimeException throwing){
- System.out.println("触发了异常通知,抛出了RuntimeException异常!");
- }
- /**
- * 声明一个环绕通知
- */
- @Around("pointcut1()")
- public Object aroundAdvice(ProceedingJoinPoint point)throws Throwable{
- System.out.println("触发了环绕通知 开始");
- Object o = point.proceed();
- System.out.println("触发了环绕通知 结束");
- return o;
- }
- }
/**
* 声明本类为一个切面
*/
@Component
@Aspect
public class MyAspectJ {
/**
* 声明一个切入点(包括切入点表达式和切入点签名)
*/
@Pointcut("execution(* com.cjm.model..*.*(..))")
public void pointcut1(){}
/**
* 声明一个前置通知
*/
@Before("pointcut1()")
public void beforeAdvide(JoinPoint point){
System.out.println("触发了前置通知!");
}/**
* 声明一个后置通知
*/
@After("pointcut1()")
public void afterAdvie(JoinPoint point){
System.out.println("触发了后置通知,抛出异常也会被触发!");
}/**
* 声明一个返回后通知
*/
@AfterReturning(pointcut="pointcut1()", returning="ret")
public void afterReturningAdvice(JoinPoint point, Object ret){
System.out.println("触发了返回后通知,抛出异常时不被触发,返回值为:" + ret);
}/**
* 声明一个异常通知
*/
@AfterThrowing(pointcut="pointcut1()", throwing="throwing")
public void afterThrowsAdvice(JoinPoint point, RuntimeException throwing){
System.out.println("触发了异常通知,抛出了RuntimeException异常!");
}/**
* 声明一个环绕通知
*/
@Around("pointcut1()")
public Object aroundAdvice(ProceedingJoinPoint point)throws Throwable{
System.out.println("触发了环绕通知 开始");
Object o = point.proceed();
System.out.println("触发了环绕通知 结束");
return o;
}
}
1、切入点表达式的格式:execution([可见性] 返回类型 [声明类型].方法名(参数) [异常])
2、切入点表达式通配符:
*:匹配所有字符
..:一般用于匹配多个包,多个参数
+:表示类及其子类
3、切入点表达式支持逻辑运算符:&&、||、!
4、切入点表达式关键词:
1)execution:用于匹配子表达式。
//匹配com.cjm.model包及其子包中所有类中的所有方法,返回类型任意,方法参数任意
@Pointcut("execution(* com.cjm.model..*.*(..))")
public void before(){}
2)within:用于匹配连接点所在的Java类或者包。
//匹配Person类中的所有方法
@Pointcut("within(com.cjm.model.Person)")
public void before(){}
//匹配com.cjm包及其子包中所有类中的所有方法
@Pointcut("within(com.cjm..*)")
public void before(){}
3) this:用于向通知方法中传入代理对象的引用。
@Before("before() && this(proxy)")
public void beforeAdvide(JoinPoint point, Object proxy){
//处理逻辑
}
4)target:用于向通知方法中传入目标对象的引用。
@Before("before() && target(target)
public void beforeAdvide(JoinPoint point, Object proxy){
//处理逻辑
}
5)args:用于将参数传入到通知方法中。
@Before("before() && args(age,username)")
public void beforeAdvide(JoinPoint point, int age, String username){
//处理逻辑
}
6)@within:用于匹配在类一级使用了参数确定的注解的类,其所有方法都将被匹配。
@Pointcut("@within(com.cjm.annotation.AdviceAnnotation)") - 所有被@AdviceAnnotation标注的类都将匹配
public void before(){}
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.TYPE, ElementType.METHOD})
- @Documented
- @Inherited
- public @interface AdviceAnnotation {
- }
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Inherited
public @interface AdviceAnnotation {
}
7)@target:和@within的功能类似,但必须要指定注解接口的保留策略为RUNTIME。
@Pointcut("@target(com.cjm.annotation.AdviceAnnotation)")
public void before(){}
8)@args:传入连接点的对象对应的Java类必须被@args指定的Annotation注解标注。
@Before("@args(com.cjm.annotation.AdviceAnnotation)")
public void beforeAdvide(JoinPoint point){
//处理逻辑
}
- public class Person {
- public void say(Address address){
- //处理逻辑
- }
- }
- @AdviceAnnotation
- public class Address {
- }
public class Person {
public void say(Address address){
//处理逻辑
}
}
@AdviceAnnotation
public class Address {
}
如果需要在Person类的say方法被调用时触发beforeAdvide通知,那么say方法的参数对应的Java类型Address类必须要被@AdviceAnnotation标注。
9)@annotation:匹配连接点被它参数指定的Annotation注解的方法。也就是说,所有被指定注解标注的方法都将匹配。
@Pointcut("@annotation(com.cjm.annotation.AdviceAnnotation)")
public void before(){}
- public class Person {
- @AdviceAnnotation
- public void say(Address address){
- //处理逻辑
- }
- }
public class Person {
@AdviceAnnotation
public void say(Address address){
//处理逻辑
}
}
Person类的say方法被@AdviceAnnotation标注,所以它匹配。
10)bean:通过受管Bean的名字来限定连接点所在的Bean。该关键词是Spring2.5新增的。
@Pointcut("bean(person)")
public void before(){}
id为person的受管Bean中的所有方法都将匹配。