Java的动态代理
1.什么是代理?
简单来说,代理就是帮[目标对象]去完成它应该做,但是不想或者不擅长做的事情。
代理在程序的世界里面,主要是为了增强[目标对象]的各种方法。
2.代理模式分为静态代理和动态代理
- 静态代理就是程序员自己编写一个代理类
- 动态代理就是让程序帮忙在运行时动态生成一个代理类
3.动态代理的实现方式分为两种,生成的代理类都是继承了Proxy
- JDK原生实现:
/** * 主要作用就是生成代理类 使用JDK的动态代理实现 它是基于接口实现的 */ public class JDKProxyFactory implements InvocationHandler { //目标对象的引用 private Object target; //通过构造方法将目标对象注入到代理对象中 public JDKProxyFactory(Object target) { super(); this.target = target; } /** * 获取proxy代理类实例 */ public Object getProxy() { //如何生成一个代理类呢? //1、编写源文件 //2、编译源文件为class文件 //3、将class文件加载到JVM中(ClassLoader) //4、将class文件对应的对象进行实例化(反射) // Proxy是JDK中的API类 // 第一个参数:目标对象的类加载器 // 第二个参数:目标对象的接口() // 第二个参数:代理对象的执行处理器 Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); return object; } /** * 重写invoke方法,把method重新invoke到target(传入的类实例)上,然后可以在前后进行方法的额外增强功能 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("这是增强的功能"); // 下面的代码,是反射中的API用法 // 该行代码,实际调用的是[目标对象]的方法 // 利用反射,调用[目标对象]的方法 Object returnValue = method.invoke(target, args); return returnValue; } }
- CGLib实现:
/** * 主要作用就是生成代理类 * 使用CGLib动态代理技术实现 它是基于继承的方式实现的 */ public class CgLibProxyFactory implements MethodInterceptor{ public Object getProxyByCgLib(Class clazz) { // 创建增强器 Enhancer enhancer = new Enhancer(); // 设置需要增强的类的类对象 enhancer.setSuperclass(clazz); // 设置回调函数 enhancer.setCallback(this); // 获取增强之后的代理对象 return enhancer.create(); } /*** * Object proxy:这是代理对象,也就是[目标对象]的子类 * Method method:[目标对象]的方法 * Object[] arg:参数 * MethodProxy methodProxy:代理对象的方法 */ @Override public Object intercept(Object proxy, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable { // 因为代理对象是目标对象的子类 // 该行代码,实际调用的是目标对象的方法 // proxy:代理对象 // 父类目标对象,调用父类目标对象中的方法 System.out.println("这是cglib的代理方法"); // 调用[目标对象]的方法 Object returnValue = methodProxy.invokeSuper(proxy, arg); return returnValue; } }
- 使用
@Test public void testJDKProxy() { //1、创建目标对象 UserService service = new UserServiceImpl(); //2、生成代理对象 JDKProxyFactory proxyFactory = new JDKProxyFactory(service); UserService proxy = (UserService) proxyFactory.getProxy(); //3、调用目标对象的方法 service.saveUser(); System.out.println("==============="); //4、调用代理对象的方法 proxy.saveUser(); } @Test public void testCgLibProxy() { //创建目标对象 UserService service = new UserServiceImpl(); //生成代理对象 CgLibProxyFactory proxyFactory = new CgLibProxyFactory(); UserService proxy = (UserService) proxyFactory.getProxyByCgLib(service.getClass()); //调用目标对象的方法 service.saveUser(); System.out.println("==============="); //调用代理对象的方法 proxy.saveUser(); }
4.总结
1)既然JDK已经帮我们实现了Proxy,为什么还要用第三方库CGLib来实现呢?
从代码里,我们不难发现,JDK的实现方式是有缺陷的,因为要想用这种方式实现代理,【目标对象】必须要有Interface。显然CGLib的实现没有要求【目标对象】有实现的Interface
2)实现原理
ps:可以看出CGLib就算没有要求目标对象类有Interface,它内部也按照它的样子制作了一个Interface出来
因为method.invoke(object, args)传的object必须是和提取出这个method的类是实现了同一个Interface的
因此,Interface对于整个流程来说是必须品,只不过CGLib帮我们在它内部处理了。