在开发过程中,不少有Spring Aop的使用,在面向切面编程时,我们会使用< aop:aspect>;在进行事务管理时,我们会使用< aop:advisor>。那么,对于< aop:aspect>与< aop:advisor>的区别,具体是怎样的呢?
在面向切面编程时,我们一般会用<aop:aspect>,<aop:aspect>定义切面(包括通知(前置通知,后置通知,返回通知等等)和切点(pointcut))
在进行事务管理时,我们一般会用<aop:advisor>,<aop:advisor>定义通知其(通知器跟切面一样,也包括通知和切点)。
<aop:advisor>大多用于事务管理。
<aop:aspect>大多用于日志、缓存。
在AOP中有几个概念:
— 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。
— 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
— 通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。
— 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。
所以<aop:aspect>实际上是定义横切逻辑,就是在连接点上做什么,<aop:advisor>则定义了在哪些连接点上应用什么<aop:aspect>。Spring这样做的好处就是可以让多个横切逻辑 (即<aop:aspect>定义的)多次使用,提供可重用性。
总的来说:
1、Adivisor是一种特殊的Aspect,Advisor代表spring中的Aspect
2、advisor只持有一个Pointcut和一个advice,而aspect可以多个pointcut和多个advice
下面,我们列举两者的几个区别。
1、实现方式不同
< aop:aspect>定义切面时,只需要定义一般的bean就行,而定义< aop:advisor>中引用的通知时,通知必须实现Advice接口。
下面我们举例说明。
首先,我们定义一个接口Sleepable和这个接口的实现Human,代码如下:
public interface Sleepable {
public void sleep();
}
public class Human implements Sleepable {
@Override
public void sleep() {
System.out.println("我要睡觉了!");
}
}
下面是< aop:advisor>的实现方式:
//定义通知
public class SleepHelper implements MethodBeforeAdvice,AfterReturningAdvice{
@Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
System.out.println("睡觉前要脱衣服!");
}
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
System.out.println("起床后要穿衣服!");
}
}
//aop配置
<bean id="sleepHelper" class="com.ghs.aop.SleepHelper"></bean>
<aop:config>
<aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/>
<aop:advisor advice-ref="sleepHelper" pointcut-ref="sleepPointcut"/>
</aop:config>
<bean id="human" class="com.ghs.aop.Human"/>
下面是< aop:aspect>的实现方式:
//定义切面
public class SleepHelperAspect{
public void beforeSleep(){
System.out.println("睡觉前要脱衣服!");
}
public void afterSleep(){
System.out.println("起床后要穿衣服!");
}
}
//aop配置
<bean id="sleepHelperAspect" class="com.ghs.aop.SleepHelperAspect"></bean>
<aop:config>
<aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/>
<aop:aspect ref="sleepHelperAspect">
<!--前置通知-->
<aop:before method="beforeSleep" pointcut-ref="sleepPointcut"/>
<!--后置通知-->
<aop:after method="afterSleep" pointcut-ref="sleepPointcut"/>
</aop:aspect>
</aop:config>
<bean id="human" class="com.ghs.aop.Human"/>
2、使用场景不同
< aop:advisor>大多用于事务管理。
例如:
<!-- 会重复读,不会脏读事务 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" timeout="120" propagation="REQUIRED" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:pointcut id="txPointCut" expression="..."/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
</aop:config>
< aop:aspect>大多用于日志,缓存
其实,不管是< aop:advisor>还是< aop:aspect>最终的实现逻辑是一样的。
小结:
可以看出,< aop:advisor>和< aop:aspect>其实都是将通知和切面进行了封装,原理基本上是一样的,只是使用的方式不同而已。
参考文章:
https://blog.csdn.net/u011983531/article/details/70504281
https://www.cnblogs.com/qinglangyijiu/p/8430144.html