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