zoukankan      html  css  js  c++  java
  • 【结构型】- 代理模式

    代理模式的定义:

      为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

    代理模式可以分为三种:静态代理,动态代理,cglib动态代理。

    静态代理

    服务接口

    package com.java.pattern.proxy.staticdemo;
    
    public interface UserService {
        void eat();
    }

    服务具体实现(委托类)

    package com.java.pattern.proxy.staticdemo;
    
    public class UserServiceImpl implements UserService {
        @Override
        public void eat() {
            System.out.println("感谢上帝,感谢神,我开动了...");
        }
    }

    服务静态代理类

    package com.java.pattern.proxy.staticdemo;
    
    public class UserProxyServiceImpl implements UserService {
        
        private UserService userService;
    
        public UserProxyServiceImpl(UserService userService) {
            this.userService = userService;
        }
        
        @Override
        public void eat() {
            System.out.println("先点外卖.....");
            userService.eat();
            System.out.println("清理外卖.....");
        }
    
    }

    测试类

    package com.java.pattern.proxy.staticdemo;
    
    public class Ctest01 {
        public static void main(String[] args) {
            UserService userService = new UserServiceImpl();// 使用静态代理,在不改变eat()方法代码的前提下,增强功能(添加额外的功能服务)
            userService = new UserProxyServiceImpl(userService);
            userService.eat();
        }
    }

    测试结果:

    先点外卖.....
    感谢上帝,感谢神,我开动了...
    清理外卖.....

    优点:

    • 在不改变委托类代码的前提下,为委托类添加额外的功能。

    缺点:

    • 代理类和委托类需要实现同一接口。
    • 一个代理类只能代理一个服务,这就导致我们需要为每一个服务都创建代理类。
    • 委托类实现的接口,一旦发生改变,代理类也要修改代码。

    jdk动态代理

      JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例,  生成目标类的代理对象。

    动态代理类

    public class DynamicProxyService implements InvocationHandler {
        private Object target;
    
        public DynamicProxyService(Object target) {
            this.target = target;
        }
    
        public Object getProxyInstance() {
            return Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("代理类[DynamicProxyService] before doSomething...");
            Object res = method.invoke(target, args);
            System.out.println("代理类[DynamicProxyService] after doSomething...");
            return res;
        }
    }

    代理的目标对象:接口的实现类

    public interface TargetService {
    
        String doSomething(String params);
        
    }
    public class TargetServiceImpl implements TargetService {
    
        @Override
        public String doSomething(String params) {
            System.out.println("[TargetServiceImpl]doSomething..."); return null; } }

    代理的目标对象:类的继承类(子类)

    public class TargetClass {
    
        /**
         * 普通方法
         */
        public void doSomething() {
            System.out.println("[TargetClass]doSomething...");
        }
    
        /**
         * final方法
         */
        public final void finalFunction() {
            System.out.println("[TargetClass]finalFunction...");
        }
        
    }
    public class TargetSubClass extends TargetClass {
    
        @Override
        public void doSomething() {
            System.out.println("[TargetSubClass]doSomething...");
        }
    
    }

    测试类:

    public class Ctest01 {
    
        public static void main(String[] args) {
            testJDKDynamicProxy();
        }
    
        public static void testJDKDynamicProxy() {
            System.out.println("---> 代理对象:接口的实现类");
            // 目标类
            TargetService targetService = new TargetServiceImpl();
            // 代理类
            DynamicProxyService dynamicProxyService = new DynamicProxyService(targetService);
            // 获取代理对象
            targetService = (TargetService)dynamicProxyService.getProxyInstance();
            targetService.doSomething("params");
            System.out.println("----------------------------------------------------------------");
            System.out.println("---> 代理对象:继承类");
            // 目标类
            TargetClass targetClass = new TargetSubClass();
            // 代理类
            dynamicProxyService = new DynamicProxyService(targetClass);
            // 获取代理对象
            targetClass = (TargetClass) dynamicProxyService.getProxyInstance();
            targetClass.doSomething();
        }
    
    }

    测试结果:

    ---> 代理对象:接口的实现类
    代理类[DynamicProxyService] before doSomething...
    [TargetServiceImpl]doSomething...
    代理类[DynamicProxyService] after doSomething...
    ----------------------------------------------------------------
    ---> 代理对象:继承类
    Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy1 cannot be cast to com.design.pattern.proxy.target.TargetClass
        at com.design.pattern.proxy.Ctest01.testJDKDynamicProxy(Ctest01.java:43)
        at com.design.pattern.proxy.Ctest01.main(Ctest01.java:15)

    优点:

    • 在不改变委托类代码的前提下,为委托类添加额外的功能。
    • 代理类无需和委托类实现同一接口。
    • 一个代理类能够代理所有委托类

    缺点:

    • 委托类必须要实现某一接口或继承某一父类

    cglib动态代理

      JDK实现动态代理需要目标类实现某一接口,对于没有实现任何接口的类,该如何实现动态代理呢,这就需要CGLib了,CGLIB(Code Generation Library)是一个代码生成的类库。采用了非常底层的字节码技术,其原理是通过字节码技术在运行时为指定类创建一个子类对象,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的目标类,以及目标类中的final方法进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。

    委托类

    public class TargetClass {
    
        /**
         * 普通方法
         */
        public void doSomething() {
            System.out.println("[TargetClass]doSomething...");
        }
    
        /**
         * final方法
         */
        public final void finalFunction() {
            System.out.println("[TargetClass]finalFunction...");
        }
    
    }

    cglib代理类

    package com.design.pattern.proxy.cglibmode;

    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;

    import java.lang.reflect.Method;

    public class CglibProxyService implements MethodInterceptor {

    private Object target;

    public CglibProxyService(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[] args, MethodProxy methodProxy) throws Throwable {
    System.out.println("cglib代理类[CglibProxyService] before doSomething...");
    Object res = method.invoke(target, args);
    System.out.println("cglib代理类[CglibProxyService] after doSomething...");
    return res;
    }
    }

    测试类

    package com.design.pattern.proxy;
    
    import com.design.pattern.proxy.cglibmode.CglibProxyService;
    import com.design.pattern.proxy.jdkmode.DynamicProxyService;
    import com.design.pattern.proxy.staticmode.ProxyService;
    import com.design.pattern.proxy.target.TargetClass;
    import com.design.pattern.proxy.target.TargetService;
    import com.design.pattern.proxy.target.TargetServiceImpl;
    import com.design.pattern.proxy.target.TargetSubClass;
    
    public class Ctest01 {
    
        public static void main(String[] args) {
            testCglibProxy();
        }
    
        public static void testCglibProxy() {
            // 目标类
            TargetClass targetClass = new TargetClass();
            // 代理类
            CglibProxyService cglibProxyService = new CglibProxyService(targetClass);
            // 获取代理对象
            targetClass = (TargetClass)cglibProxyService.getProxyInstance();
            targetClass.doSomething();
            // 测试cglib动态代理是否能代理final方法
            targetClass.finalFunction();
        }
    
    }

    测试结果如下:

    cglib代理类[CglibProxyService] before doSomething...
    [TargetClass]doSomething...
    cglib代理类[CglibProxyService] after doSomething...
    [TargetClass]finalFunction...

    优点:

    • 在不改变委托类代码的前提下,为委托类添加额外的功能。
    • 代理类无需和委托类实现同一接口。
    • 一个代理类能够代理所有委托类
    • 相比于JDK动态代理,委托类无需要实现某一接口或继承某一父类。

    缺点:

    • 委托类不能是final类,因为final类无法被继承。
  • 相关阅读:
    生成日期列表的函数.sql
    Archlinux下启用Thinkpad功能键
    使用临时表进行编号重排的处理示例.sql
    行值动态变化的交叉报表处理示例.sql
    工作日处理函数(标准节假日).sql
    字符串在编号查询中的应用示例及常见问题.sql
    分段更新函数.sql
    TypeMembersToIL.cs
    排序规则在拼音处理中的应用.sql
    text与image字段转换处理示例.sql
  • 原文地址:https://www.cnblogs.com/517cn/p/10878118.html
Copyright © 2011-2022 走看看