美文网首页
Java 代理模式

Java 代理模式

作者: 索性流年 | 来源:发表于2021-02-08 08:54 被阅读0次

    文集地址

    一句话总计代理模式

    • 让别人帮你做事,便是代理模式

    什么是代理模式?

    *为其他对象生成一个代理,以控制这个对象的访问

    为什么使用代理模式?

    • 中介隔离:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到承上启下的作用,其特征是代理类和委托类实现相同的接口。

    • 开闭原则,增加功能代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

    代理模式实现原理

    • 代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy)

    生么是静态代理?

    • 静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

    • 总结: 自己手写代理类就是静态代理。

    静态代理的缺点?

    • 如若项目中被代理类过多,那么就会生成很多代理类,代码会非常冗余

    动态代理

    • 动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象,动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成。

    代理模式两种创建方式

    • 继承、实现

    静态代理与动态代理区别

    • 静态代理是程序员手动创建的代理,而动态代理则是由系统在运行时自动创建的代理。

    JDK动态代理与CGLIB代理区别

    • JDK实现动态代理,被代理类必须实现接口,底层是采用反射机制执行
    • CGLIB实现动态代,采用继承代理实现类的方式,底层是采用ASM(字节码)生成子类

    JDK动态代理实现原理

    • 拼接java 源码
    • 编译为 class 文件
    • 使用类加载器将class 文件读取到程序中
    • JDK的动态代理,走拦截回调,通过实现接口生成动态代理类,使用反射技术执行目标方法

    CGLIB代理实现原理

    • 通过ASM字节码技术生成class 文件
    • 使用类加载器将class 文件读取到程序中
    • 采用FastClass 机制调用目标方法
    • CGLIB 动态代理采用集成的方式生成代理类,底层通过ASM 字节码技术实现
    • FastClass 会将我们目标对象下所有的方法生成对应索引标记,直接根据索引标记调用目标方法

    应用案例

    • 小朋友要吃糖,他只能自己去找糖,撕开糖纸,在把糖吃进嘴里,这时候小朋友就会想,要是能有人帮我把糖拿过来,撕开糖纸,把糖塞进我嘴里多好。
      这就是代理模式,让别人把你做事

    实现案例

    • 被代理对象
    /**
     * 被代理对象
     *
     * @author ext.liuyan10
     * @date 2021/2/5 14:34
     */
    public class User {
        public void test() {
            System.out.println("小朋友:糖真甜");
        }
    }
    
    

    静态代理

    • 代理对象 UserProxy
    /**
     * 代理对象
     *
     * @author ext.liuyan10
     * @date 2021/2/5 13:38
     */
    public class UserProxy implements UserApi {
        private User user;
    
        public UserProxy(User user) {
            this.user = user;
        }
    
        @Override
        public void test() {
            System.out.println("将糖找来");
            System.out.println("撕开糖纸,喂给小朋友");
            user.test();
        }
    }
    
    
    • 调用代理对象 TestApp
    /**
     * @author liunian
     * @date 2021/2/5 13:42
     */
    public class TestApp {
    
        public static void main(String[] args) {
            User user = new User();
            UserProxy userProxy = new UserProxy(user);
            userProxy.test();
        }
    }
    

    动态代理

    CGLIB动态代理

    • 对被代理对象无要求,可以是接口,也可以是具体类

    • 引入依赖

      <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>3.2.10</version>
      </dependency>
    
    • 生成代理对象(可多次调用生成不同代理对象)
    /**
     * 生成动态代理对象
     *
     * @author liunian
     * @date 2021/2/5 14:35
     */
    public class UserCglibInvocation implements MethodInterceptor {
        private Object target;
    
        public UserCglibInvocation(Object target) {
            this.target = target;
        }
    
        public Object getProxyInstance() {
            //工具类
            Enhancer en = new Enhancer();
            //设置父类
            en.setSuperclass(target.getClass());
            //设置回调函数
            en.setCallback(this);
            //创建子类代理对象
            return en.create();
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("将糖找来");
            System.out.println("撕开糖纸,喂给小朋友");
            Object invoke = method.invoke(target);
            return invoke;
        }
    }
    
    
    • 调用方法
    /**
     * @author liunian
     * @date 2021/2/5 13:42
     */
    public class TestApp {
    
        public static void main(String[] args) {
            User user = new User();
            UserCglibInvocation userInvocation = new UserCglibInvocation(user);
            User proxyInstance = (User) userInvocation.getProxyInstance();
            proxyInstance.test();
        }
    }
    
    
    JDK动态代理
    • 要求被代理对象是一个接口并且以被实现

    • 被代理对象 UserApi

    /**
     * 被代理对象 
     *
     * @author liunian
     * @date 2021/2/5 13:39
     */
    public interface UserApi {
        void test();
    }
    
    • 被代理对象实现 UserImpl
    /**
     * 被代理对象实现
     *
     * @author liunian
     * @date 2021/2/5 13:36
     */
    public class UserImpl implements UserApi{
        @Override
        public void test() {
            System.out.println("小朋友:糖真甜");
        }
    }
    
    • 生成代理对象(可多次调用生成不同代理对象)
    /**
     * 生成代理对象
     *
     * @author ext.liuyan10
     * @date 2021/2/5 14:03
     */
    public class UserInvocation implements InvocationHandler {
    
        Object target;
    
        public UserInvocation(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("将糖找来");
            System.out.println("撕开糖纸,喂给小朋友");
            Object invoke = method.invoke(target);
            return invoke;
        }
    }
    
    
    • 调用方法
    /**
     * @author liunian
     * @date 2021/2/5 13:42
     */
    public class TestApp {
        public static void main(String[] args) {
            UserApi user = new UserImpl();
            UserInvocation userInvocation = new UserInvocation(user);
            UserApi userApi = (UserApi) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), userInvocation);
            userApi.test();
        }
    }
    
    • 调用结果
    Connected to the target VM, address: '127.0.0.1:51870', transport: 'socket'
    将糖找来
    撕开糖纸,喂给小朋友
    小朋友:糖真甜
    Disconnected from the target VM, address: '127.0.0.1:51870', transport: 'socket'
    
    Process finished with exit code 0
    
    

    相关文章

      网友评论

          本文标题:Java 代理模式

          本文链接:https://www.haomeiwen.com/subject/ufkfzctx.html