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();
	}
}


项目目录:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值