您的位置:首页 > 编程语言 > Java开发

Spring AOP 测试

2014-04-28 00:00 85 查看
动态代理测试

JDK 1.7

public interface CgTestInterface {

public void print();

public void print1();

// public void print2();

}

public class CgTest implements CgTestInterface {

public void print() {

System.out.println(getClass().getName() + " print: hello world");

print1();

print2();

}

public void print1() {

System.out.println(getClass().getName() + " print1: hello world");

}

private void print2() {

System.out.println(getClass().getName() + " print2: hello world");

}

}

public class PerformanceMonitor {

static long begTime;

public static void begin() {

System.out.println("begins...");

begTime = System.currentTimeMillis();

}

public static void end(String strName) {

System.out.println(strName + " : " + (System.currentTimeMillis() - begTime)+“ms”);

}

}

public class PerformanceHandler implements InvocationHandler {

private Object target;

public PerformanceHandler(Object target) {

this.target = target;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

// TODO Auto-generated method stub

PerformanceMonitor.begin();

System.out.println(proxy.getClass().getName());

Object obj = method.invoke(target, args);

PerformanceMonitor.end(method.getName());

return obj;

}

}

public class TestMain {

public static void main(String[] args) {

CgTestInterface cg = new CgTest();

PerformanceHandler handler = new PerformanceHandler(cg);

CgTestInterface proxy1 = (CgTestInterface)Proxy.newProxyInstance(cg.getClass().getClassLoader(), cg.getClass().getInterfaces(), handler);

System.out.println(proxy1.getClass().getName());

proxy1.print();

}

}

测试结果:

com.sun.proxy.$Proxy0

begins...

com.sun.proxy.$Proxy0

com.cglib.CgTest print: hello world

com.cglib.CgTest print1: hello world

com.cglib.CgTest print2: hello world

print : 0ms

基于JDK的动态代理生成了一个接口实现类。当调用print时,实际调用的是该代理类的print方法,在PerformanceHandler中为该方法实现了增强,所以实际调用的序列是:

PerformanceMonitor.begin();

Object obj = method.invoke(target, args);

PerformanceMonitor.end(method.getName());

而通过method.invoke调用了CgTest的print方法。所以增强的代码不会直接作用于CgTest中的方法,故print1还是按CgTest中的代码执行。

虽然通过proxy1执行,但实际是用CgTest实例进行的调用;

通过CGLib实现AOP

public class CglibProxy implements MethodInterceptor {

private Enhancer enhancer = new Enhancer();

public Object getProxy(Class cla) {

enhancer.setSuperclass(cla);

enhancer.setCallback(this);

return enhancer.create();

}

@Override

public Object intercept(Object arg0, Method arg1, Object[] arg2,

MethodProxy arg3) throws Throwable {

// TODO Auto-generated method stub

PerformanceMonitor.begin();

Object result = arg3.invokeSuper(arg0, arg2);

System.out.println(arg0.getClass().getName());

PerformanceMonitor.end(arg1.getName());

return result;

}

}

public class TestMain {

public static void main(String[] args) {

// TODO Auto-generated method stub

CglibProxy proxy = new CglibProxy();

CgTest test = (CgTest)proxy.getProxy(CgTest.class);

System.out.println(test.getClass().getName());

test.print();

}

}

测试结果:

com.cglib.CgTest$$EnhancerByCGLIB$$4d4122d

begins...

com.cglib.CgTest$$EnhancerByCGLIB$$4d4122d

com.cglib.CgTest$$EnhancerByCGLIB$$4d4122d print: hello world

begins...

com.cglib.CgTest$$EnhancerByCGLIB$$4d4122d

com.cglib.CgTest$$EnhancerByCGLIB$$4d4122d print1: hello world

print1 : 0ms

com.cglib.CgTest$$EnhancerByCGLIB$$4d4122d print2: hello world

print : 1ms

结果发现print及其内部调用的print1方法都被添加了增强功能代码。从CgTest派生了一个子类,重写了所有方法,所有的调用都是在子类方法之间进行。

在CgTest对print方法做如下改动:

public void print() {

System.out.println(this.getClass().getName() + " print: hello world");

try {

CgTest.class.getMethod("print1").invoke(this);

} catch (IllegalAccessException | IllegalArgumentException

| InvocationTargetException | NoSuchMethodException

| SecurityException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

//print1();

//print2();

}

执行的结果进一步证明了这点:

com.cglib.CgTest$$EnhancerByCGLIB$$c6c06c4

begins...

com.cglib.CgTest$$EnhancerByCGLIB$$c6c06c4

com.cglib.CgTest$$EnhancerByCGLIB$$c6c06c4 print: hello world

begins...

com.cglib.CgTest$$EnhancerByCGLIB$$c6c06c4

com.cglib.CgTest$$EnhancerByCGLIB$$c6c06c4 print1: hello world

print1 : 0ms

print : 0ms

如果将CgTest改为final,则运行时抛出异常。

当然,CGLib也可以与JDK一样,对接口进行代理,得到的结果与JDK一样。

但是在spring的aop中,虽然是基于jdk或者CGLib实现,但是经过测试,五种增强方式的调用都是发生在被代理类内部,方法调用方法不会带来多重增强,这个不知道为啥,暂留后来研究。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: