目录

  • 简介
  • 包含角色
  • JDK Proxy UML类图
  • java实现(JDK Proxy)
  • JCgLib UML类图
  • java实现(CgLib方式)
  • 原理分析
  • 优缺点

1. 简介

给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用,在 AOP实现、拦截器、中介、黄牛、媒婆等应用场景中使用,


2. 包含角色

2.1 抽象主题角色(CgLib方式没有该角色)

一般使用接口或者抽象类来实现

2.2 真实主题角色

被代理的角色

2.3 动态代理主题角色

代理真实角色,代理真实角色后一般会做一些附属的操作

2.4 实现方式

  • JDK Proxy
  • Cglib方式

3. JDK Proxy实现方式UML类图

设计模式---动态代理模式

4. java实现(JDK Proxy)

4.1 抽象主题角色

/**
 * @program: proxy
 * @description: 抽象主题角色
 * @author: chengqj
 * @create: 2018-07-27 10:18
 **/
public interface Person {
    void findLove();
}

4.2 真实主题角色

/**
 * @program: proxy
 * @description: 具体主题角色
 * @author: chengqj
 * @create: 2018-07-27 09:23
 **/
public class ChengqjPerson implements Person {

    @Override
    public void findLove() {
        System.out.println("chengqj 找对象");
    }
}

4.3 动态代理主题角色

/**
 * @program: proxy
 * @description: jdk方式的动态代理类
 * @author: chengqj
 * @create: 2018-07-27 10:18
 **/
public class DynamicProxy implements InvocationHandler {
    private Object target;

    public DynamicProxy(Object obj) {
        this.target = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前期物色");
        Object proxyObj = method.invoke(target, args);
        System.out.println("后续跟踪");
        return proxyObj;
    }
}

4.4 JDK Proxy代理测试

/**
 * @program: proxy
 * @description: 动态代理测试类
 * @author: chengqj
 * @create: 2018-07-27 10:22
 **/
public class DynamicProxyTest {
    public static void main(String[] args) {
        //ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
        //Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
        //InvocationHandler h:指定动态代理类,执行目标对象的方法时,会触发事件处理器的方法
        Person proxyPerson = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),
                new Class[]{Person.class}, new DynamicProxy(new ChengqjPerson()));
        System.out.println(proxyPerson.getClass());
        proxyPerson.findLove();
    }
}

5. CgLib实现方式UML类图

设计模式---动态代理模式


6. java实现(CgLib方式)

6.1 具体主题角色

/**
 * @program: proxy
 * @description: 具体主题角色
 * @author: chengqj
 * @create: 2018-07-27 09:23
 **/
public class ChengqjPerson {

    public void findLove() {
        System.out.println("chengqj 找对象");
    }
}

6.2 动态代理主题角色

/**
 * @program: proxy
 * @description: cglib的代理类
 * @author: chengqj
 * @create: 2018-07-27 11:42
 **/
public class CglibProxy implements MethodInterceptor {
    public Object getInstance(Class<?> clazz) {
        Enhancer enhancer = new Enhancer();
        //要把哪个设置为即将生成的新类父类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return  enhancer.create();
    }

    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("前期物色");
        methodProxy.invokeSuper(object,args);
        System.out.println("后期跟踪");
        return null;
    }
}

6.3 cglib测试类

CglibProxy proxy = new CglibProxy();
ChengqjPerson personProxy = (ChengqjPerson)proxy.getInstance(ChengqjPerson.class);
personProxy.findLove();

7. 原理分析

7.1 JDK Proxy代理

1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取
2、JDK Proxy类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口
3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)
4、编译新生成的Java代码.class
5、再重新加载到JVM中运行
以上这个过程就叫字节码重组

7.2 Cglib代理

非接口类实现动态代理,采用非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑

8. 优缺点

8.1 优点:

不用去关心被代理的类到底是怎样的,可以与被代理的类完全解耦,从而灵活的运用到不同的应用场景中

8.2 缺点

JDK Proxy:

  1. 被代理的类必须是接口,不然会报
    Exception in thread “main” java.lang.IllegalArgumentException:com.chengqj.dynamic.proxy.ChengqjPerson is not an interface
  2. 动态生成的代理类注定有一个共同的父类proxy(com.sun.proxy.$Proxy0)
    CgLib
    对于final修饰的类或者方法无法进行代理,由于cglib是采用动态创建子类的方式进行代理

相关文章: