继续Spring AOP的学习,总所周知,aop的魅力所在就是它能在方法前后起拦截作用,以便我们定义横切逻辑代码。增强大致分为5类:前置增强(就是在目标方法调用前拦截),后置增强(就是在目标方法调用之后拦截),异常增强(就是在目标方法抛出后拦截),引介增强(它是一种特殊的增强,可以在目标类添加属性和方法,通过拦截定义一个接口,让目标代理实现这个接口,它的连接点是类级别的),而前面三种增强则是方法级别的。以上四种增强接口是Spring定义的,还有只用环绕增强(目标方法前后拦截)是AOP联盟定义的接口。其实aop增强很简单,通过实现这些增强接口,在实现这些接口的方法中定义横切逻辑,然后通过配置spring配置文件,就可以完成将增强织入到目标方法中了。
首先,以前置增强为例,大家都知道如果我们到餐厅去,服务员首先会欢迎顾客,然后再为我们提供服务。这里我们一个
Waiter类:
package com.me.services;
public interface Waiter {
void greetTo(String name);
void serveTo(String name);
}
现在我们来看一个训练不足的服务生的服务情况:
package com.me.services.imp;
import com.me.services.Waiter;
public class LuceyWaiter implements Waiter {
public void greetTo(String name) {
System.out.println("greet to "+name);
}
public void serveTo(String name) {
System.out.println("server "+name);
}
}
Lucey走到闷不做声走到顾客面前, 提供服务,那么,我们就需要对每个服务生进行规范,在服务之前要行礼貌用语。
package com.me.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object obj)
throws Throwable {
String clientName = args[0].toString();
System.out.println("How are you,"+clientName+"!");
}
}
这里我们就用到了前置增强,通过实现org.springframework.aop.MethodBeforeAdvice接口的before方法定义逻辑代码。before中的三个参数分别代表:目标方法,目标方法的参数列表,目标实例。
目标对象也有了,增强也有了,接下来如何把增强织入的目标对象生成代理呢?上一次博客写到spring的代理机制,我们知道可以通过JDK和CGLib两种方式动态创建代理。但是那样我们代码太过麻烦,要自定义一个类实现指定接口,那有没有简单的方法呢?当然,spring为我们提供了ProxyFactoryBean,它帮我们完成了上面通过JDK,CGLib创建代理那些复杂的工作,我们只需要在spring中配置一下即可完成织入工作,^-^
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <!-- 需要代理的业务类 --> <bean id="target" class="com.me.services.imp.LuceyWaiter"></bean> <!-- 指定增强,一个业务类可以有多个增强形成增强链,调用顺序与添加顺序一致 --> <bean id="greetAdvice" class="com.me.advice.GreetingBeforeAdvice"></bean> <!-- 利用ProxyFactoryBean创建代理 --> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 代理要实现的接口,可以是多个接口 --> <property name="proxyInterfaces" value="com.me.services.Waiter"/> <property name="target" ref="target"/> <!-- 需要织入目标对象的0增强数组 --> <property name="interceptorNames"> <list> <value>greetAdvice</value> </list> </property> </bean> </beans>
关于ProxyFactoryBean的工作原理将在以后写到,但需要进一步了解它的几个常用配置属性,除上面的属性外,还有singleton:返回代理是否为单实例,默认true.
optimize:当设置为true时,强制使用CGLib代理。对于单实例推荐配置true,但对于作用域类型的代理推荐false.
proxyTargetClass:是否对类代理(不是对接口进行代理),设置为true使用CGLib代理。当然如果设置为true就不必设置proxyInterfaces属性了,及时设置了也将被忽略。下面来一段测试代码吧:
package com.me.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.me.services.Waiter;
public class TestBeforeAdvice {
public static void main(String[] args) {
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
Waiter waiter = (Waiter)cxt.getBean("waiter");
waiter.greetTo("John");
}
}
后置增强,异常抛出增强和环绕增强用法差不多,只是实现的接口不一样罢了。下面就做说明了,我将测试代码上传供大家学习。接下来,来谈谈我们类级别的增强,即引介增强,我们还是根据上一篇博客代理机制的示例来学习引介增强。我们前面用到监测用户添加和删除性能,现在将起改为可控的。即维护人员可控制是否采用性能监控。
首先定义一个用于标志目标类是否支持性能监控的接口:
package com.me.advice;
public interface Monitorable {
/**
* @param IsActive
* true:性能监控功能激活
* false: 性能监控功能关闭
*/
public void setMonitorActive(boolean IsActive);
}
通过继承DelegatingIntroductionInterceptor为目标类引入性能监控功能,代码如下:
package com.me.util;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
@SuppressWarnings("serial")
public class ControllablePerformanceMonitor extends
DelegatingIntroductionInterceptor implements Monitorable {
//为了解决线程安全问题
private ThreadLocal<Boolean> statusMap = new ThreadLocal<Boolean>();
public void setMonitorActive(boolean IsActive) {
statusMap.set(new Boolean(IsActive));
}
public Object invoke(MethodInvocation mi)throws Throwable{
Object obj = null;
if(statusMap.get()!=null && statusMap.get().booleanValue()){
PerformanceMonitor pm = new PerformanceMonitor();
pm.start(mi.getClass().getName()+"."+mi.getMethod().getName());
obj = super.invoke(mi);
pm.end();
}else{
obj = super.invoke(mi);
}
return obj;
}
}
配置引介增强
<bean id="target" class="com.me.services.imp.UserServiceImp"/> <bean id="pmonitor" class="com.me.util.ControllablePerformanceMonitor"/> <!-- 创建代理 --> <bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 引介增强所实现的接口 --> <property name="interfaces"> <value>com.me.util.Monitorable</value> </property> <property name="target" ref="target"/> <property name="interceptorNames"> <idref local="pmonitor"/> </property> <!-- 由于引介增强通过子类创建代理,所以强制使用CGLib代理实现机制 --> <property name="proxyTargetClass" value="true"/> </bean>
测试引介增强
package com.me.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.me.services.UserService;
import com.me.entity.*;
import com.me.util.Monitorable;
public class TestCotrollerPerformance {
/**
* @param args
*/
public static void main(String[] args) {
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = (UserService)cxt.getBean("userService");
service.deleteUser(1);
service.insertUser(new User());
//这里强制成果,说明返回的代理引入了Monitorable接口
Monitorable monitor = (Monitorable)service;
monitor.setMonitorActive(true);
service.deleteUser(1);
service.insertUser(new User());
}
}
本文介绍了Spring AOP的五种增强类型:前置、后置、异常、引介和环绕增强,并通过具体示例展示了如何使用Spring配置文件进行前置增强及引介增强的实现。

998

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



