代理模式

2020-03-10  本文已影响0人  lclandld

一、代理模式的概念

就是为目标对象提供另外一种访问方式,通过访问代理对象来间接访问目标对象。

优点是:
缺点是:

二、代理模式的分类

image.png

三、静态代理

需要定义三个类(接口、目标对象、代理对象),目标对象和代理对象同时实现接口,代理对象中维护一个目标对象的引用,并追加额外的功能

3.1、静态代理的UML图
image.png
3.2、静态代理的简单DEMO
/**
 * @author lichunlan
 * @description 接口
 * @since 2020-03-09
 */
public interface Subject {
     void request();
 }

/**
 * @author lichunlan
 * @description 目标对象
 * @since 2020-03-09
 */
public class RealSubject implements Subject {

    public void request() {
        System.out.println("这个是真实目标对象要处理的事情.......");
    }
}
/**
 * @author lichunlan
 * @description 代理对象
 * @since 2020-03-09
 */
public class Proxy implements Subject {
    public RealSubject realSubject;

    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    public void request() {
        preRequest();
        //目标对象的逻辑
        realSubject.request();
        postRequest();
    }

    public void preRequest(){
        System.out.println("目标方法之前追加的功能.......");
    }
    public void postRequest(){
        System.out.println("目标方法之后追加的功能.......");
    }
}
public class Main {
    public static void main(String[] args) {
        Proxy proxy = new Proxy(new RealSubject());
        proxy.request();

    }
}
优点:可以在不修改目标对象的情况下追加新的功能。
缺点:当接口中添加新的方法之后,目标对象和代理对象都要进行维护。

当代理方法越多,重复逻辑越多,前后执行的逻辑可能大部分都是一样的,于是就有了动态代理

四、动态代理

动态代理就是动态的创建代理类的技术,这样代理类就不需要手动实现接口了。
动态代理又分为JDK动态代理和CGLIB动态代理。

4.1、JDK动态代理
4.1.1 JDK动态代理主要点
4.1.2 JDK动态代理简单DEMO
/**
 * @author lichunlan
 * @description 接口
 * @since 2020-03-09
 */
public interface Subject {
     void request();
 }

/**
 * @author lichunlan
 * @description 目标对象
 * @since 2020-03-09
 */
public class RealSubject implements Subject {

    public void request() {
        System.out.println("这个是真实目标对象要处理的事情.......");
    }
}
/**
 * @author lichunlan
 * @description JDK动态代理
 * @since 2020-03-09
 */
public class JDKProxySubject implements InvocationHandler {
    private  RealSubject realSubject;

    public JDKProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        preRequest();
        Object result = null;
        //动态反射方法
        result = method.invoke(realSubject, args);
        postRequest();
        return result;
    }

    public void preRequest(){
        System.out.println("JDK动态代理目标方法之前追加的功能.......");
    }
    public void postRequest(){
        System.out.println("JDK动态代理目标方法之后追加的功能.......");
    }
}
public class Main {
    public static void main(String[] args) {
        //目标对象
        RealSubject realSubject = new RealSubject();
        JDKProxySubject jdkProxySubject = new JDKProxySubject(realSubject);
        //给目标对象创建代理对象
        Subject subject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class}, jdkProxySubject);
        subject.request();

    }
}
/**
 * @author lichunlan
 * @description 接口
 * @since 2020-03-09
 */
public interface Subject {
    void request();
    void request1();
    void request2();
    void request3();
    void request4();
    void request5();
    void request6();
    void request7();
    void request8();
 }

/**
 * @author lichunlan
 * @description 目标对象
 * @since 2020-03-09
 */
public class RealSubject implements Subject {

    public void request() {
        System.out.println("这个是真实目标对象要处理的事情.......");
    }

    public void request1() {
        System.out.println("这个是真实目标对象1要处理的事情.......");
    }

    public void request2() {
        System.out.println("这个是真实目标对象2要处理的事情.......");
    }

    public void request3() {
        System.out.println("这个是真实目标对象3要处理的事情.......");
    }

    public void request4() {
        System.out.println("这个是真实目标对象4要处理的事情.......");
    }

    public void request5() {
        System.out.println("这个是真实目标对象5要处理的事情.......");
    }

    public void request6() {
        System.out.println("这个是真实目标对象6要处理的事情.......");
    }

    public void request7() {
        System.out.println("这个是真实目标对象7要处理的事情.......");
    }

    public void request8() {
        System.out.println("这个是真实目标对象8要处理的事情.......");
    }
}

/**
 * @author lichunlan
 * @description
 * @since 2020-02-26
 */
public class Main {
    public static void main(String[] args) {
        //目标对象
        RealSubject realSubject = new RealSubject();
        //JDK代理对象
        JDKProxySubject jdkProxySubject = new JDKProxySubject(realSubject);
        //给目标对象创建代理对象
        Subject subject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class}, jdkProxySubject);
        subject.request();
        subject.request1();
        subject.request2();
        subject.request3();
        subject.request4();
        subject.request5();
        subject.request6();
        subject.request7();
        subject.request8();
    }
}
4.2、CGLIB动态代理
4.2.1 CGLIB动态代理主要点
4.2.2 CGLIB动态代理简单DEMO

这种代理方式是为了解决目标对象并没有实现任何接口的时候,使用这种方式生成一个子类对象从而实现对目标对象功能的扩展

/**
 * @author lichunlan
 * @description 目标对象
 * @since 2020-03-09
 */
public class RealSubject{

    public void request() {
        System.out.println("这个是真实目标对象要处理的事情.......");
    }
}

/**
 * @author lichunlan
 * @description CGLIB动态代理(自定义MethodInterceptor)
 * @since 2020-03-09
 */
public class CglibProxySubject implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();

    /**
     * 通过字节码技术生成CGLIB动态代理的代理对象
     * @param clazz  目标对象
     * @return
     */
    public Object getProxy(Class clazz){
        //继承被代理类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通过字节码技术动态生成代理对象
        return enhancer.create();
    }

    /**
     *
     * @param o  cglib生成的代理对象
     * @param method  被代理对象方法
     * @param objects 方法入参
     * @param methodProxy 代理方法
     * @return
     * @throws Throwable
     */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        preRequest();
        Object object = null;
        object = methodProxy.invokeSuper(o, objects);
        postRequest();
        return object;
    }

    public void preRequest(){
        System.out.println("CGLIB动态代理目标方法之前追加的功能.......");
    }
    public void postRequest(){
        System.out.println("CGLIB动态代理目标方法之后追加的功能.......");
    }
}

/**
 * @author lichunlan
 * @description
 * @since 2020-02-26
 */
public class Main {
    public static void main(String[] args) {
        CglibProxySubject proxy = new CglibProxySubject();
        //通过生成子类的方式创建代理类
        RealSubject realSubject = (RealSubject)proxy.getProxy(RealSubject.class);
        realSubject .request();
    }
}

五、CGLIB动态代理和JDK动态代理的比较

六 、应用场景

既然动态代理模式是采用的反射或者字节码动态生成代理类,那下篇文章我将把反射的原理和字节码的原理学习一遍,并进行记录。因为反射在源码中是一个非常重要的概率

参考

慕课网课程"探秘Spring AOP"

上一篇 下一篇

猜你喜欢

热点阅读