面向切面的Spring
一、面向切面的概念
在软件开发中,散布于应用多处的功能被称为横切关注点(cross-cutting concern)。
通常来讲这些横切关注带点从概念上来讲是与应用逻辑相分离的(但是往往会直接嵌入到应用的业务逻辑中)。
把这些横切关注点与业务逻辑相互分离正是面向切面编程(AOP)所要解决的问题。
切面所适用的场景:日志、声明式事务、安全和缓存。
横切关注点可以被模块化特殊的类,这些类被称为切面。
1.相关术语
1)通知(advice):描述了切面的工作及如何工作。通知的类型:
前置通知(Before)
后置通知(After)
返回通知(After-returning)
异常通知(After-throwing)
环绕通知(方法调用前后都执行)
2)连接点(join-point):应用执行时可以插入的一个点,如方法调用时,异常抛出时。
3)切点(cut-point):切点的定义会匹配通知所要植入的一个或者多个链接点。
4)切面(Aspect):切面是通知和切点的结合,通知和切点共同定义切面的全部内容----
它是什么及何时何地完成其内容。
5)引入(Introduction):
6)织入(Weaving):把切面应用到目标对象,并创建新的代理的过程。
2.Spring对AOP的支持
Spring提供了4种类型的AOP支持
1.基于代理的经典SpingAOP
2.纯POJO切面
3.@AspectJ注解驱动的切面
4.注入式AspectJ切面
前三个都是Spring AOP实现的变体,Spring AOP构建在动态代理的基础上,
因此,Spring对AOP的支持仅仅限于方法层面。
1.示例使用JavaConfig:
public interface Performance { void performance(); }
public class Actor implements Performance{ public void performance() { System.out.println("An actor is on the stage!!!~!!"); } }
@Aspect public class Audience { //定义命名的切点 @Pointcut("execution(* entity.Actor.performance(..))") public void performance() {} @Before("performance()") public void silence() { System.out.println("Silence please!"); } @Before("performance()") public void takeSeats() { System.out.println("Take seats please!"); } @AfterReturning("performance()") public void performanceOver() { System.out.println("Performance Over!"); } @AfterThrowing("performance()") public void wrong() { System.out.println("Something wrong with the show!"); } /* * 在一个通知方法中同时编写前置和后置通知 * */ @Around("performance()") public void around(ProceedingJoinPoint pjp) { System.out.println("Around!! before"); try { pjp.proceed(); //必须调用该方法,如果不调用会阻塞除了 // AfterReturning以外的其他方法 System.out.println("Around!! after"); } catch (Throwable throwable) { throwable.printStackTrace(); } } }
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = Aconfig.class) public class TestAll { @Autowired private Performance actor; @Test public void ts() { actor.performance(); /*Around!! before Silence please! Take seats please! An actor is on the stage!!!~!! Around!! after Performance Over!*/ } }
@Configuration @EnableAspectJAutoProxy //启用自动代理功能 public class Aconfig { @Bean public Audience audience() { return new Audience(); } @Bean public Performance actor() { return new Actor(); } }
2.示例通过XML:
@Aspect public class Audience { public void silence() { System.out.println("Silence please!"); } public void takeSeats() { System.out.println("Take seats please!"); } public void performanceOver() { System.out.println("Performance Over!"); } public void wrong() { System.out.println("Something wrong with the show!"); } /* * 在一个通知方法中同时编写前置和后置通知 * */ public void around(ProceedingJoinPoint pjp) { System.out.println("Around!! before"); try { pjp.proceed(); //必须调用该方法,如果不调用会阻塞除了 // AfterReturning以外的其他方法 System.out.println("Around!! after"); } catch (Throwable throwable) { throwable.printStackTrace(); } } }
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--目标对象--> <bean id="actor" class="entity.Actor" /> <!--切面对象--> <bean id="audience" class="entity.Audience"/> <!--切面--> <aop:config> <!--定义命名的切点--> <aop:pointcut expression="execution(* entity.Actor.performance(..))" id="cutRef"/> <aop:aspect ref="audience"> <aop:before method="silence" pointcut-ref="cutRef"/> <aop:before method="takeSeats" pointcut-ref="cutRef"/> <aop:after-returning method="performanceOver" pointcut-ref="cutRef"/> <aop:after-throwing method="wrong" pointcut-ref="cutRef"/> <aop:around method="around" pointcut-ref="cutRef"/> </aop:aspect> </aop:config> <aop:aspectj-autoproxy/><!--启用自动代理--> </beans>
@Autowired private Performance actor; @Test public void ts() { actor.performance(); /*Silence please! Take seats please! Around!! before An actor is on the stage!!!~!! Around!! after Performance Over!*/ }
3.处理通知中的参数