在Spring中aop是一个重要的特性。和Hibernate结合的事务控制使用的就是aop,下面看如何使用。
首先定义一个增强(即通知),这是在被代理的方法执行前或执行后先执行增强中的代码再去执行被代理的方法。增强包括前置增强、后置增强、环绕增强、异常抛出增强和引介增强。
下面看一个前置增强
package com.maxjay.bank.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* 日志记录 前置增强
*
* @author Administrator
*
*/
public class LoggerBeforeAdvice implements MethodBeforeAdvice {
/**
* 当被代理对象的方法执行前,此方法被执行
*
* @param method
* 目标类方法
* @param args
* 方法的参数
* @param obj
* 目标类实例
*/
public void before(Method method, Object[] args, Object obj)
throws Throwable {
// if (method.getName().indexOf("validateUser") != -1) { // 由advisor(切面)来定义对那些方法进行拦截
System.out.println("日志记录开始,将要运行的方法为"
+ obj.getClass().getSimpleName() + "." + method.getName());
// }
}
}
在applicationContext-aop.xml中定义这个增强
<!-- 使用AOP进行日志记录,定义增强 -->
<bean id="loggerBeforeAdvice" class="com.maxjay.bank.advice.LoggerBeforeAdvice" />
使用ProxyFactoryBean配置,让spring来产生这个增强后的代理bean
<!--
配置单个bean的代理,在使用时不能用原有bean的id要用AppContext.get("singleLoginProxy")从context中获取(见测试类LoggerAdviceTest)
-->
<bean id="singleLoginProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.maxjay.bank.service.UserService</value>
</property>
<property name="interceptorNames">
<list>
<value>loggerBeforeAdvice</value>
</list>
</property>
<property name="target">
<ref bean="userService" />
</property>
<!-- 设置是否直接代理类(默认为false):true即使用cglib生成代理类,此时target对象不可以JDK动态代理过的bean;false则使用JDK动态代理 -->
<property name="proxyTargetClass">
<value>true</value>
</property>
</bean>
上面这段代码中的userService是普通的service类,它实现了UserService接口。这段配置就是要产生userService的代理类,而且采用的是cglib代理的方式,因此这个userService不能是JDK已经动态代理过的bean。由于我配置的这个userService已经加上了事务控制的aop增强,而且一般情况下声明式事务产生的是jdk动态代理的bean,因此会报一个无法代理的异常。如果要使用这个userService,就必须在声明事务的地方设置属性optimize为true,意思是强制使用cglib生成其代理的bean。具体配置如下:
<!-- 事务代理 -->
<bean id="baseTransaction" lazy-init="true" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="modify*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="create*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="read*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
<!-- 设置强制使用CGLIB生成代理 -->
<property name="optimize" value="true" />
</bean>
userService的配置如下:
<bean id="userService" parent="baseTransaction">
<property name="target">
<bean
class="com.maxjay.bank.service.impl.UserServiceImpl">
<property name="userDao">
<ref bean="userDao" />
</property>
</bean>
</property>
</bean>
测试类:
package test.com.maxjay.bank.advice;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import com.maxjay.bank.service.UserService;
public class LoggerAdviceTest {
public static void main(String[] args) {
String[] paths = { "web/WEB-INF/applicationContext.xml",
"web/WEB-INF/applicationContext-dao.xml",
"web/WEB-INF/applicationContext-service.xml",
"web/WEB-INF/applicationContext-aop.xml" };
ApplicationContext ctx = new FileSystemXmlApplicationContext(paths);
UserService service = (UserService) ctx.getBean("singleLoginProxy");
service.validateUser("zxm", "zxm");
//service.getAllUsers();
}
}
此时控制台会打印:
日志记录开始,将要运行的方法为UserServiceImpl$$EnhancerByCGLIB$$3b846ea.validateUser
可以看出在调用UserService的方法时已经加入了我们想要增加的日志记录方法,到此可以学会增强的配置方法了...