使用CGLIB实现动态代理

CGLIB动态代理

原理:
运行时动态的生成一个被代理类的子类(通过ASM字节码处理框架实现),子类重写了被代理类中所有非final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势植入横切逻辑。
先来看一段代码:

//被代理的类 模仿数据库的service层
public class ServiceBean {
    public void create(){
        System.out.println("creating!!");
    }
    public void delete(){
        System.out.println("deleting!!");
    }
    public void update(){
        System.out.println("updating!!");
    }
    public void query(){
        System.out.println("querying!!");
    }
}

我们如果需要在后续给每个方法拓展一些功能,比如说权限功能,日志功能。去修改每个方法显然是不明智的。这时候就可以使用到动态代理。而上篇文章已经说到过,jdk的动态代理是需要实现接口的,明显在这里不太适合,我们选用另外一种方式实现动态代理
下面程序实现的效果是 :除了query()方法外,其他的方法都需要boss权限才能调用,而query()所有人都能调用

//使用cglib实现的代理类需要实现MethodInterceptor 拦截器
public class MyCglibProxy implements MethodInterceptor {
    private Logger logger = LoggerFactory.getLogger(MyCglibProxy.class);
    private String name;
    //Enhancer 适用于创建代理对象的一个工具类
    public Enhancer enhancer = new Enhancer();

    //给这个代理设置一个名字
    public MyCglibProxy(String name) {
        this.name = name;
    }

    public Object getObjectBean(Class cls){
        enhancer.setSuperclass(cls);
        enhancer.setCallbacks(new Callback[]{this, NoOp.INSTANCE});
        /**
         * 在此设置过滤器(这个可以根据需求设置)
         * MyProxyFilter 实现过滤器 CallbackFilter
         * 他的作用是可以明确表示,被代理中的类的不同方法 被哪拦截器所拦截
         *
         * 对于setCallbacks方法
         * setCallbacks中定义了所使用的拦截器,其中NoOp.INSTANCE是CGlib所提供的实际是一个没有任何操作的拦截器,
         * 他们是有序的,一定要和CallbackFilter(在这里是MyProxyFilter)里面的顺序一致。上面return返回(0/1)的就是返回的顺序。也就是说如果调用query方法就使用NoOp.INSTANCE进行拦截。
         */
        enhancer.setCallbackFilter(new MyProxyFilter());
        return enhancer.create();
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        logger.info("调用方法:"+method.getName());
        if(!"boss".equals(name)){
            logger.info("您没有权限");
            return null;
        }
        //代理子类对象生成以后 会调用复写的方法,传入对应得参数
        Object result = methodProxy.invokeSuper(o,objects);
        return result;
    }

}
public class MyProxyFilter implements CallbackFilter {

    @Override
    public int accept(Method method) {
        //return 的顺序和enhancer.setCallbacks(new Callback[]{proxy, NoOp.INSTANCE});中的顺序是对应的
        //如果返回的是0,则使用的是proxy拦截器 如果返回的是1 则使用的是NoOp.INSTANCE,这个拦截器什么都没有做
        if(!"query".equalsIgnoreCase(method.getName())){
            return 0;
        }
        return 1;
    }
}
//方法调用
public class Main {
    public static void main(String[] args) {
        ServiceBean serviceBean1 = (ServiceBean)(new MyCglibProxy("boss").getObjectBean(ServiceBean.class));
        serviceBean1.create();
        ServiceBean serviceBean2 = (ServiceBean)(new MyCglibProxy("jonh").getObjectBean(ServiceBean.class));
        //虽然是jonh 但是query()是允许调用的
        serviceBean2.query();
        ServiceBean serviceBean3 = (ServiceBean)(new MyCglibProxy("jonh").getObjectBean(ServiceBean.class));
        //不是boss 无权限调用create()
        serviceBean3.create();
    }
}

与JDK不同的是 cglib动态生成了一个子类。子类重写了被代理类中所有非final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势植入横切逻辑。

你可能感兴趣的:(设计模式)