Spring AOP的核心是Cglib和JDK的动态代理,那我们先写Spring AOP的前置增强和后置增强
示例代码链接
第一次尝试
我们对Greeting类进行前置和后置增强
public class Greeting {
public void greet(String name){
System.out.println("Hello,"+name);
}
}
先写一个前置增强
public class BeforeProxy implements MethodInterceptor {
public T getProxy(Class clazz) {
return (T) Enhancer.create(clazz, this);
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object result=methodProxy.invokeSuper(o,objects);
return result;
}
private void before() {
System.out.println("call before");
}
}
再写一个后置增强
public class AfterProxy implements MethodInterceptor {
public T getProxy(Class clazz) {
return (T) Enhancer.create(clazz, this);
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result=methodProxy.invokeSuper(o,objects);
after();
return result;
}
private void after() {
System.out.println("call after");
}
}
应该就是这样写吧?先用 BeforeProxy 去增强 Greeting,得到一个代理对象beforeGreeting。然后再用 AfterProxy 去增强上一步得到的代理对象,得到一个新的代理对象 beforeAfterGreeting。最后将这个新的代理对象强制转型为目标类对象,并调用目标类对象的 greet() 方法。我们通过Client输出一下。
public class Client {
public static void main(String args[]) {
Greeting beforeGreeting= new BeforeProxy().getProxy(Greeting.class);
Greeting beforeAfterGreeting=new AfterProxy().getProxy(beforeGreeting.getClass());
beforeAfterGreeting.greet("gethin");
}
}
运行时报错!而且抛出了一个 net.sf.cglib.core.CodeGenerationException,可见这是 CGLib 的内部异常。遇到这种异常,一般都是很让人抓狂。看来 CGLib 自动生成的类,不能被自己再次增强了。如何解决呢?不妨借鉴 Servlet 的 Filter Chain的设计模式,它是“责任链模式”的一种变体,在 JavaEE 设计模式中命名为“拦截过滤器模式”。我们可以将每个 Proxy 用一根链子串起来,形成一个 Proxy Chain。然后调用这个 Proxy Chain,让它去依次调用 Chain 中的每个 Proxy。
第二次尝试
我们通过责任链模式,重新设计一下。
定义一个Proxy
public interface Proxy {
Object doProxy(ProxyChain proxyChain);
}
编写代理链
public class ProxyChain {
private Object targetObject;
private MethodProxy methodProxy;
private Object[] params;
private Method method;
List proxyList;
private int currentIndex=0;
public ProxyChain(Object targetObject, MethodProxy methodProxy, Object[] params, Method method, List proxyList) {
this.targetObject = targetObject;
this.methodProxy = methodProxy;
this.params = params;
this.method = method;
this.proxyList = proxyList;
}
public Object doProxyChain() throws Throwable {
Object result;
if(currentIndex getProxyList() {
return proxyList;
}
}
编写代理工厂类
public class ProxyFactory {
public static T createProxy(Class tClass, final List proxyList){
return (T) Enhancer.create(tClass, new MethodInterceptor() {
public Object intercept(Object targetObject, Method originMethod, Object[] params, MethodProxy methodProxy) throws Throwable {
return new ProxyChain(targetObject,methodProxy,params,originMethod,proxyList).doProxyChain();
}
});
}
}
我们的目标不是为了实现 Proxy,而是为了实现 AOP。为了实现 AOP,采用了“模板方法模式”,弄一个 AbstractProxy 抽象类,让它去实现 Proxy 接口,并在其中定义方法调用模板,在需要横向拦截的地方,定义一些“钩子方法”。Spring 源码中大量使用了这一技巧。
public abstract class AbstractProxy implements Proxy {
public Object doProxy(ProxyChain proxyChain) {
Object targetObject = proxyChain.getTargetObject();
Object[] params = proxyChain.getParams();
MethodProxy methodProxy = proxyChain.getMethodProxy();
Object result=null;
begin();
try {
before(targetObject, params, methodProxy);
result = proxyChain.doProxyChain();
after(targetObject, params, methodProxy);
} catch (Throwable throwable) {
error(targetObject, params, methodProxy);
}
end();
return result;
}
public void end() {
}
public void error(Object targetObject, Object[] params, MethodProxy methodProxy) {
}
public void after(Object targetObject, Object[] params, MethodProxy methodProxy) {
}
public void before(Object targetObject, Object[] params, MethodProxy methodProxy) {
}
public void begin() {
}
}
重新编写前置类
public class BeforeProxy extends AbstractProxy {
@Override
public void before(Object targetObject, Object[] params, MethodProxy methodProxy) {
System.out.println("call before");
}
}
重新编写后置类
public class AfterProxy extends AbstractProxy {
@Override
public void after(Object targetObject, Object[] params, MethodProxy methodProxy) {
System.out.println("call after");
}
}
Client
public class Client6 {
public static void main(String args[]) {
BeforeProxy beforeProxy = new BeforeProxy();
AfterProxy afterProxy = new AfterProxy();
List proxyList = new ArrayList();
proxyList.add(afterProxy);
proxyList.add(beforeProxy);
Student student = ProxyFactory.createProxy(Student.class, proxyList);
student.sayHello();
}
}
最终如愿输出结果