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实现

  • 相关阅读:
    如何解压.bz2文件包
    Typecho中的gravatar头像无法加载
    整理的mysql优化内容
    PHP常用的一些正则表达式
    git log --stat常用命令
    Linux查找含有某字符串的所有文件
    linux下如何查看chm文件
    linux访问windows共享文件夹的方法
    typecho除了首页其他大部分网页404怎么办?
    Windows在当前目录打开cmd
  • 原文地址:https://www.cnblogs.com/zh-ch/p/12882385.html
Copyright © 2011-2022 走看看