cglib動態代理模式

    cglib動態代理。上一篇在寫aop的時候提了一下代理模式。今天來看一下,cglib動態代理。

    首先,動態代理是通過反射進行執行的。運行時編譯。其次,它也具備代理模式的共性,都是在主業務邏輯開始之前和之後進行一些操作,不需要修改原來的業務代碼。


拿http://blog.csdn.net/xiaohai0504/article/details/6832990做介紹

1. 我們創建一個對Table操作的DAO類,提供了CQUD方法。 
    BookServiceBean.java

[java] view plain copy
  1. package com.tech.cglibx;  
  2. public class BookServiceBean {  
  3.  public void create(){     
  4.         System.out.println("create() is running !");     
  5.     }     
  6.     public void query(){     
  7.         System.out.println("query() is running !");     
  8.     }     
  9.     public void update(){     
  10.         System.out.println("update() is running !");     
  11.     }     
  12.     public void delete(){     
  13.         System.out.println("delete() is running !");     
  14.     }     
  15. }  

OK,它就是一個javaBean,提供了CQUD方法的javaBean。 
    下面我們創建一個DAO工廠,用來生成DAO實例。

[java] view plain copy
  1. package com.tech.cglibx;  
  2. public class BookServiceFactory {  
  3.  private static BookServiceBean service = new BookServiceBean();  
  4.  private BookServiceFactory() {  
  5.  }  
  6.  public static BookServiceBean getInstance() {  
  7.   return service;  
  8.  }  
  9. }  

接下來我們創建客戶端,用來調用CQUD方法。

[java] view plain copy
  1. public class Client {     
  2.     
  3.     public static void main(String[] args) {     
  4.         BookServiceBean service = BookServiceFactory.getInstance();   
  5.         doMethod(service);     
  6.     }     
  7.     public static void doMethod(BookServiceBean service){     
  8.         service.create();  
  9.         service.update();  
  10.         service.query();  
  11.         service.delete();   
  12.     }     
  13. }   

 OK,完成了,CQUD方法完全被調用了。

    當然這裏並沒有CGlib的任何內容。問題不會這麼簡單的就結束,新的需求來臨了。

 
2. one day,Boss告訴我們這些方法不能開放給用戶,只有“zhangsan”纔有權使用。怎麼辦,難道我們要在每個方法上面進行判斷嗎?好像這麼做也太那啥了吧?對了,Proxy可能是最好的解決辦法。jdk的代理就可以解決了。 好了我們來動手改造吧。等等jdk的代理需要實現接口,這樣, 我們的dao類需要改變了。既然不想改動dao又要使用代理,我們這就請出CGlib。
我們只需新增一個權限驗證的方法攔截器。


主業務邏輯不變:

package com.baidu.cglib.service;

public class BookServiceBean {
	public void create() {
		System.out.println("create() is running !");
	}
	public void query() {
		System.out.println("query() is running !");
	}
	public void update() {
		System.out.println("update() is running !");
	}
	public void delete() {
		System.out.println("delete() is running !");
	}
}

增加cglib動態代理類:

package com.baidu.cglib.intercept;

import java.lang.reflect.Method;

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

public class MyCglibProxy implements MethodInterceptor{

	public Enhancer enhancer = new Enhancer(); //用來製作一個對象的代理對象
	private String name;
	public MyCglibProxy(String name) {
		this.name = name;
	}
	// 冗餘代碼,在fctory中並沒有調用該方法
//	public Object getDaoBean(Class clas) {
//		enhancer.setSuperclass(clas);
//		enhancer.setCallback(this);
//		return enhancer.create();
//	}
	
	public Object intercept(Object obj, Method method, Object[] arg,
			MethodProxy methodProxy) throws Throwable {
		System.out.println(obj.getClass()); // EnhancerByCGLIB類型。就是指的是類中enhancer
		System.out.println(arg.getClass());
		System.out.println(method.getName());
		if(!"zhangsan".equals(name)) {
			System.out.println("you have no power");
			return null;
		}
		Object result = methodProxy.invokeSuper(obj,arg);
		return result;
	}

}
enhancer的setSuperClass(clas),作用就是設置這個enhancer生成的代理對象是繼承clas對象的。由此可以看出,cglib動態代理模式的實現其實是通過繼承來做的。然後同這裏是在factory類中調用的。

fctory代碼:

package com.baidu.cglib.factory;

import net.sf.cglib.proxy.Enhancer;

import com.baidu.cglib.intercept.MyCglibProxy;
import com.baidu.cglib.service.BookServiceBean;

public class BookServiceFactory {
	private static BookServiceBean service = new BookServiceBean();
	
	private BookServiceFactory() {}
	public static BookServiceBean getBean() {
		return service;
	}
	public static BookServiceBean getProxyInstance(MyCglibProxy myProxy) {
		Enhancer en = new Enhancer();
		en.setSuperclass(BookServiceBean.class);
		en.setCallback(myProxy); // 設置回調,在myproxy中調用Bookservice中的方法
		return (BookServiceBean)en.create();
	}
}
客戶端測試代碼:

package com.baidu.cglib.client;

import com.baidu.cglib.factory.BookServiceFactory;
import com.baidu.cglib.intercept.MyCglibProxy;
import com.baidu.cglib.service.BookServiceBean;

public class Client {
	public static void main(String[] args) {
		BookServiceBean service = BookServiceFactory.getBean();
		doMethod(service);
		BookServiceBean service2 = BookServiceFactory.getProxyInstance(new MyCglibProxy("zhangsan"));
		service2.create();
	}
	public static void doMethod(BookServiceBean service) {
		service.create();
		service.update();
		service.query();
		service.delete();
	}
}

最後生成:

create() is running !
update() is running !
query() is running !
delete() is running !
class com.baidu.cglib.service.BookServiceBean$$EnhancerByCGLIB$$f98390c1
class [Ljava.lang.Object;
create
create() is running !

這時,所有的業務邏輯就只能有zhangsan去執行了。但是現在如果要開放業務邏輯中的query()方法給所有的人應該怎麼做?這時候就需要用方法過濾器(CallbackFilter),CallbackFilter可以明確表明,被代理的類中不同的方法,被哪個攔截器所攔截。
下面我們就來做個過濾器用來過濾query方法。

package com.baidu.cglib.intercept;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.CallbackFilter;

public class MyProxyFilter implements CallbackFilter{

	public int accept(Method method) {
		if(!"query".equalsIgnoreCase(method.getName())) {    
            <span style="white-space:pre">		</span>return 0;       
		}
		return 1; 
	}
}
return 0或者1對應了攔截器的順序。在factory類中新增加一個被攔截器攔截的方法。

package com.baidu.cglib.factory;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;

import com.baidu.cglib.intercept.MyCglibProxy;
import com.baidu.cglib.intercept.MyProxyFilter;
import com.baidu.cglib.service.BookServiceBean;

public class BookServiceFactory {
	private static BookServiceBean service = new BookServiceBean();
	
	private BookServiceFactory() {}
	public static BookServiceBean getBean() {
		return service;
	}
	public static BookServiceBean getProxyInstance(MyCglibProxy myProxy) {
		Enhancer en = new Enhancer();
		en.setSuperclass(BookServiceBean.class);
		en.setCallback(myProxy); // 設置回調,在myproxy中調用Bookservice中的方法
		return (BookServiceBean)en.create();
	}
	public static BookServiceBean getAuthInstanceByFilter(MyCglibProxy myProxy) {
		Enhancer en = new Enhancer();
		en.setSuperclass(BookServiceBean.class);
		en.setCallbacks(new Callback[] {myProxy,NoOp.INSTANCE});
		en.setCallbackFilter(new MyProxyFilter());
		return (BookServiceBean)en.create();
	}
}
setCallbacks中定義了所使用的攔截器,其中NoOp.INSTANCE是CGlib所提供的實際是一個沒有任何操作的攔截器, 
   他們是有序的,一定要和CallbackFilter裏面的順序一致。上面return返回(0/1)的就是返回的順序。也就是說如果調用query方法就使用NoOp.INSTANCE進行攔截。

重寫client類:

package com.baidu.cglib.client;

import com.baidu.cglib.factory.BookServiceFactory;
import com.baidu.cglib.intercept.MyCglibProxy;
import com.baidu.cglib.service.BookServiceBean;

public class Client {
	public static void main(String[] args) {
		BookServiceBean service = BookServiceFactory.getBean();
		doMethod(service);
		BookServiceBean service2 = BookServiceFactory.getProxyInstance(new MyCglibProxy("zhangsan"));
		service2.create();
		BookServiceBean service3 = BookServiceFactory.getAuthInstanceByFilter(new MyCglibProxy("jhon"));
		service3.query();
		service3.create();
	}
	public static void doMethod(BookServiceBean service) {
		service.create();
		service.update();
		service.query();
		service.delete();
	}
}


項目目錄:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章