zoukankan      html  css  js  c++  java
  • 通俗易懂的讲解一下Java的代理模式如何实现

    一、代理模式的基本介绍

    何为代理模式呢?

    就是为对象提供一个替身,以控制对这个对象的访问,即通过代理对象访问目标对象,这样做的好处是可以在目标对象实现的基础上,增强额外的功能操作( 在调用这个方法前做前置处理,调用这个方法后 做后置处理。),即扩展对象的功能(类似明星需要经纪人一个道理,比如明星接广告,那么广告上需要和经纪人商量这事,而不是直接和明星去谈这件事)。

    image-20200518205817345

    二、代理模式的分类及实现

    1、静态代理

    静态代理在使用的时候,需要定义接口,被代理对象(目标对象)与代理对象一起实现相同的接口。

    具体实现:

    1、定义一个接口:UserManager,

    2、真实对象UserManagerImpl实现UserManager接口,代理对象ProxyUserManager也实现UserManager

    3、调用的时候通过调用代理对象的方法来调用目标对象

    类结构图:

    image-20200518211345498

    //接口
    public interface UserManager {
    
        void addUser(String userId, String userName);
       
    }
    
    //真实对象
    public class UserManagerImpl implements UserManager {
        @Override
        public void addUser(String userId, String userName) {
            System.out.println("添加用户!!!!!!!");
        }
    
    }
    
    //代理对象
    public class ProxyUserManager implements UserManager {
        private UserManager userManager;  //目标对象
        //构造器传递目标对象
        public ProxyUserManager(UserManager userManager) {
            this.userManager = userManager;
        }
    
        @Override
        public void addUser(String userId, String userName) {
            System.out.println("添加用户开始!!!!!!!!!!!!!!!");
            userManager.addUser(userId, userName);
            System.out.println("添加用户结束!!!!!!!!!!!!!!!!!");
        }
    
    }
    
    //客户端测试
    public class ClientTest {
    
        public static void main(String[] args) {
            UserManager userManager=new ProxyUserManager(new UserManagerImpl());
            userManager.addUser("1","张三");
        }
    }
    

    优点:在不修改目标对象功能的前提下,能通过代理对象对目标对象实现功能的扩展

    缺点:因为代理对象需要和目标对象实现一样的接口,所以会有很多代理对象

    ​ 一旦接口增加对象,目标对象与代理对象都要维护

    2、动态代理(JDK)代理

    代理对象不需要实现接口,但是目标对象需要实现接口,否则不能实现动态代理

    代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象

    方法说明:

    ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
    Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
    InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
    
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
    

    接口对象UserManager,目标对象UserManagerImpl同静态代理,代理类:ProxyFactory

    public class ProxyFactory {
    
        private Object target; //目标对象
    
        public ProxyFactory(Object target) {
            this.target = target;   //对目标对象初始化
        }
    
        //给目标对象生成一个代理对象
        public Object getProxyInstance() {
            
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("JDK代理开始!!!!!!");
                            Object obj = method.invoke(target, args);
                            System.out.println("JDK代理结束!!!!!");
                            return obj;
                        }
                    });
        }
    
    }
    
    

    测试客户端:

    public class Client {
        public static void main(String[] args) {
            //目标对象
            UserManager target = new UserManagerImpl();
            //创建代理对象
            UserManager proxyInstance = (UserManager) new ProxyFactory(target).getProxyInstance();
            proxyInstance.addUser("231", "zhangfu");
        }
    
    }
    

    3、动态代理(CJLIB)代理

    静态代理和动态代理都需要目标对象实现一个接口,但有时候目标对象只是一个单独的对象,

    并没有实现任何接口,这个时候就可以使用目标对象实现动态代理---CJLIB代理。

    CJLIb代理是内存中构建一个子类对象从而实现对目标对象功能的扩展,Cjlib是一个强大的高性能的代码

    生成包,它可以在运行期扩展java类与实现JAVA接口,广泛的应用在(SpringAOP)当中。

    Cjlib 包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。

    实例实现:

    首先导入CJLIB 的架包

    image-20200518221940520

    代理类(ProxyFactory)需要实现MethodInterceptor接口,重写intercept()的方法。

    代码实现:

    public class UserManagerImpl  {
    
        public void addUser(String userId, String userName) {
            System.out.println("添加用户!!!!!!!");
        }
    
    }
    
    public class ProxyFactory implements MethodInterceptor {
        private Object target;  //目标对象
    
        public ProxyFactory(Object target) {
            this.target = target;  //初始化目标对象
        }
    
        //返回一个代理对象
        public Object getProxyInstance() {
            //创建一个工具类
            Enhancer enhancer = new Enhancer();
            //设置父类
            enhancer.setSuperclass(target.getClass());
            //设置回调函数
            enhancer.setCallback(this);
            //创建代理对象
            return enhancer.create();
    
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
            System.out.println("CJLIB代理开始");
            Object obj = method.invoke(target, objects);
            System.out.println("CJLIB代理结束");
            return obj;
        }
    }
    

    客户端测试

    public class Client {
        public static void main(String[] args) {
            UserManagerImpl proxyInstance = (UserManagerImpl) new ProxyFactory(new UserManagerImpl()).getProxyInstance();
            proxyInstance.addUser("A", "AD");
        }
    }
    

    三、小结

    在实际工作中:如果目标对象需要实现接口,采用静态代理,JDK代理

    目标对象不需要实现接口,采用CJLIB代理

    技术之路漫长,每天进步一丢丢

  • 相关阅读:
    火星救援
    Android学习笔记(8)————详细谈谈intent的startActivityForResult()方法
    Android小技巧(二):为ContentProvider添加数据库事务支持
    Android小技巧(一):实现捕获应用的运行时异常
    理解Activity的生命周期
    Android异步处理四:AsyncTask的实现原理
    Android异步处理三:Handler+Looper+MessageQueue深入详解
    Android异步处理二:使用AsyncTask异步更新UI界面
    Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
    Android APK反编译详解(附图)
  • 原文地址:https://www.cnblogs.com/xiaofuzi123456/p/12913581.html
Copyright © 2011-2022 走看看