Spring的AOP实现
1.纯java实现,无需特殊的编译过程,不需要控制类加载层次
2.目前只支持方法执行连接点(通知Spring Bean的方法执行)
3.不是为了提供最完整的AOP实现(尽管它非常强大);而是侧重于提供一种AOP实现和Spring IoC容器之间的整合,用于帮助解决企业应用中的常见问题
4.Spring AOP不会与AspectJ竞争,从而提供综合全面的AOP解决方案
Spring所有的切面和通知器都必须放在一个<aop:config>内(可以配置包含多个<aop:config>元素),每一个<aop:config>可以包含pointcut , advisor 和 aspect元素
(它们必须按照这个顺序进行声明)
先来一个简单用例
1. 创建一个切面类
package aop.schema.advice;
public class MyAspect {
public void before()
{
System.out.println("MyAspect:before");
}
}
2. 创建一个需要进行AOP的业务类
package aop.schema.advice.biz;
public class AspectBiz {
public void biz()
{
System.out.println("AspectBiz:biz");
}
}
3. 在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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="myAspect" class="aop.schema.advice.MyAspect"></bean>
<bean id="aspectBiz" class="aop.schema.advice.biz.AspectBiz"></bean>
<aop:config>
<aop:aspect id="myAspectAOP" ref="myAspect">
<!--该表达式的意思是,切入点是 aop.schema.advice.biz.AspectBiz 类中的所有方法 -->
<aop:pointcut expression="execution(* aop.schema.advice.biz.AspectBiz.*(..))" id="myPiontcut"/>
<!--指定前置通知, method中的名称即是 myAspect中的方法名,pointcut-ref 指向某一个切入点 -->
<aop:before method="before" pointcut-ref="myPiontcut"/>
</aop:aspect>
</aop:config>
</beans>
4. 测试
package test.aop;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import annotation.BeanAnnotation;
import aop.schema.advice.biz.AspectBiz;
@RunWith(BlockJUnit4ClassRunner.class)
public class TestAopSchemaAdvice {
private ClassPathXmlApplicationContext context;
@Test
public void testBean(){
context = new ClassPathXmlApplicationContext("spring-aop-schema-advice.xml");
AspectBiz ab = (AspectBiz) context.getBean("aspectBiz");
ab.biz();
}
}
输出:
MyAspect:before
AspectBiz:biz
还可以指定 切入点方法执行完之后调用的通知 <aop:after-returning >
<?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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="myAspect" class="aop.schema.advice.MyAspect"></bean>
<bean id="aspectBiz" class="aop.schema.advice.biz.AspectBiz"></bean>
<aop:config>
<aop:aspect id="myAspectAOP" ref="myAspect">
<!--该表达式的意思是,切入点是 aop.schema.advice.biz.AspectBiz 类中的所有方法 -->
<aop:pointcut expression="execution(* aop.schema.advice.biz.AspectBiz.*(..))" id="myPiontcut"/>
<!--指定前置通知, method中的名称即是 myAspect中的方法名,pointcut-ref 指向某一个切入点 -->
<aop:before method="before" pointcut-ref="myPiontcut"/>
<!--指定在 切入点方法返回之后调用的通知 ,method中的名称即是 myAspect中的方法名 -->
<aop:after-returning method="afterReturning" pointcut-ref="myPiontcut"/>
</aop:aspect>
</aop:config>
</beans>
在切面类中加入 afterReturning方法
package aop.schema.advice;
public class MyAspect {
public void before()
{
System.out.println("MyAspect:before");
}
public void afterReturning()
{
System.out.println("MyAspect:afterReturning");
}
}
测试结果:
MyAspect:before
AspectBiz:biz
MyAspect:afterReturning
除了 after-returning 之外
1. 还可以指定抛出异常之后调用的通知 , 若抛出异常,则after-returning不会执行
<aop:after-throwing method="afterThrowing" pointcut-ref="myPiontcut"/>
当有异常抛出时 执行throwing ,但是由于是非正常结束,所以after-returning就是不会执行了,但是after 是不管你是否正常结束,都一定会执行。
<aop:after method="after" pointcut-ref="myPiontcut"/>
2. 指定环绕通知 ,注意 通知方法的第一个参数必须是ProceedingJoinPoint类型
例如:
<!--环绕通知 , 通知方法的第一个参数必须是 ProceedingJoinPoint类型 -->
<aop:around method="around" pointcut-ref="myPiontcut"/>
在myAspect定义 around方法
public Object around(ProceedingJoinPoint pjp)
{
Object obj =null;
try {
System.out.println("MyAspect: around 1");
obj = pjp.proceed();
System.out.println("MyAspect: around 2");
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
运行结果
MyAspect:before
MyAspect: around 1
AspectBiz:biz
MyAspect: around 2
MyAspect:after
MyAspect:afterReturning