13.spring之基于@AspectJ的AOP

1.启用对@AspectJ的支持

spring默认不支持@Aspect风格的切面声明,需要添加如下配置

<aop:aspectj-autoproxy/>  

这样Spring就能发现@AspectJ风格的切面并且将切面应用到目标对象。

2.声明切面

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

@Aspect()  
Public class Aspect{  

} 

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

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

该切面就是一个POJO,可以在该切面中进行切入点及通知定义,接着往下看吧。

3.声明切入点

@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) {}

4.声明通知

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

  • 前置通知:使用org.aspectj.lang.annotation 包下的@Before注解声明;
@Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名")  

下面来一个例子

@Aspect
@Component
public class HelloWorldAspectAnno {

    @Pointcut(value="execution(* com.anjunshuang..*.sayBefore(..)) && 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);
    }
}
public interface HelloWorldService {
    void sayHello();

    void sayBefore(String name);
}
public class HelloWorldServiceImpl implements HelloWorldService {
    @Override
    public void sayHello() {
        System.out.println("hello world aspect!");
    }

    @Override
    public void sayBefore(String name) {
        System.out.println("hello world aspect!" + name);
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:aspectj-autoproxy/>
    <bean id="helloWorldService"
          class="com.anjunshuang.spring.aop.service.impl.HelloWorldServiceImpl"/>

    <bean id="aspect"
          class="com.anjunshuang.spring.aop.aspect.HelloWorldAspectAnno"/>
</beans>
    @Test
    public void testAnnotationBeforeAdvice() {
        System.out.println("======================================");
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/aspect/advice2.xml");
        HelloWorldService helloWorldService = ctx.getBean("helloWorldService", HelloWorldService.class);
        helloWorldService.sayBefore("before");
        System.out.println("======================================");
    }

切面、切入点、通知全部使用注解完成:

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

 几个通知的例子,大体都类似

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

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

    @Around(value="execution(* com.anjunshuang..*.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;
    }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值