A、面向切面
AOP解决了通用功能点和业务逻辑分离开
DI有助于应用对象之间的解耦,AOP实现横切关注点与他们所影响的对象之间的解耦
看完能回答的问题
a、如何将一个类声明为切面?
b、Spring如何实现切面?
1、AOP基础信息
切面的常用术语:通知、切点、连接点
通知:定义了切面是什么以及何时使用,分为五种类型通知:前置、后置、返回、异常、环绕通知
连接点:应用程序中的需要织入通知的点
切点:定义了切面的何处,定义好之后会匹配上织入点的一个或者多个连接点,
切面:切点和通知的结合,总和,它是什么,在何时和何处完成其功能
织入:把切面应用到目标对象并创建新的代理对象的古城
目标对象生命周期的多个点织入:编译器、类加载器、运行期(Spring AOP就是这种形式织入的)
Spring在运行时通知对象
在代理类中包裹切面,代理类封装了目标类,拦截被通知方法的调用,再转发调用,代理拦截到调用时执行切面逻辑再调用目标bean
Spring支持方法级别的连接点
定义切点,选择连接点
定义切点的时候使用aspectJ表达式来进行操作,execution指示器是用来实际执行匹配的,其他的指示器用来限制所匹配的切点。@within、@target、@annotation、@args等等
2、编写切点:
@Aspect 定义一个类是切面
2.1、切点表达式:
@Pointcut("execution(public * spring.Performance.perform(..))")
以*号开始,不关心返回值类型;spring.Performance.perform 全限定名和方法名;(..)不关注调用perform时传入的参数
@Pointcut("execution(public * spring.Performance.perform(..)) && within(spring.*)")
仅匹配spring包下的方法被调用
&& and关系;|| 或关系;!not关系;
2.2、在切点中选择指定的bean
@Pointcut("execution(public * spring.Performance.perform(..)) && bean('wookstock')")
仅在bean为wookstock的时候织入切点
2.2.1、定义通知(使用注解表明应该在什么时候调用)
@After(通知方法会在目标方法返回或者抛出异常后调用)、@AfterReturning、@AfterThrowing
@Before
@Around(通知方法会将目标方法封装起来)
@Pointcut 定义一个切点表达式,在其他的定义通知里可以直接使用@Pointcut定义的切点方法
2.2.2、启动自动代理功能:
xml形式: <aop:aspectj-autoproxy proxy-target-class="true" /> 声明注解类
注解形式: @EnableAspectJAutoProxy
切面依然是基于代理的???这句话怎么理解,尽管使用的是@Aspect注解,但我们仍然限于代理方法的调用,代理方法是什么意思?
2.2.3、创建环绕通知
环绕通知顾名思义就是环绕在目标方法执行过程中的通知,执行前、执行返回后、执行异常返回后,一个顶好几个通知定义
@Around("execution(* spring.Performance.perform(..))")
public void watchPerforence(ProceedingJoinPoint pj) {
try {
// 表演前
System.out.println("Silencing cell phones");
System.out.println("Taking Seats");
pj.proceed(); // 将控制权交给被通知的方法
// 表演后
System.out.println("CLAP CLAP CLAP!");
} catch (Throwable e) {
// 表演失败
System.out.println("Demand a refund");
}
}
携带参数的切点:"execution(* spring.Performance.perform(int)) && args(trackNumber)
Spring发现一个bean使用了@Aspect注解时,Spring就会创建一个代理,然后将调用委托给被代理的bean或者被引入的实现
基于注解的配置 > 基于Java的配置 > 基于XML的配置
XML的配置: aop:after/before/around
<aop:aspectj-autoproxy> 启用@Aspect注解的驱动
<aop:config>
<aop:aspect ref="audience">
<!-- 定义切点-->
<aop:pointcut id="embark" expression="execution(* *.)"/>
<!--前置通知-->
<aop:before pointcut-ref="embark" method="XXX"/>
<!--后置通知-->
<aop:after pointcut-ref="embark" method="YYY"/>
</aop:aspect>
</aop:config>
多个方法协作的时候,要想进行通信,那么就是有一个成员变量,都可以调用,但是会存在线程问题,因为实例只有一个
asepctOf() 获取切面的引用