• 代理模式


    代理模式:为某些对象提供代理以实现对这个对象的访问。

    对一个对象进行访问控制的原因是为了只有在我们确实需要这个对象时才对它进行创建和初始化。

    一般包括以下组件:

    被代理者接口:提供被代理者的访问途径。

    被代理者:定义真实对象。

    代理者:保存一个被代理者的引用, 并对外提供统一的代理方法, 可以对被代理者的方法实现修饰和控制。

    要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,所以首先要编写用于生成代理对象的类。java在JDK1.5之后提供了java.lang.reflect.Proxy类,通过Proxy类提供的newProxyInstance方法用来创建一个对象的代理对象,这个方法总共有3个参数,ClassLoader loader用来指明生成代理对象使用哪个类装载器,Class<?>[] interfaces用来指明生成哪个对象的代理对象,通过接口指定,InvocationHandler 用来指明产生的这个代理对象要做什么事情。所以只需要调用newProxyInstance方法就可以得到某一个对象的代理对象了。

    代理类需要实现InvocationHandler接口,该接口只有一个invoke方法,用于自定义代理行为. 

    JDK动态代理示例

    ----------------

    //代理接口
    public interface IClient {
        void doSomething(String thing);
    }

    -

    //被代理者
    public class Client implements IClient {
        @Override
        public void doSomething(String thing) {
            System.out.println("do a thing:" + thing);
        }
    }

    -

    //代理
    public class ProxyAgent implements InvocationHandler {
        private Object client;
        
        public ProxyAgent(Object client) {
            this.client = client;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 这里可以对method进行过滤或添加其他代码,然后调具体对象的方法
            Object object = method.invoke(client, args);
            return object;
        }
        
        //获取代理实例 
        public Object getProxy(){
            return Proxy.newProxyInstance(getClass().getClassLoader(), client.getClass().getInterfaces(), this);
        }
        
        public static void main(String[] args){
            //被代理者
            Client client = new Client();
            //代理者
            IClient proxy = (IClient) new ProxyAgent(client).getProxy();
            //调用代理动作
            proxy.doSomething("buy something");
        }
    }

    ----------------

    由上可见,使用JDK的Proxy实现动态代理有一个要求:被代理的类必须实现接口,未实现接口则没办法完成动态代理。

    实际中有些类没有实现接口,不应该为了实现动态代理而去抽出一些没有实例意义的接口,可以通过cglib对一个类实现代理。

    <dependency>
          <groupId>cglib</groupId>
          <artifactId>cglib</artifactId>
          <version>3.2.4</version>
    </dependency>

    示例如下:

    package cn.luan.demo;
    
    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 DynamicProxy implements MethodInterceptor {
    
        // 被代理对象
        Object targetObject;
    
        // 动态生成一个新的类,使用父类的无参构造方法创建一个指定了特定回调的代理实例
        public Object getProxyObject(Object object) {
            //set被代理对象
            this.targetObject = object;
            //动态代码生成器
            Enhancer enhancer=new Enhancer();
            //回调方法
            enhancer.setCallback(this);
            //设置生成类的父类类型
            enhancer.setSuperclass(targetObject.getClass());
            //动态生成字节码并返回代理对象
            return enhancer.create();
        }
    
        // 实现了一个方法拦截器接口
        @Override
        public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    
            System.out.println("方法调用前织入的横切内容");
            System.out.println("method name: " + method.getName());
    
            // 调用方法
            Object result = methodProxy.invoke(targetObject, args);
    
            System.out.println("方法调用后织入的横切内容");
    
            return result;
        }
    
        //测试
        public static void main(String[] args) {
            Client client = (Client) new DynamicProxy().getProxyObject(new Client());
            client.doSomething("cglib proxy");
        }
    }

    --cglib不能对final类做代理

    end

    觉得不错,点个赞吧
  • 相关阅读:
    validFrom不通过submit按钮来触发表单验证
    微信小程序组件开发
    css3 单行文字溢出,多行文字溢出
    表格布局
    对象设置默认属性
    按钮样式
    判断一个json是否为空
    vue高仿饿了么(三)
    Win10 用IE打开网址默认跳转到Edge如何解决?
    VMware虚拟机安装Win11正式版
  • 原文地址:https://www.cnblogs.com/luangeng/p/5517307.html
Copyright © 2020-2023  润新知