Spring 2.x AOP声明式配置
package aop.test;
public class People{
public String SayHello(String str){
System.out.println(this.getClass().getName()+ "说:"+str);
return str;
}
}
创建含有main()方法的测试类TestMain,从Spring IoC容器中获取Peoples对象,并调用其SayHello()方法,
代码如下:
package aop.test;
// import省略
public class TestMain {
public static void main(String[] args) {
// 实例化Spring IoC容器
ApplicationContext ac = new ClassPathXmlApplicationContext(
"applicationContext.xml");
// 获取受管Bean的实例
People p = (People) ac.getBean("TestBean");
p.SayHello("传入的参数值");
}
}
创建MyAspect类,添加一个beforeAdvice()方法作为前置通知方法,
代码如下:
package aop.test;
import org.aspectj.lang.JoinPoint;
public class MyAspect {
public void beforeAdvice(JoinPoint point) {
System.out.println("前置通知被触发:" + point.getTarget().getClass().getName()+ "将要" + point.getSignature().getName());
}
}
修改xml配置文件,为其添加aop命名空间,并把MyAspect注册为一个受管Bean,作为我们下面定义切面的backing bean。
代码如下:
<?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-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="MyAspect" class="aop.test.MyAspect" />
<bean id="TestBean" class="aop.test.People" />
<aop:config proxy-target-class="true">
<aop:aspect ref="MyAspect" order="0" id="Test">
<aop:pointcut id="testPointcut"
expression="execution(* aop..*(..))" />
<aop:before pointcut-ref="testPointcut"
method="beforeAdvice" />
</aop:aspect>
</aop:config>
</beans>
即可.
实例分析AOP声明式配置:
在基于AOP命名空间的Spring AOP中,要声明一个切面,需要使用<aop:config/>的子标签<aop:aspect>。<aop: aspect>标签有一个ref属性必须被赋值,它用于指定和该切面关联的受管Bean.正如上例所示, MyAspect该Bean对应的java类是一个普通的java类,在该类中定义了切面的通知方法。此外,<aop:aspect>标签还有两个可选的order属性和id属性,order属性用于指定该切面的加载顺序,id属性用于标识该切面。
要声明一个切入点,可以使用<aop:aspect>的子标签<aop:pointcut>,在Spring2.5中它有两个属性id和expression,分别用于标示该切入点和设定该切入点表达式。如上例.
和@AspectJ一样,基于AOP命名空间的配置也可以定义五种通知类型,并且使用方式和特性类似。与@AspectJ不同的是,配置信息从Annotation中转移到了xml配置文件。
声明一个前置通知可以使用<aop:aspect>的子标签<aop:before/>。该标签的属性说明如下表:
<aop:aspect ref="MyAspect" order="0" id="Test">
<aop:pointcut id="testPointcut"
expression="execution(* aop.test.TestBean.*(..))"/>
<aop:before pointcut-ref="testPointcut" method="beforeAdvice"/>
</aop:aspect>
声明一个后置通知使用<aop:after/>标签,它的属性等和<aop:before/>标签类似,下面是范例:
<aop:aspect ref="MyAspect" order="0" id="Test">
<aop:pointcut id="testPointcut"
expression="execution(* aop.test.TestBean.*(..))" />
<aop:after pointcut-ref="testPointcut" method="AfterAdvice"/>
</aop:aspect>
3)、 返回后通知
<aop:after-returning/>标签可以声明一个返回后通知,该标签的属性和<aop:before/>相比它多了一个returning属性。该属性的意义类似于@AfterReturning注解的returning属性,用于将链接点的返回值传给通知方法。用法如下:
<aop:aspect ref="MyAspect" order="0" id="Test">
<aop:pointcut id="testPointcut"
expression="execution(* aop.test.TestBean.*(..))" />
<aop:after-returning pointcut-ref="testPointcut"
method="AfterReturnAdvice" returning="reVlue" />
</aop:aspect>
4)、 异常通知
声明一个异常通知使用<aop:after-throwing />标签,它有一个类似于throwing属性又来指定该通知匹配的异常类型。用法如下:
<aop:aspect ref="MyAspect" order="0" id="Test">
<aop:pointcut id="testPointcut"
expression="execution(* aop.test.TestBean.*(..))" />
<aop:after-throwing pointcut-ref="testPointcut"
method="afterThrowingAdvice" throwing="throwable" />
</aop:aspect>
5)、 环绕通知
环绕通知是所有通知中功能最强大的通知,用<aop:around/>标签来声明。用法如下:
<aop:aspect ref="MyAspect" order="0" id="Test">
<aop:pointcut id="testPointcut"
expression="execution(* aop.test.TestBean.*(..))" />
<aop:around pointcut-ref="testPointcut" method="aroundAdvice"/>
</aop:aspect>
Spring 2.x AOP声明式事务配置
execution组合表达式表述数据库事务切点:
大部分service类的方法使用数据源txManager-datasourceone,对应事物切点txPointcut-datasourceone,事物拦截器txAdvice-datasourceone;
service层PublishService类的几个方法使用数据源txManager-datasourcetwo,对应事物切点txPointcut-datasourcetwo,事物拦截器txAdvice-datasourcetwo;
一个自定义方法拦截器RuntimeLogInterceptor(拦截每个方法,并记录每个方法的执行日志),拦截切点runtimeLogInterceptorPoint;
<!-- 数据源1事务管理器 -->
<bean id="txManager-datasourceone" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="DataSource"/>
</bean>
<!-- 数据源2事务管理器 -->
<bean id="txManager-datasourcetwo" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="srcDataSource"/>
</bean>
<!-- 数据源1事务拦截器 -->
<tx:advice id="txAdvice-datasourceone" transaction-manager="txManager-datasourceone" >
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 数据源2事务拦截器 -->
<tx:advice id="txAdvice-datasourcetwo" transaction-manager="txManager-datasourcetwo" >
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- aop配置 强制使用cglib代理 -->
<aop:config proxy-target-class="true">
<!-- datasourceone 数据库事务管理切点
包含的方法:service包(或子包)下所有名字以 'Service' 结尾的类内所有的方法。
不包含的方法:x.y.service包下PublishService类的getResCategory(..)方法,
getEditorResList(..)方法,updateResbackrmd(..)方法
-->
<aop:pointcut id="txPointcut-datasourceone"
expression="execution(* x.y.service..*Service.*(..))
and !execution(* x.y.service.PublishService.getResCategory(..))
and !execution(* x.y.service.PublishService.getEditorResList(..))
and !execution(* x.y.service.PublishService.updateResbackrmd(..))"/>
<!-- datasourcetwo 数据库事务管理切点
包含的方法:x.y.service包PublishService类的getResCategory(..)方法,
getEditorResList(..)方法,updateResbackrmd(..)方法。
-->
<aop:pointcut id="txPointcut-datasourcetwo"
expression="execution(* x.y.service.PublishService.getResCategory(..))
or execution(* x.y.service.PublishService.getEditorResList(..))
or execution(* x.y.service.PublishService.updateResbackrmd(..))"/>
<!-- 运行日志拦截点
包含的方法:service包(或子包)下所有名字以 'Service' 结尾的类内所有的方法。
不包含的方法:x.y.service包RuntimeLogService类createRuntimeLogBeforeRequest(..)方法,
getRuntimeLog(..)方法,setRuntimeLog(..)方法,completeRuntimeLogAfterRequest(..)方法。
-->
<aop:pointcut id="runtimeLogInterceptorPoint"
expression="execution(* x.y.service..*Service.*(..))
and !execution(* x.y.service.RuntimeLogService.createRuntimeLogBeforeRequest(..))
and !execution(* x.y.service.RuntimeLogService.getRuntimeLog(..))
and !execution(* x.y.service.RuntimeLogService.setRuntimeLog(..))
and !execution(* x.y.service.RuntimeLogService.completeRuntimeLogAfterRequest(..))"/>
<!-- 运行日志拦截 -->
<aop:advisor advice-ref="RuntimeLogInterceptor" pointcut-ref="runtimeLogInterceptorPoint"/>
<!-- datasourceone,datasourcetwo数据库事务拦截 -->
<aop:advisor advice-ref="txAdvice-datasourceone" pointcut-ref="txPointcut-datasourceone"/>
<aop:advisor advice-ref="txAdvice-datasourcetwo" pointcut-ref="txPointcut-datasourcetwo"/>
</aop:config>
--------------------------------------------------------------------------------
2,常见的情况:
第一种情况:x.y.service..*Service.*(..)
x.y.service:表示包“x.y.service”
x.y.service.. :表示包“x.y.service”及其子包例如:“x.y.service.abc”,“x.y.service.def”,“x.y.service.ghi”,“x.y.service.jkl”。。。
*Service:定义接口(或没有实现接口的类,需要使用cglib代理)表达式;所有以Service结尾的类或接口,注意不是所有以Service结尾的包名。
*(..) :定义方法名,方法参数表达式;任意方法的名称,任意方法参数。
第二种情况:com.xyz.service.*.*(..)
com.xyz.service:定义 包“com.xyz.service”
*.*(..):定义任意接口(或没有实现接口的类,需要使用cglib代理),任意方法,任意参数在service包下定义的任意方法的执行。
第三种情况:com.xyz.service..*.*(..)
com.xyz.service:定义 包“com.xyz.service”
com.xyz.service.. :定义包“com.xyz.service”及其子包
*.*(..):定义任意接口(或没有实现接口的类,需要使用cglib代理),任意方法,任意参数.
本文详细介绍了基于Spring框架的声明式AOP配置方法,包括如何声明切面、切入点、通知类型(前置、后置、返回后、异常、环绕通知),以及如何配置事务管理器和事务拦截器。并通过实例展示了如何在实际应用中应用这些配置。
316

被折叠的 条评论
为什么被折叠?



