《Spring揭秘》第十章——Spring AOP二世
新特性
1. 可以使用POJO声明Aspect和Advice
2. 新的Pointcut表达方式
@AspectJ形式的Spring AOP
示例1:编程方式织入
@Aspect public class PerformanceTraceAspect { private final Log logger = LogFactory.getLog(PerformanceTraceAspect.class); @Pointcut("execution(public void *.method1()) || execution(public void *.method2())") public void pointcutName(){} @Around("pointcutName()") public Object performanceTrace(ProceedingJoinPoint joinPoint) { StopWatch watch = new StopWatch(); try { watch.start(); return joinPoint.proceed(); } catch (Throwable e) { logger.error("", e); return null; } finally { watch.stop(); if (logger.isInfoEnabled()) { logger.info("PT in method[" + joinPoint.getSignature().getName() + "]>>>>>" + watch.toString()); } } } } public class Foo { public void method1() { System.out.println("method1 execution."); } public void method2() { System.out.println("method2 execution."); } } public class Main { public static void main(String[] args) { AspectJProxyFactory weaver = new AspectJProxyFactory(); weaver.setProxyTargetClass(true); weaver.setTarget(new Foo()); weaver.addAspect(PerformanceTraceAspect.class); Object proxy = weaver.getProxy(); ((Foo) proxy).method1(); ((Foo) proxy).method2(); } }
执行结果如下:
method1 execution. 八月 30, 2018 3:21:00 下午 com.zte.mao.PerformanceTraceAspect performanceTrace 信息: PT in method[method1]>>>>>StopWatch '': running time (millis) = 37; [] took 37 = 100% method2 execution. 八月 30, 2018 3:21:00 下午 com.zte.mao.PerformanceTraceAspect performanceTrace 信息: PT in method[method2]>>>>>StopWatch '': running time (millis) = 0; [] took 0 = 0%
示例2:自动代理织入
<?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" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" > <property name="proxyTargetClass" value="true"></property> </bean> <bean id="performanceAspect" class="com.zte.mao.PerformanceTraceAspect"></bean> <bean id="target" class="com.zte.mao.Foo"></bean> </beans>
public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("springContext.xml"); Object proxy = context.getBean("target"); ((Foo) proxy).method1(); ((Foo) proxy).method2(); } }
执行结果如下:
八月 30, 2018 3:45:03 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4534b60d: startup date [Thu Aug 30 15:45:03 CST 2018]; root of context hierarchy 八月 30, 2018 3:45:03 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [springContext.xml] method1 execution. 八月 30, 2018 3:45:04 下午 com.zte.mao.PerformanceTraceAspect performanceTrace 信息: PT in method[method1]>>>>>StopWatch '': running time (millis) = 26; [] took 26 = 100% method2 execution. 八月 30, 2018 3:45:04 下午 com.zte.mao.PerformanceTraceAspect performanceTrace 信息: PT in method[method2]>>>>>StopWatch '': running time (millis) = 0; [] took 0 = 0%
将springContext.xml中的内容替换为下面内容,也可以实现自动代理织入:
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> <!-- <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" > <property name="proxyTargetClass" value="true"></property> </bean> --> <bean id="performanceAspect" class="com.zte.mao.PerformanceTraceAspect"></bean> <bean id="target" class="com.zte.mao.Foo"></bean>
@AspectJ形式的Pointcut
@Aspect public class CommonAspect { @Pointcut("execution(void method1())") // pointcut_expression private void method1Exec() {} // pointcut_signature @Pointcut("execution(void method2())") private void method2Exec() {} @Pointcut("execution(void method1()) || execution(void method1())") private void bothMethodExec() {} @Pointcut("method1Exec() || method2Exec()") private void bothMethodExec2() {} }
@AspectJ形式Pointcut表达式的标志符
execution(modifier-pattern? re-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?) with(declaring-type-pattern) // 只接受类型声明,匹配指定类型下的所有Jointpoint this(ObjectType) // this表示目标对象的代理对象,当代理对象的类型是ObjectType时,匹配ObjectType类型的所有Jointpoint target(ObjectType) // target表示目标对象,当目标对象是ObjectType时,匹配ObjectType类型目标对象内定义的所有Jointpoint args() // 指定参数类型、指定参数数量的Jointpoint @within() // 标注了某种类型的注解,静态匹配 @target() // 标注了某种类型的注解,动态匹配 @args() // 检查方法参数的参数类型是否包含某种类型的注解 @annotation() // 所有对象的所有方法级别的Jointpoint,方法是否包含某种类型的注解
实际上,@AspectJ形式声明的所有Pointcut表达式,在Spring中都会通过解析,转化成具体的Pointcut对象。
public class AspectJProxyFactory extends ProxyCreatorSupport { public void addAspect(Class<?> aspectClass) { String aspectName = aspectClass.getName(); AspectMetadata am = createAspectMetadata(aspectClass, aspectName); MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName); addAdvisorsFromAspectInstanceFactory(instanceFactory); } private AspectMetadata createAspectMetadata(Class<?> aspectClass, String aspectName) { AspectMetadata am = new AspectMetadata(aspectClass, aspectName); if (!am.getAjType().isAspect()) { throw new IllegalArgumentException("Class [" + aspectClass.getName() + "] is not a valid aspect type"); } return am; } } public AspectMetadata(Class<?> aspectClass, String aspectName) { this.aspectName = aspectName; Class<?> currClass = aspectClass; AjType<?> ajType = null; while (currClass != Object.class) { AjType<?> ajTypeToCheck = AjTypeSystem.getAjType(currClass); if (ajTypeToCheck.isAspect()) { ajType = ajTypeToCheck; break; } currClass = currClass.getSuperclass(); } if (ajType == null) { throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect"); } if (ajType.getDeclarePrecedence().length > 0) { throw new IllegalArgumentException("DeclarePrecendence not presently supported in Spring AOP"); } this.aspectClass = ajType.getJavaClass(); this.ajType = ajType; switch (this.ajType.getPerClause().getKind()) { case SINGLETON: this.perClausePointcut = Pointcut.TRUE; return; case PERTARGET: case PERTHIS: AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(); ajexp.setLocation(aspectClass.getName()); ajexp.setExpression(findPerClause(aspectClass)); ajexp.setPointcutDeclarationScope(aspectClass); this.perClausePointcut = ajexp; return; case PERTYPEWITHIN: // Works with a type pattern this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass))); return; default: throw new AopConfigException( "PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass); } }
@AspectJ形式的Advice
@Before
@AfterReturning
@AfterThrowing
@After
@Aroud
@DeclareParents Introduction类型的Advice,该注解对应标注对象的域(Field)而不是方法(Method)
Before示例:
public class Foo { public void method1() { System.out.println("method1 execution."); } public void method2() { System.out.println("method2 execution."); } public void method3() { System.out.println("method3 execution."); } public void method4(String name) { System.out.println("method4 execution, name=" + name); } } @Aspect public class BeforeAspect { @Pointcut("execution(public void *.method1()))") public void pointcutName(){} @Before("pointcutName()") public void beforeTest1() { System.out.println("@Before test1"); } @Before("execution(public void *.method2()))") public void beforeTest2() { System.out.println("@Before test2"); } @Before("execution(public void *.method4(String)))") public void beforeTest3(JoinPoint joinPoint) { System.out.println("@Before test3 : " + joinPoint.getArgs()[0]); } @Before(value = "execution(public void *.method4(String)) && args(name)") public void beforeTest4(String name) { System.out.println("@Before test4 : " + name); } } public class Main { public static void main(String[] args) { AspectJProxyFactory weaver = new AspectJProxyFactory(); weaver.setProxyTargetClass(true); weaver.setTarget(new Foo()); weaver.addAspect(BeforeAspect.class); Object proxy = weaver.getProxy(); ((Foo) proxy).method1(); ((Foo) proxy).method2(); ((Foo) proxy).method3(); ((Foo) proxy).method4("myName"); } }
执行结果:
@Before test1
method1 execution.
@Before test2
method2 execution.
method3 execution.
@Before test3 : myName
@Before test4 : myName
method4 execution, name=myName
posted on 2018-08-31 16:22 maoshiling 阅读(335) 评论(0) 编辑 收藏 举报