cglib动态代理。上一篇在写aop的时候提了一下代理模式。今天来看一下,cglib动态代理。
首先,动态代理是通过反射进行执行的。运行时编译。其次,它也具备代理模式的共性,都是在主业务逻辑开始之前和之后进行一些操作,不需要修改原来的业务代码。
拿http://blog.csdn.net/xiaohai0504/article/details/6832990做介绍
1. 我们创建一个对Table操作的DAO类,提供了CQUD方法。
BookServiceBean.java
- package com.tech.cglibx;
- 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 !");
- }
- }
OK,它就是一个javaBean,提供了CQUD方法的javaBean。
下面我们创建一个DAO工厂,用来生成DAO实例。
- package com.tech.cglibx;
- public class BookServiceFactory {
- private static BookServiceBean service = new BookServiceBean();
- private BookServiceFactory() {
- }
- public static BookServiceBean getInstance() {
- return service;
- }
- }
接下来我们创建客户端,用来调用CQUD方法。
- public class Client {
- public static void main(String[] args) {
- BookServiceBean service = BookServiceFactory.getInstance();
- doMethod(service);
- }
- public static void doMethod(BookServiceBean service){
- service.create();
- service.update();
- service.query();
- service.delete();
- }
- }
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();
}
}