2019独角兽企业重金招聘Python工程师标准>>>
Spring除了支持Schema方式配置AOP,还支持注解方式:使用@AspectJ风格的切面声明。
启用对@AspectJ的支持
<aop:aspectj-autoproxy/>
声明切面
@AspectJ风格的声明切面只需要使用@Aspect注解进行声明,可以在该切面中进行切入点及通知定义
@Aspect()
Public class Aspect{ ....}
将此切面声明成Bean,<bean id="aspect" class="……Aspect"/>
声明切入点
@AspectJ风格的命名切入点使用org.aspectj.lang.annotation包下的@Pointcut+方法(方法必须是返回void类型)实现。
@Pointcut(value="切入点表达式", argNames = "参数名列表")
public void pointcutName(……) {}
argNames指定命名切入点方法参数列表参数名字,可以有多个用“,”分隔,这些参数将传递给通知方法同名的参数,同时比如切入点表达式“args(param)”将匹配参数类型为命名切入点方法同名参数指定的参数类型。
pointcutName:切入点名字,可以使用该名字进行引用该切入点表达式。
@Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")
public void beforePointcut(String param) {}
定义了一个切入点,名字为“beforePointcut”,该切入点将匹配目标方法的第一个参数类型为通知方法实现中参数名为“param”的参数类型。
声明通知
5种通知类型:前置通知,后置返回通知,后置异常通知,后置最终通知,环绕通知。
前置通知:@Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名")
1、定义接口和实现,在此我们就使用Schema风格时的定义;
2、定义切面:
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class HelloWorldAspect2 { }
3、定义切入点:
@Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")
public void beforePointcut(String param) {}
4、定义通知:
@Before(value = "beforePointcut(param)", argNames = "param")
public void beforeAdvice(String param) {System.out.println("====before advice param:" + param);}
5、xml配置
<?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-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="helloWorldService" class="cn.javass.spring.chapter6.service.impl.HelloWorldService"/> <bean id="aspect" class="cn.javass.spring.chapter6.aop.HelloWorldAspect2"/>
</beans>
总结:
切面、切入点、通知全部使用注解完成:
1)使用@Aspect将POJO声明为切面;
2)使用@Pointcut进行命名切入点声明,同时指定目标方法第一个参数类型必须是java.lang.String,对于其他匹配的方法但参数类型不一致的将也是不匹配的,通过argNames = "param"指定了将把该匹配的目标方法参数传递给通知同名的参数上;
3)使用@Before进行前置通知声明,其中value用于定义切入点表达式或引用命名切入点;
4)配置文件需要使用<aop:aspectj-autoproxy/>来开启注解风格的@AspectJ支持;
5)需要将切面注册为Bean,如“aspect”Bean;
6)测试代码完全一样。
后置返回通知:
@AfterReturning(
value="切入点表达式或命名切入点",
pointcut="切入点表达式或命名切入点",
argNames="参数列表参数名",
returning="返回值对应参数名")
@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);
}
其它代码与前置通知一样。
后置异常通知:
@AfterThrowing (
value="切入点表达式或命名切入点",
pointcut="切入点表达式或命名切入点",
argNames="参数列表参数名",
throwing="异常对应参数名")
@AfterThrowing(
value="execution(* cn.javass..*.sayAfterThrowing(..))",
argNames="exception", throwing="exception")
public void afterThrowingAdvice(Exception exception) {
System.out.println("====after throwing advice exception:" + exception);
}
后置最终通知:
@After (
value="切入点表达式或命名切入点",
argNames="参数列表参数名")
@After(value="execution(* cn.javass..*.sayAfterFinally(..))")
public void afterFinallyAdvice() {
System.out.println("====after finally advice");
}
环绕通知:
@Around (
value="切入点表达式或命名切入点",
argNames="参数列表参数名")
@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;
}