zoukankan      html  css  js  c++  java
  • 设计模式系列三-代理模式

    代理模式主要有两个目的:

    1、保护被代理对象

    2、增加被代理对象

    静态代理:

    静态代理就是利用代理对象持有被代理对象

    举个栗子:

    public interface Animal {
        void dosomething();
    }
    public class Bird implements Animal {
    
        @Override
        public void dosomething(){
            System.out.println("bird fly");
        }
    }
    public class StaticProxy {
    
        private Animal animal;
        public StaticProxy(Animal animal){
            this.animal = animal;
        }
        public void dosomething(){
            System.out.println("静态代理");
            animal.dosomething();
        }
    
    }
    public class Test2 {
        public static void main(String[] args) {
            Bird bird = new Bird();
            // 静态代理
            StaticProxy staticProxy = new StaticProxy(bird);
            staticProxy.dosomething();
    
        }
    }

    动态代理

    jdk动态代理

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class JDKProxy implements InvocationHandler {
        private Bird bird;
    
        public Object getInstance(Bird bird){
            //生成$Proxy0的class文件,也就是代理类的字节码文件
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
            this.bird = bird;
            Class<? extends Bird> clazz = bird.getClass();
            // 这里生成代理对象
            return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("jdk动态代理");
            before();
            Object invoke = method.invoke(bird, args);
            after();
            return invoke;
        }
        private void before(){
            System.out.println("jdk before");
        }
        private void after(){
            System.out.println("jdk after");
        }
    
    }
    public class Test2 {
        public static void main(String[] args) {
            Bird bird = new Bird();
            // jdk动态代理
            Animal proxy = (Animal) new JDKProxy().getInstance(bird);
            proxy.dosomething();
        }
    }

    代理方法:

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

    newProxyInstance,方法有三个参数:

    loader: 用哪个类加载器去加载代理对象,就是产生的代理类会是这个类的实现类

    interfaces:动态代理类需要实现的接口,会把这里传入的所有方法都增强,都会调用invoke方法

    h:动态代理方法在执行时,会调用h里面的invoke方法去执行,也就是InvocationHandler的实现类,用内部类的方式也行

    Animal proxyDog = (Animal)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动态代理....");
                            method.invoke(target, args);
                            return null;
                        }
                    });

    cglib动态代理

    需要引入cglib包

    <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
    </dependency>
    import net.sf.cglib.core.DebuggingClassWriter;
    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 CglibProxy implements MethodInterceptor {
    
        public Animal getInstance(Class<?> clazz){
            // 输出生成的代理类 方便理解原理
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "c:/");
            // 创建 增强器  类似JDK的proxy类
            Enhancer enhancer = new Enhancer();
            // 设置目标类
            enhancer.setSuperclass(clazz);
            // 设置回调函数  也就是实现了MethodInterceptor接口的类
            enhancer.setCallback(this);
            // 创建代理类
            Animal o = (Animal) enhancer.create();
            return o;
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("cglib动态代理");
            before();
            Object o1 = methodProxy.invokeSuper(o, objects);
            after();
            return o1;
        }
    
        private void before(){
            System.out.println("cglib Proxy before method.");
        }
        private void after(){
            System.out.println("cglib Proxy after method.");
        }
    }
    public class Test2 {
        public static void main(String[] args) {
            // cglib动态代理
            Animal instance = new CglibProxy().getInstance(Bird.class);
            instance.dosomething();
        }
    }

    也可以仿造jdk、cglib的方式自己实现动态代理模式,思路都是动态生成java代理类然后动态加载

    Cglib 采用了 FastClass 机制,它的原理简单来说就是:为代理类和被代理类各生成一个 Class,这个 Class 会为代理类或被代理类的方法分配一个 index(int 类型)。这个 index 当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比 JDK动态代理通过反射调用高

     CGLib 和 JDK 动态代理对比

    1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。
    2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。
    3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法,CGLib 执行效率更高。

    静态代理和动态的本质区别

    1、静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步新增,违背开闭原则。
    2、动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则。
    3、若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码。

    代理模式的优缺点

    使用代理模式具有以下几个优点:

    1、代理模式能将代理对象与真实被调用的目标对象分离。
    2、一定程度上降低了系统的耦合度,扩展性好。
    3、可以起到保护目标对象的作用。
    4、可以对目标对象的功能增强。

    当然,代理模式也是有缺点的:

    1、代理模式会造成系统设计中类的数量增加。
    2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
    3、增加了系统的复杂度

     Spring中的代理模式 Proxy开头的类,AOP实现

  • 相关阅读:
    React在componentDidMount里面发送请求
    React 术语词汇表
    React里受控与非受控组件
    React和Vue等框架什么时候操作DOM
    【LeetCode】79. Word Search
    【LeetCode】91. Decode Ways
    【LeetCode】80. Remove Duplicates from Sorted Array II (2 solutions)
    【LeetCode】1. Two Sum
    【LeetCode】141. Linked List Cycle (2 solutions)
    【LeetCode】120. Triangle (3 solutions)
  • 原文地址:https://www.cnblogs.com/zh-ch/p/12882385.html
Copyright © 2011-2022 走看看