本文依然参考夏昕的Spring开发指南(下载自满江红)。
这里,我想先说下“满江红开源”(http://wiki.redsaga.com/)。这是我见识过国内最好的开源组织。满江红的页面非常简洁,但是提供的东西都是非常实用的。在主页下端还提供了到JavaEye的连接。因为本身我觉着JavaEye就是一个很好的社区,所以进一步说明满江红是一个很不错的组织。
转入正题,昨天写了关于Java动态代理的东东,但是从实现过程来看,稍显复杂。从原始类得到代理类的过程,很容易让人迷惑。使用Spring的AOP可以很简单的实现动态代理,并且得到代理对象的过程完全由Spring完成,我们做的只是写xml配置。还有另外一点,就是如果使用JDK的动态代理,那么被代理类必须实现接口。但是Spring的AOP没有这样的限制,它的代理实现有两种方式,JDK的动态代理和CGLIB(在后面的文章中有介绍)。下面是个Spring的AOP的例子,有JDK的动态代理和CGLIB两个版本,用AOP记录函数的执行时间。
首先是JDK动态代理版本。
接口test.quqtalk.spring.aop. ITest :
package test.quqtalk.spring.aop;
public interface ITest {
public abstract void doTest();
public abstract void executeTest();
}
接口的实现类:
package test.quqtalk.spring.aop;
public class Test implements ITest {
public void doTest() {
for (int i = 0; i < 10000; i++) {
}
}
public void executeTest() {
for (int i = 0; i < 25000; i++) {
}
}
}
AOP的逻辑处理类:
package test.quqtalk.spring.aop;
import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MethodTimeCostInterceptor implements MethodInterceptor,
Serializable {
/**
*
*/
private static final long serialVersionUID = 5916297666638680535L;
protected static final Log logger = LogFactory
.getLog(MethodTimeCostInterceptor.class);
public Object invoke(MethodInvocation invocation) throws Throwable {
long time = System.currentTimeMillis();
Object rval = invocation.proceed();
time = System.currentTimeMillis() - time;
System.out.println("Method Cost Time => " + time + " ms");
return rval;
}
}
Spring配置文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> <bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="MyInterceptor"/> </property> <property name="patterns"> <list> <value>.*do.*</value> <value>.*execute.*</value> </list> </property> </bean> <bean id="MyInterceptor" class="test.quqtalk.spring.aop.MethodTimeCostInterceptor"/> <bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>test.quqtalk.spring.aop.ITest</value> </property> <property name="target"> <ref local="test"/> </property> <property name="interceptorNames"> <value>myPointcutAdvisor</value> </property> </bean> <bean id="test" class="test.quqtalk.spring.aop.Test"/> </beans>
测试类:
package test.quqtalk.spring.aop;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
"test/quqtalk/spring/aop/app.xml");
//这里强制转换成ITest
ITest test = (ITest) ctx.getBean("myAOPProxy");
test.doTest();
test.executeTest();
}
}
然后,是CGLIB版本。
被代理类test.quqtalk.spring.aop.Test,注意这里没有实现任何接口:
package test.quqtalk.spring.aop;
public class Test{
public void doTest() {
for (int i = 0; i < 10000; i++) {
}
}
public void executeTest() {
for (int i = 0; i < 25000; i++) {
}
}
}
处理逻辑跟JDK动态代理版本相同:
package test.quqtalk.spring.aop;
import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MethodTimeCostInterceptor implements MethodInterceptor,
Serializable {
/**
*
*/
private static final long serialVersionUID = 5916297666638680535L;
protected static final Log logger = LogFactory
.getLog(MethodTimeCostInterceptor.class);
public Object invoke(MethodInvocation invocation) throws Throwable {
long time = System.currentTimeMillis();
Object rval = invocation.proceed();
time = System.currentTimeMillis() - time;
System.out.println("Method Cost Time => " + time + " ms");
return rval;
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> <bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="MyInterceptor"/> </property> <property name="patterns"> <list> <value>.*do.*</value> <value>.*execute.*</value> </list> </property> </bean> <bean id="MyInterceptor" class="test.quqtalk.spring.aop.MethodTimeCostInterceptor"/> <bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyTargetClass"> <value>true</value> </property> <property name="target"> <ref local="test"/> </property> <property name="interceptorNames"> <value>myPointcutAdvisor</value> </property> </bean> <bean id="test" class="test.quqtalk.spring.aop.Test"/> </beans>
测试程序:
package test.quqtalk.spring.aop;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
"test/quqtalk/spring/aop/app.xml");
//这里强制转换成Test
Test test = (Test) ctx.getBean("myAOPProxy");
test.doTest();
test.executeTest();
}
}
运行后控制台都会打出:
Method Cost Time => 0 ms
Method Cost Time => 0 ms