《架构探险》之面向切面编程(AOP)(上)
写代码应该是一个由繁到简,然后由简到繁的一个螺旋上升的过程。
在Spring中有个很重要的特性那就是面向切面编程(AOP)。假想这样的一个情景,如果有一段逻辑很多方法执行前或执行后都需要,我们会怎么办?我们试着从一个极端走到另一个极端来考虑这个问题。从一个极端出发,如果需要这段逻辑的方法个数很少只有一个,我们可以直接在方面的最前面或最后面调用这段逻辑,怎么简单怎么来,像这样:
public void function(){ commonBegin(); ... commonEnd(); }
当这样的方法从一个变成两三个的时候,我们就看到了两三个类似的方法,然后当方法数变得特别多的时候,我们就会看到一堆这样的方法,当不只有一个Begin或End,而是还包含其他的Begin和End时,随着代码的不断增多,代码看起来估计就像套马杆的汉子般威武雄壮了...
那怎样才能把这样的问题搞的简单点呢?找代理~
1、静态代理:
首先我们可以尝试一下找个静态代理,静态代理就是谁是谁的代理都已经很明显了,一对一的服务,像这个样子(举个例子,你的一序列的方法都属于一些顾客的行为):
public class Proxy implements Cliemt{ private Client client; //Client只是其中的一个顾客类 public Proxy(Client client){ this.client = client; } public void buy(){ doSomething(); client.buy(); //顾客的工作就是买买买 } }
这样的话,顾客方法里面就不需要写那些前置或者后置的逻辑,代理里面来实现这部分就可以了,保证了顾客清清白白,然而,然而,这样不就凭空多了跟顾客类一样多的代理类了吗,代码不仅没有减少,反而翻番了。
2、JDK动态代理:
静态代理不行,那就找动态代理。动态代理会根据你的类生产对应的代理类,首先看看JDK的动态代理的实现机制。在静态代理中,有多少类需要实现同一个共同逻辑就需要对应多少个静态代理类,如果代理类中的代理对象类型没有指定的话,即前面没有指定ClientImpl,那么可以抽象出一个代理的调用控制器,在控制器中通过反射机制来调用具体对象的方法:
public class DynamicInvocationHandler implements InvocationHandler{ private Object object; public DynamicInvocationHandler (Object object){ this.object = object; } public Object invoke(Object proxy, Method method, Object... params){ return method.invoke(object, params); // try } }
然后我们可以通过Java中的Proxy根据我们的调用控制器来动态生成我们的代理:
Client client= new ClientImpl(); DynamicInvocationHandler handler = new DynamicInvocationHandler (client); Client clientProxy = (Client ) Proxy.newInstance(client.getClass().getClassLoader(), client .getClass().getInterfaces(), handler);
3、CGLIB动态代理:
JDK动态代理需要类实现相应的接口,如果是针对没有接口的类,可以使用CGlib来实现,实现方式大概是这个样子:
public class CGLibInterceptor implements MethodInterceptor{ public Object intercept(Object object, Method method, Object... params, MethodProxy proxy){ return proxy.invokeSuper(object, params); // try } }
然后可以通过Enhance的create方法创建代理对象:
CGLibInterceptor cglibInterceptor = new CGLibInterceptor(); Hello helloProxy = (Hello)Enhancer.create(Hello.class, cglibInterceptor); helloProxy.say("````");
有了动态代理之后,当我们对某个类的方法前或之后调用特定的逻辑时,就可以创建一个动态的代理对象出来,特定的逻辑放在InvocationHandler或MethodInterceptor中,可以把这两个类看成是动态代理的中介,有了这个中介之后,不管什么类都可以根据需要创建出对应的动态代理,省去了编写一堆静态代理的麻烦,而这个中介中的特定逻辑其实就是AOP的中切面(待续~)