spring12----基于@AspectJ的AOP

Spring除了支持Schema方式配置AOP,还支持注解方式:使用@AspectJ风格的切面声明。

一. 启用对@AspectJ的支持

 Spring默认不支持@AspectJ风格的切面声明,为了支持需要使用如下配置

<aop:aspectj-autoproxy/>

二. 声明切面

@AspectJ风格的声明切面非常简单,使用@Aspect注解进行声明:

@Aspect() 
Public class Aspect{
……
}

然后将该切面在配置文件中声明为Bean后,Spring就能自动识别并进行AOP方面的配置:

<bean id="aspect" class="……Aspect"/>

三. 声明切入点

@AspectJ风格的命名切入点使用org.aspectj.lang.annotation包下的@Pointcut+方法(方法必须是返回void 类型)实现。

@Pointcut(value="切入点表达式", argNames = "参数名列表")
 public void pointcutName(……) {
 }

value:指定切入点表达式;
argNames:指定命名切入点方法参数列表参数名字,可以有多个用“,”分隔,这些参数将传递给通知方法同 名的参数,同时比如切入点表达式“args(param)”将匹配参数类型为命名切入点方法同名参数指定的参数类型。
pointcutName:切入点名字,可以使用该名字进行引用该切入点表达式。

@Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")  
public void beforePointcut(String param) {}  

说明:定义了一个切入点,名字为“beforePointcut”,该切入点将匹配目标方法的第一个参数类型为通知方法实现中参数 名为“param”的参数类型。

四. 声明通知

@AspectJ风格的声明通知也支持5种通知类型:

1. 前置通知

使用org.aspectj.lang.annotation 包下的@Before注解声明;

@Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名")

value:指定切入点表达式或命名切入点;
argNames:与Schema方式配置中的同义。

举例:

1 public interface IHelloWorldService {
2     public void sayAdviserBefore(String param);
3 }
View Code
 1 package com.test.spring.service.impl;
 2 
 3 
 4 import com.test.spring.service.IHelloWorldService;
 5 
 6 public class HelloWorldService implements IHelloWorldService{
 7     public void sayAdviserBefore(String param) {
 8         
 9     }
10 }
View Code
@Aspect
public class HelloWorldAspect2 {
    @Pointcut(value="execution(* com.test.spring.service.impl..*.sayAdviserBefore(..)) && args(param)", argNames = "param")  
    public void beforePointcut(String param) {
    }
    
    @Before(value = "beforePointcut(param)", argNames = "param")  
    public void beforeAdvice(String param) {  
        System.out.println("===========before advice param:" + param);  
    } 
    

}
<aop:aspectj-autoproxy/>
    <bean id="helloWorldService"
        class="com.test.spring.service.impl.HelloWorldService" />
    <bean id="aspect" class="com.test.spring.aop.HelloWorldAspect2" />
 1 public class AopTest {
 2     @Test
 3     public void test() {
 4         ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
 5         IHelloWorldService helloWorldService=(IHelloWorldService) context.getBean("helloWorldService");
 6         helloWorldService.sayAdviserBefore("hahah");
 7     }
 8 }
 9 
10 
11 ===========before advice param:hahah
View Code

分析:

切面、切入点、通知全部使用注解完成:
1)使用@Aspect将POJO声明为切面;
2)使用@Pointcut进行命名切入点声明,同时指定目标方法第一个参数类型必须是java.lang.String,对于其他 匹配的方法但参数类型不一致的将也是不匹配的,通过argNames = "param"指定了将把该匹配的目标方法参数传递 给通知同名的参数上;
3)使用@Before进行前置通知声明,其中value用于定义切入点表达式或引用命名切入点;
4)配置文件需要使用<aop:aspectj-autoproxy/>来开启注解风格的@AspectJ支持;
5)需要将切面注册为Bean,如“aspect”Bean;
6)测试代码完全一样。

2. 后置返回通知

使用org.aspectj.lang.annotation 包下的@AfterReturning注解声明;

@AfterReturning(  
value="切入点表达式或命名切入点",  
pointcut="切入点表达式或命名切入点",  
argNames="参数列表参数名",  
returning="返回值对应参数名")  

  value指定切入点表达式或命名切入点;

  pointcut同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

  argNames与Schema方式配置中的同义;

  returning与Schema方式配置中的同义。

@AfterReturning(  
    value="execution(* cn.javass..*.sayBefore(..))",  
    pointcut="execution(* cn.javass..*.sayAfterReturning(..))",  
    argNames="retVal", returning="retVal")  
public void afterReturningAdvice(Object retVal) {  
    System.out.println("===========after returning advice retVal:" + retVal);  
}  

3. 后置异常通知

三、后置异常通知:

使用org.aspectj.lang.annotation 包下的@AfterThrowing注解声明;

@AfterThrowing (  
value="切入点表达式或命名切入点",  
pointcut="切入点表达式或命名切入点",  
argNames="参数列表参数名",  
throwing="异常对应参数名")  

       value指定切入点表达式或命名切入点;

       pointcut同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

       argNames与Schema方式配置中的同义;

       throwing与Schema方式配置中的同义。

@AfterThrowing(  
    value="execution(* cn.javass..*.sayAfterThrowing(..))",  
    argNames="exception", throwing="exception")  
public void afterThrowingAdvice(Exception exception) {  
    System.out.println("===========after throwing advice exception:" + exception);  
}  

四. 后置最终通知

使用org.aspectj.lang.annotation 包下的@After注解声明

@After (  
value="切入点表达式或命名切入点",  
argNames="参数列表参数名")  

       value指定切入点表达式或命名切入点;

       argNames与Schema方式配置中的同义;

@After(value="execution(* cn.javass..*.sayAfterFinally(..))")  
public void afterFinallyAdvice() {  
    System.out.println("===========after finally advice");  
}  

5. 环绕通知

使用org.aspectj.lang.annotation 包下的@Around注解声明

@Around (  
value="切入点表达式或命名切入点",  
argNames="参数列表参数名")  

       value指定切入点表达式或命名切入点;

       argNames与Schema方式配置中的同义;

@Around(value="execution(* cn.javass..*.sayAround(..))")  
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {  
    System.out.println("===========around before advice");  
    Object retVal = pjp.proceed(new Object[] {"replace"});  
    System.out.println("===========around after advice");  
    return retVal;  
}  

参考文献

https://jinnianshilongnian.iteye.com/blog/1420689

原文地址:https://www.cnblogs.com/Hermioner/p/10202374.html