Java中的代理

Java中的代理

代理模式(Proxy)是經過代理對象訪問目標對象,這樣能夠在目標對象基礎上加強額外的功能,如添加權限,訪問控制和審計等功能。
  • 增長額外功能,進行加強
  • 引入第三方代理類,進行解耦
  1. 靜態代理

請參考下面的代碼:java

/**
*聲明一個明星接口,明星只須要關注本身的唱、跳
*/
public interface StarService {
    void sing();
    void jump();
}
/**
*明星接口的具體實現類
*/
public class StarServiceImpl implements StarService{
    public void sing() {
        System.out.println(" sing a song ");
    }

    public void jump() {
        System.out.println(" just dance ");
    }
}
/**
*代理類
*/
public class StarServiceProxy implements StarService {

    private StarService starService;
	// 經過構造方法將目標實現類注入
    public StarServiceProxy(StarService starService) {
        this.starService = starService;
    }

    public void sing() {
        System.out.println("唱歌以前先聯繫綜藝節目,肯定時間、地點");
        starService.sing();
        System.out.println("表演結束以後,安排下一場演出");
    }

    public void jump() {
        return starService.jump();
        System.out.println("跳舞以後,觀衆鼓掌");
    }
}
public class ProxyTest {

    public static void main(String[] args) {
        StarService starService = new StarServiceImpl();
        StarServiceProxy proxy = new StarServiceProxy(starService);
        proxy.sing();
    }
}
輸出:
 唱歌以前先聯繫綜藝節目,肯定時間、地點
  sing a song 
 表演結束以後,安排下一場演出

總結ide

  • 靜態代理模式在不改變目標對象的前提下,實現了對目標對象的功能擴展;
  • 不足: 靜態代理實現了目標對象的全部方法,一旦目標接口增長方法,代理對象和目標對象都要進行相應的修改,增長維護成本。
  1. 動態代理

Java中的動態代理須要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 類的支持 。jdk的動態代理是面向接口的,即jdk的動態代理只能代理實現接口的類,不能代理抽象類或者沒有實現接口的類。函數

java.lang.reflect.InvocationHandler接口的定義以下:工具

/**
*	Object proxy   被代理的對象  
*	Method method  要調用的方法  
*	Object[] args  方法調用時所須要參數  
*/
public interface InvocationHandler {  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;  
}

java.lang.reflect.Proxy類的定義以下:測試

/**
*	CLassLoader loader    類的加載器 
*	Class<?> interfaces   獲得所有的接口  
*	InvocationHandler h   獲得InvocationHandler接口的子類的實例
*/  
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

jdk動態代理流程:this

  1. 經過實現 InvocationHandler 接口建立本身的調用處理器;
  2. 經過爲 Proxy 類指定 ClassLoader 對象和一組interface來建立動態代理類;
  3. 經過反射機制得到動態代理類的構造函數,其惟一參數類型是調用處理器接口類型;
  4. 經過構造函數建立動態代理類實例,構造時調用處理器對象做爲參數被傳入。
// 自定義中間代理類
public class YourHandler implements InvocationHandler {
    // 目標對象  
    private Object targetObject;  
    
    public ProxyHandler( Object proxied ) {   
    	this.proxied = proxied;   
  	}  
    
     /*proxy表示代理目標對象,method表示原對象被調用的方法,args表示方法的參數*/  
    @Ovrride
    public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable {   
    //在轉調具體目標對象以前,能夠執行一些功能處理

    //轉調具體目標對象的方法
    return method.invoke( proxy, args);  
    
    //在轉調具體目標對象以後,能夠執行一些功能處理
  		}    
    }

實際應用時代碼以下:代理

// RealSubject  要代理的目標對象
RealSubject real = new RealSubject(); 
// Subject 目標對象實現的接口
    Subject proxySubject =   	(Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(), 
     new Class[]{Subject.class}, 
     new YourHandler(real));
 // proxySubject 爲中間代理類        
    proxySubject.method( Object[] args);
  1. Cglib代理
`Cglib`代理補充了`jdk`中只面向接口進行代理的不足,`Cglib`代理支持基於對象代理,不用關心該對象是否實現了某個接口。 `Cglib`是一個`java`字節碼的生成工具,它動態生成一個被代理類的子類,子類重寫被代理的類的全部不是`final`的方法。在子類中採用方法攔截的技術攔截全部父類方法的調用,順勢織入橫切邏輯。 

	以上面的`StarServiceImpl`爲被代理對象,舉個例子:
/**
*  自定義中間代理類
*/
public class MyMethodInterceptor implements MethodInterceptor {

	@Override
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("Before: "  + method.getName());
        Object object = methodProxy.invokeSuper(o, objects);
        System.out.println("After: " + method.getName());
        return object;
	}
}
// 測試以下
public static void main(String[] args) {
		Enhancer enhancer = new Enhancer();
        //繼承被代理類
        enhancer.setSuperclass(Star.class);
        //設置回調
        enhancer.setCallback(new MyMethodInterceptor());
        //設置代理類對象
        StarServiceImpl starService = (StarServiceImpl) enhancer.create();
        //在調用代理類中方法時會被咱們實現的方法攔截器進行攔截
        starService.sing();
	}
輸出結果以下:
    Before: sing
	sing a song
	After: sing
相關文章
相關標籤/搜索