springAOP之代理

AOP是指面向切面編程。編程

在學習AOP以前先來了解一下代理,由於傳說中的AOP其實也對代理的一種應用。框架

首先來看這樣一段代碼:maven

public interface Hello {
    void say(String name);
}

實現類:學習

public class HelloImpl implements Hello {

    public void say(String name) {
        System.out.println("Hello!"+name);
    }
}

若是如今須要在say調用的先後作一些操做,那最簡單的方法就是直接在say方面中增長代碼,但這樣確定不夠優雅。this

這時候能夠用第一種代理模式:靜態代理spa

public class HelloProxy implements Hello {

    private Hello hello;

    public HelloProxy(){

        hello=new HelloImpl();

    }

    public void say(String name) {
        before();
        hello.say(name);
        after();
    }

    private void before(){
        System.out.println("before");
    }

    private void after(){
        System.out.println("after");
    }
}

這樣咱們在保留原來HelloImple中say方法的同時,用HelloProxy代理在say方法的先後增長了before和after代理

調用一下試試:code

 public static void main(String[] args){
        Hello helloProxy=new HelloProxy();
        helloProxy.say("Gary");
}

運行結果:對象

那麼新的問題來了,若是每次都須要寫一個代理類不也很麻煩嗎,項目中就會有不少個xxxProxy,所以就出現了 JDK動態代理blog

代碼以下:

public class DynamicProxy implements InvocationHandler {

    private Object target;

    public DynamicProxy(Object target){
       this.target=target;
    }

    public <T> T getProxy(){
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result=method.invoke(target,args);
        after();
        return result;
    }

    private void before(){
        System.out.println("before");
    }

    private void after(){
        System.out.println("after");
    }
}

注:Proxy.newProxyInstance()參數有三個:

  • ClassLoader
  • 該實現類的全部接口
  • 動態代理對象

在該類中target就是被代理的對象,該類實現了InvocationHandler接口,經過反射去動態建立Hello接口的代理類

那麼如今的調用就變簡單了:

 public static void main(String[] args){
        DynamicProxy dynamicProxy=new DynamicProxy(new HelloImpl());
        Hello helloProxy= dynamicProxy.getProxy();
        helloProxy.say("gary");
    }

用了JDK動態代理後,咱們以爲仍是有問題,若是要代理一個沒有接口的類,該怎麼辦呢,因而就輪到咱們的 CGlib動態代理 出場了。

在Spring、Hibernate等框架中都用到了CGlib動態代理,maven資源以下:

 <!-- https://mvnrepository.com/artifact/cglib/cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.6</version>
        </dependency>

他的使用須要實現MethodInterceptor類,並完成intercept方法。CGlib 提供的是方法級別的代理:

public class CGLibProxy implements MethodInterceptor {

    public <T> T getProxy(Class<T> cls){
        return (T) Enhancer.create(cls,this);
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object result=methodProxy.invokeSuper(o,objects);
        after();
        return result;
    }

    private void before(){
        System.out.println("before");
    }

    private void after(){
        System.out.println("after");
    }
}

這樣使用時就不須要提供接口了:

  public static void main(String[] args){
        CGLibProxy cgLibProxy= new CGLibProxy();
        Hello hello=cgLibProxy.getProxy(HelloImpl.class);
        hello.say("Gary");
    }

最後再改造一下,加上單例模式就更完美了

    private static CGLibProxy instance=new CGLibProxy();
    
    private CGLibProxy(){
    }
public static CGLibProxy getInstance(){ return instance; }

調用就改成:

public static void main(String[] args){
        Hello hello=CGLibProxy.getInstance().getProxy(HelloImpl.class);
        hello.say("Gary");
    }
相關文章
相關標籤/搜索