欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《架构探险》之面向切面编程(AOP)(上)

程序员文章站 2022-06-13 21:44:06
...

写代码应该是一个由繁到简,然后由简到繁的一个螺旋上升的过程。

 

        在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的中切面(待续~)