zoukankan      html  css  js  c++  java
  • 设计模式(一)--代理模式

    设计模式是java基础中很重要的一部分,设计模式说白了就是以前的人总结出的套路,就像小说中那些武功秘籍、内功心法一样

    设计模式分为三大类:

      1、创建型模式(5种):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式

      2、结构型模式(7种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

      3、行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式

    中介者模式、解释器模式

      设计模式不应该死记硬背、更应该去融会贯通,应用到项目中,可以通过查看框架或者一些优秀开源项目得到启发

    本文讲的是代理模式,因为要写关于AOP的随笔了,代理是跳不过去的,所以还是单独写一下吧,方便自己理解、复习

    代理模式

      生活中有很多代理的例子,很多职业都会有代理(微商、保险等),又或者是一个明星,他的经纪人也是代理,虽然这个代理有时很坑爹。

    。。又或者是Spring AOP,代理是一种思想,不只是存在Java

    定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用

    1、静态代理

    SellCar.java为共同接口

    public interface SellCar {
        void sellCar();
    }

    SellCarImpl.java目标对象

    public class SellCarImpl implements SellCar{
        @Override
        public void sellCar() {
            System.out.println("selll car");
        }
    }

    SellCarProxy.java代理类

    public class SellCarProxy implements SellCar{
    
        private SellCar sellCar;
    
        @Override
        public void sellCar() {
            System.out.println("sell car proxy start");
            if (null == sellCar) {
                sellCar = new SellCarImpl();
            }
            sellCar.sellCar();
            System.out.println("sell car proxy end");
        }
    }

    SellCarTest.java测试类

    public class SellCarTest {
    
        public static void main(String[] args) {
            SellCar sellCar = new SellCarProxy();
            sellCar.sellCar();
        }
    }

    结果:

    sell car proxy start
    selll car
    sell car proxy end

    缺点:

      目标对象要创建好,作为代理类的内部属性。一个target对应一个proxy,这样如果需要代理的对象很多,难道就要写很多proxy吗?接口内

    方法改了,target对象和proxy对象都要修改。如果我们提前不知道目标对象是什么,这个都是静态代理存在的问题

    2、动态代理

    动态代理不关心target对象,而是在运行期间生成proxy

    2.1).jdk动态代理

    jdk自带的,不需要第三方jar包,使用简单但相对功能较弱

    SellCarProxy.java

    @AllArgsConstructor    //生成全参构造器
    public class SellCarProxy implements InvocationHandler {
    
        private Object target;
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("sell car proxy start");
            Object o = method.invoke(target, args);
            System.out.println("sell car proxy end");
            return o;
        }
    }

    SellCarTest.java

    public class SellCarTest {
    
        public static void main(String[] args) {
            SellCar sellCar = (SellCar) Proxy.newProxyInstance(
                    SellCarImpl.class.getClassLoader(), SellCarImpl.class.getInterfaces(), new SellCarProxy(new SellCarImpl())
            );
            sellCar.sellCar();
        }
    }

    结果:

    sell car proxy start
    selll car
    sell car proxy end

    注意:

      第一/二个参数,一定是target类,而不是通用接口类,否则会报错:com.sun.proxy.$Proxy0 cannot be cast to com.it.SellCar,因为你

    去获取接口的interface数组啊

      三个参数分别为:加载target的类加载器,target类实现的接口,实现对象

    缺点:

      只能代理实现接口的类,如果没有接口,将无法使用

    2.2).cglib动态代理

      CGLib采用了非常底层的字节码技术,总体性能比JDK自带的动态代理好,且功能十分强大其原理是通过字节码技术为一个类创建子类,并在子

    类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

    首先需要引入jar包

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib-nodep</artifactId>
        <version>3.1</version>
    </dependency>

    SellCarProxy.java

    public class SellCarProxy implements MethodInterceptor {
    
        private Object target;
    
        public Object getTarget(Object object) {
            this.target = object;
            Enhancer enhancer = new Enhancer();
            //设置父类,被代理类(这里是Car.class)
            enhancer.setSuperclass(this.target.getClass());
            enhancer.setCallback(this); // 回调方法
            return enhancer.create();   // 创建代理对象
        }
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("sell car proxy start");
            methodProxy.invokeSuper(o, objects);    //代理类调用父类的方法
            System.out.println("sell car proxy end");
            return null;
        }
    }

    SellCarTest.java

    public class SellCarTest {
    
        public static void main(String[] args) {
            SellCarProxy proxy = new SellCarProxy();
            SellCar sellCar = (SellCarImpl)proxy.getTarget(new SellCarImpl());
            sellCar.sellCar();
        }
    }

    结果:

    sell car proxy start
    selll car
    sell car proxy end

    2.3).ASM:这个不太懂,实现动态代理效率很高

    静态代理和动态代理的区别:

      代理类的创建时间不同,静态代理通常只能代理一个类,而动态代理可以代理多个,运行的时候才知道代理的是什么

      1、静态代理:是直接创建的代码,对其进行编译。代理类的class文件已经存在

      2、动态代理:程序运行过程,由反射机制动态生成

    文章参考:公众号-方志朋-一起学设计模式 - 代理模式

  • 相关阅读:
    npm升级package.json依赖包到最新版本号
    vue中 父子组件的通讯
    vue组件开发
    vue模拟后端获取数据——json-server与express
    vue-cli 2.x 搭建项目
    python socket编程
    python异常处理
    python反射
    python特殊成员函数
    Executor ExecutorService Executors
  • 原文地址:https://www.cnblogs.com/huigelaile/p/10980045.html
Copyright © 2011-2022 走看看