• 【设计模式】【结构型7-1】【代理模式】【动态代理】【静态代理】


    代理模式

    代理 是结构型 通过继承,或者实现相同的接口来进行增强和监控
    经典的使用 spring aop,mybatis dao层

    静态代理

    作用:可以增加功能 而不破坏现有代码结构,一定程度的解耦

    第一步 创建接口

    /***
     * 卖房子
     */
    public interface Sell {
        void sellHouse();
    }
    

    第二步 创建需要代理的对象

    public class PersonSell implements Sell{
        @Override
        public void sellHouse() {
            System.out.println("我卖房子---");
        }
    }
    

    第三步 创建代理对象 使用

    public class ProxySell implements Sell{
        private Sell sell;
        public ProxySell(Sell sell) {
            this.sell = sell;
        }
        @Override
        public void sellHouse() {
            System.out.println("中介联系人");
            sell.sellHouse();
            System.out.println("中介促成交易");
        }
    }
    
        public static void main(String[] args) {
            PersonSell personSell = new PersonSell();
            ProxySell proxySell = new ProxySell(personSell);
            proxySell.sellHouse();
        }
    

    可以看到 调用代理人方法 最终代理人服务被代理的对象 进行了前后包夹 无死角环绕

    动态代理

    jdk动态代理

    1. Interface:对于 JDK 动态代理,目标类需要实现一个 Interface。
    2. InvocationHandler:InvocationHandler 是一个接口,可以通过实现这个接口,定义横切逻辑,再通过反射机制(invoke)调用目标类的代码,在次过程,可能包装逻辑,对目标方法进行前置后置处理。
    3. Proxy:Proxy 利用 InvocationHandler 动态创建一个符合目标类实现的接口的实例,生成目标类的代理对象。
    return Proxy.newProxyInstance(sourceObject.getClass().getClassLoader(), sourceObject.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("-----------我开始代理啦------------");
                    method.invoke(sourceObject, args);
                    return proxy;
                }
            });
    其实整个核心就是这样的 使用Proxy.newProxyInstance 传入类加载器 传入接口 新创建一个处理器 执行 method.invoke 方法 并返回代理对象
    

    展开一下

    public interface Sell2 {
        void sellHouse();
    }
    
    public class PersonSell implements Sell2 {
        @Override
        public void sellHouse() {
            System.out.println("我卖房子---");
        }
    }
    
    public class DynamicSellProxy {
    	//这里就两步 1:用Proxy newProxyInstance 创建一个代理类 用 InvocationHandler 来执行 target的方法
        public Object proxy(Object target){
            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("----动态代理前置----");
                    method.invoke(target,args);
                    System.out.println("----动态代理后置----");
                    return proxy;
                }
            });
        }
    }
    //测试
     public static void main(String[] args) {
            ((Sell2) new DynamicSellProxy().proxy(new PersonSell())).sellHouse();
        }
    

    cjlib动态代理

    1. 使用 JDK 创建代理有一大限制,它只能为接口创建代理实例,而 CgLib 动态代理就没有这个限制。
    2. CgLib 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
    3. CgLib 创建的动态代理对象性能比 JDK 创建的动态代理对象的性能高不少,但是 CGLib 在创建代理对象时所花费的时间却比 JDK 多得多,所以对于单例的对象,因为无需频繁创建对象,用 CGLib 合适,反之,使用 JDK 方式要更为合适一些。同时,由于 CGLib 由于是采用动态创建子类的方法,对于 final 方法,无法进行代理
    public class CGLIBSellProxy {
    
        public Object getProxy(Object target){
            Enhancer enhancer = new Enhancer();
            //设置被代理的class
            enhancer.setSuperclass(target.getClass());
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    System.out.println("--------cjlib 动态代理前置-------");
                    methodProxy.invokeSuper(o, objects);
                    System.out.println("------cjlib 动态代理后置---------");
                    return o;
                }
            });
            return enhancer.create();
        }
    }
    
    ((PersonSell) (new CGLIBSellProxy().getProxy(new PersonSell()))).sellHouse();
    
  • 相关阅读:
    如何在 Visual Studio Code 中使用 Prettier 格式化代码
    redux原理分享
    基于SuperMap iObjects C++之最佳路径分析
    详解vue中中localStorage的使用方法
    Redis的java客户端
    【AIGC调研系列】MiniCPM-Llama3-V2.5模型与GPT-4V对比
    Spring基础元注解@Target、@Retention、@Documented、@Inherited
    SpringBoot+PageHelper+Vue+Element从零开始实现分页功能(包含前后端源码)
    工业智能网关BL110应用之三十二: 如何连接配置阿里云服务器
    【Java】----面向对象
  • 原文地址:https://blog.csdn.net/SHI_IHS/article/details/139994926