设计模式(一)--代理模式

设计模式是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、动态代理:程序运行过程,由反射机制动态生成

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

原文地址:https://www.cnblogs.com/huigelaile/p/10980045.html