zoukankan      html  css  js  c++  java
  • Java反射(三)反射与代理设计模式

    代理设计模式的思想,即用一个代理类实现为被代理类添加额外的工作,在实际开发中可能是日志记录、耗时计算等。

    1.代理模式必不可少的元素:被代理接口、被代理类、代理类(组合被代理类);

    2.一般可以使用两种方式实现代理:(1)静态代理;(2)动态代理。

    3.还有一个可以直接对类进行代理,不需要被代理接口,即为CGLib。


    1.静态代理

    静态代理很容易理解,代理类与被代理类都实现同一个接口,代理类将被代理类组合为自己的属性,在调用接口方法时,添加额外的功能。举例如下:

    • 被代理接口:IMessage
    • 被代理类:MessageReal
    • 代理类:MessageProxy,其中包含对代理对象的额外处理。
    interface IMessage{
        void send(String msg);
    }
    
    /**
     * 被代理类
     */
    class MessageReal implements  IMessage{
    
        public void send(String msg){
            System.out.println("发送消息");
        }
    }
    
    /**
     * 代理类
     */
    class MessageProxy implements  IMessage{
    
        private IMessage message;
    
        public MessageProxy(IMessage message){
            this.message = message;
        }
    
        /**
         * 代理后的处理方法
         * @param msg
         */
        public void send(String msg){
            if(connect()){
                message.send(msg);
                close();
            }
        }
    
        private boolean connect(){
            System.out.println("创建连接");
            return  true;
        }
    
        private void close(){
            System.out.println("关闭连接");
        }
    }

     静态代理特点:每个代理类只能代理一个被代理类。如果开发中存在上千个类需要代理,这种方式就不适合了,可以采用动态代理的方式。

    2.动态代理

    上文中说代理必备的元素:被代理接口、被代理类、代理类,在动态代理中也是必不可少的。关键元素:

    • java.lang.reflect.Proxy,代理类,其通过生成代理字节码实现代理,具体底层实现请关注后文。
    • java.lang.reflect.InvocationHandler ,辅助代理类添加额外的功能,由用户自定义实现,执行具体方法时,进行回调。

    (1)Proxy

    重要的静态方法是newProxyInstance方法,该方法返回的即为代理类,定义如下:

    public static Object newProxyInstance​(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

     loader - 定义代理类的ClassLoader(the class loader to define the proxy class),实现与被代理类使用相同的类加载器

    interfaces - 被代理接口(the list of interfaces for the proxy class to implement)

    h - 代理回调处理类(the invocation handler to dispatch method invocations to),自定义的InvocationHandler类,一般会包含被代理类

    (2)InvocationHandler 

     重要方法invoke(),处理代理类方法调用并返回结果,该方法在关联的代理类调用方法时会被调用。

    Object invoke​(Object proxy,Method method,Object[] args)throws Throwable

    proxy - 调用该方法的代理类,一般程序中不使用

    method - 被调方法的Method对象

    args - 被调方法的参数。

    (3)动态代理实例

    设计个网络代理NetProxy,实现InvocationHandler接口,添加代理类处理逻辑。

    • 被代理接口:target.getClass().getInterfaces()
    • 被代理类:Object target
    • 代理类:Proxy.newProxyInstance
    class NetProxy implements InvocationHandler{
    
        private Object target;//被代理类,Object可以代理任何类型的类
    
        public <T> T proxy(Object target, Class<T> clazz){
            this.target = target;
            return (T)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    
        /**
         * 代理对象方法调用的回调处理方法
         * @param proxy
         * @param method
         * @param args
         * @return
         * @throws Throwable
         */
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable{
            Object result = null;
            if(this.connect()){
                method.invoke(target, args);
                this.close();
            }
            return result;
        }
    
        private boolean connect(){
            System.out.println("创建连接");
            return  true;
        }
    
        private void close(){
            System.out.println("关闭连接");
        }
    }

      测试:

     public static void main(String[] args){
            IMessage message = new NetProxy().proxy(new MessageReal(), IMessage.class);
            message.send("hello");
        }

      输出:

    创建连接
    发送消息
    关闭连接

     3.CGLib代理

     上文描述的静态代理和动态代理都基于接口实现,即需要有明确的被代理接口。CGLib代理,直接对类进行代理,不需要接口。其底层是通过生成代理类字节码实现的。

    • 被代理接口:无
    • 被代理类:Object target
    • 代理类:Enhancer.create()
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    
    class NetProxy implements MethodInterceptor{
    
        private Object target;//被代理类,Object可以代理任何类型的类
    
        public <T> T proxy(Object target, Class<T> clazz){
            this.target = target;
            Enhancer enhancer = new Enhancer();//创建代理的程序类
            enhancer.setSuperclass(target.getClass());//假定一个父类
            enhancer.setCallback(this);//设置代理类回调处理方法
            return (T)enhancer.create();//创建代理类
        }
    
        /**
         * 拦截器,代理执行会被拦截
         * @param proxy
         * @param method
         * @param objects
         * @param methodProxy
         * @return
         * @throws Throwable
         */
        public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            if(this.connect()){
                method.invoke(target, objects);
                this.close();
            }
            return null;
        }
    
        private boolean connect(){
            System.out.println("创建连接");
            return  true;
        }
    
        private void close(){
            System.out.println("关闭连接");
        }
    }

    4.总结

    1.常用的代理模式三要素:被代理接口、被代理类、代理类,对面向接口的编程,该方式比较适合

    2.静态代理和动态代理都是基于三要素实现的,区别在于静态代理可实现具体代理类代理某个类,不能扩展;动态代理可以代理任一类型的类

    3.动态代理核心是Proxy和InvocationHandler类,底层通过生成代理字节码文件实现代理

    4.CGLib代理不需要接口,可直接代理类,在Spring中同时支持Java动态代理和CGlib代理。

  • 相关阅读:
    作业01(2020年10月10号)
    C语言I博客作业04
    C语言I博客作业03
    C语言I博客作业02
    第一次学c语言作业
    C语言I博客作业09
    C语言I博客作业08
    C语言I博客作业07
    C语言I博客作业06
    C语言I博客作业05
  • 原文地址:https://www.cnblogs.com/shuimuzhushui/p/12676791.html
Copyright © 2011-2022 走看看