代理模式詳解

       
        代理模式爲對象提供一個代理以控制對這個對象的訪問。所謂代理,是指與代理元(即:被代理的對象)具備相同接口的類,客戶端必須經過代理與代理元進行交互。咱們能夠 將代理理解成另外一個對象的表明
        代理(proxy)模式本質上就是經過一個代理對象訪問目標對象,而不直接訪問目標對象;代理模式能夠在不修改被代理對象的基礎上,經過擴展代理類,進行一些功能的附加與加強。這麼作的好處是,可讓目標對象只關注業務邏輯,而非業務邏輯(好比日誌輸出等)能夠在代理對象中實現,實現業務分離。

 

代理模式要點:
  • 代理模式包含三個要素:1)接口/Interface; 2)代理元/Target:即被代理的對象; 3)代理類/Proxy:代理元的表明,對外提供訪問;
  • 代理元與代理類都是接口的實現類;
  • 客戶端只能訪問代理類,沒法直接訪問代理元;

 

代理分爲靜態代理和動態代理。java

 


靜態代理

 
        靜態代理就是在編譯時生成代理類。即:經過編碼手動建立代理類,並在代理類中調用代理元。
 
編碼實現
 
1.接口
package effectiveJava.proxy;

public interface HelloService {
    void sayHello();
}

2,代理元git

package effectiveJava.proxy;

public class HelloServiceImpl implements HelloService{
    @Override
    public void sayHello() {
        System.out.println("Hello Proxy.");
    }
}

3,代理類github

package effectiveJava.proxy.staticProxy;

import effectiveJava.proxy.HelloService;

public class LogProxy implements HelloService {

    private HelloService service;

    public LogProxy(HelloService service) {
        this.service = service;
    }

    @Override
    public void sayHello() {
        System.out.println("Static Proxy : Before Hello....");
        service.sayHello();
        System.out.println("Static Proxy : After Hello....");
    }
}

4,測試類ide

package effectiveJava.proxy.staticProxy;

import effectiveJava.proxy.HelloServiceImpl;

public class LogProxyDemo {
    public static void main(String[] args) {
        LogProxy logProxy = new LogProxy(new HelloServiceImpl());
        logProxy.sayHello();
    }
}

5,測試結果函數

Static Proxy : Before Hello....
Hello Proxy.
Static Proxy : After Hello....

 


動態代理測試


 

        動態代理地實現有兩種方式:1)基於JDK的動態代理;2)基於CGLIB的動態代理;this

 

1)基於JDK的動態代理編碼

 

APIspa

public class Proxy implements java.io.Serializable {
     /**
   * 建立代理實例
      *  @param loader 代理元的類加載器
      *  @param interfaces 代理元的接口
      *  h 一個 InvocationHandler 對象
      */
     
   public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);

}
/**
 *
 * 每一個代理的實例都有一個與之關聯的 InvocationHandler 實現類,
 * 若是代理的方法被調用,那麼代理便會通知和轉發給內部的 InvocationHandler 實現類,由它決定處理。
 */
public interface InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

 

編碼實現代理

1,接口、代理元(編碼與靜態代理一致,再也不贅述)
2,代理類(必須實現InvocationHandler接口)
package effectiveJava.proxy.v0;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class HelloInvocation implements InvocationHandler {
    /**
     * 代理元
     */
    private Object target;

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

    /**
     *
     * @param proxy 代理類實例
     * @param method 實際要調用的方法
     * @param args  實際要調用方法的參數類型
     * @return 結果值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("HelloInvocation : Before Hello....");
        Object reslut = method.invoke(target, args);
        System.out.println("HelloInvocation : After Hello....");
        return reslut;
    }

}

3,測試類

package effectiveJava.proxy.v0;

import effectiveJava.proxy.HelloService;
import effectiveJava.proxy.HelloServiceImpl;

import java.lang.reflect.Proxy;

/**
* 經過Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)建立代理對象的實例
*/
public class HelloInvocationDemo {
    public static void main(String[] args) {
        HelloServiceImpl helloService = new HelloServiceImpl();
        HelloInvocation helloInvocation = new HelloInvocation(helloService);
        HelloService impl = (HelloService)Proxy.newProxyInstance( helloService.getClass().getClassLoader(), helloService.getClass().getInterfaces(), helloInvocation);
        impl.sayHello();
    }
}

4,測試結果

HelloInvocation : Before Hello....
Hello Proxy.
HelloInvocation : After Hello....

 

2)基於CGLIB的動態代理

   Cglib是基於繼承的方式進行代理,代理類去繼承目標類,每次調用代理類的方法都會被方法攔截器攔截,在攔截器中才是調用目標類的該方法的邏輯。所以,基於CGLIB的動態代理不須要接口。

 

 

編碼實現

1,引入架包

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
2,代理類(HelloServiceImpl.java,編碼與靜態代理一致)
 3, 方法攔截器
package effectiveJava.proxy.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class LogInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib : Before hello..."); 
        //調用父委方法
        Object result = methodProxy.invokeSuper(object, args);
        System.out.println("Cglib : After hello...");
        return result;
    }
}

4,測試類

package effectiveJava.proxy.cglib;

import effectiveJava.proxy.HelloService;
import effectiveJava.proxy.HelloServiceImpl;
import net.sf.cglib.proxy.Enhancer;

public class CglibDemo {
    public static void main(String[] args) {
        //建立Enhancer對象,相似於JDK動態代理的Proxy類
        Enhancer enhancer = new Enhancer();
        //設置父類
        enhancer.setSuperclass(HelloServiceImpl.class);
        //設置回調函數(攔截器)
        enhancer.setCallback(new LogInterceptor());
        //建立代理類實例
        HelloService service = (HelloService)enhancer.create();
        service.sayHello();
    }
}

5,測試結果

Cglib : Before hello...
Hello Proxy.
Cglib : After hello...
總結:
  • 靜態代理是在編譯時建立代理,動態代理是在運行時建立代理;
  • JDK動態代理是基於接口的方式,CGLib動態代理是基於繼承;
 
相關文章
相關標籤/搜索