通过使用动态代理,我们可以通过在运行时,动态生成一个持有RealObject、并实现代理接口的Proxy,同时注入我们相同的扩展逻辑。哪怕你要代理的RealObject是不同的对象,甚至代理不同的方法,都可以动过动态代理,来扩展功能。简单理解,动态代理就是我们上面提到的方案一,只不过这些proxy的创建都是自动的并且是在运行期生成的。
JDK动态代理
基本实现
使用动态代理,需要将待扩展的功能类实现InvocationHandler ,并且需要将扩展代码写在该类的中
public class DynamicProxyHandler implements InvocationHandler { private Object realObject; public DynamicProxyHandler(Object realObject) { this.realObject = realObject; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //代理扩展逻辑 System.out.println("proxy do"); return method.invoke(realObject, args); } }
调用方式
public static void main(String[] args) { RealObject realObject = new RealObject(); Action proxy = (Action) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Action.class}, new DynamicProxyHandler(realObject)); proxy.doSomething(); }
Proxy.newProxyInstance
传入的是一个ClassLoader
, 一个代理接口,和我们定义的handler,返回的是一个Proxy的实例。- 代理三要素
真实对象:RealObject,代理接口:Action,代理实例:Proxy
输入 RealObject、Action,返回一个Proxy
源码实现
private static final Class<?>[] constructorParams = { InvocationHandler.class }; public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Class<?> cl = getProxyClass0(loader, intfs); ... final Constructor<?> cons = cl.getConstructor(constructorParams); if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); }
整体流程就是:
1、生成代理类Proxy的Class对象。
2、如果Class作用域为私有,通过 setAccessible 支持访问
3、获取Proxy Class构造函数,创建Proxy代理实例。
生成的代理类
package com.sun.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Action { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler var1) throws { //将handler对象赋值给超类Proxy中的h super(var1); } public final void doSomething() throws { try { //利用Proxy中的h,调用我们定义的invoke方法 super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } ... static { try { ... m3 = Class.forName("Action").getMethod("doSomething", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
步骤
编写业务类,不实现任何接口
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency>
public class HelloService { public HelloService() { System.out.println("HelloService构造"); } /** * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的 */ final public String sayOthers(String name) { System.out.println("HelloService:sayOthers>>"+name); return null; } public void sayHello() { System.out.println("HelloService:sayHello"); } }
自定义MethodInterceptor,覆盖cglib的MethodInterceptor类,并重写intercept方法
public class CGLibProxyInterceptor implements MethodInterceptor { /** * sub:cglib生成的代理对象 * method:被代理对象方法 * objects:方法入参 * methodProxy: 代理方法 */ @Override public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("=====插入前置通知====="); //调用原始类的被拦截到的方法 Object o = methodProxy.invokeSuper(sub, objects); System.out.println("=====插入后置通知====="); return o; } }
- obj表示增强的对象,即实现这个接口类的一个对象;
- method表示要被拦截的方法;
- args表示要被拦截方法的参数;
- proxy表示要触发父类的方法对象;
调用类
public class Client { public static void main(String[] args) { // 代理类class文件存入本地磁盘方便我们反编译查看源码 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "F:\\work"); // 通过CGLIB动态代理获取代理对象的过程 Enhancer enhancer = new Enhancer(); // 设置产生的代理对象的父类 enhancer.setSuperclass(HelloService.class); // 设置CallBack接口的实例 enhancer.setCallback(new CGLibProxyInterceptor()); // 使用默认无参数的构造函数创建目标对象 HelloService proxy= (HelloService)enhancer.create(); // 通过代理对象调用目标方法 proxy.sayHello(); } }
- 字节码生成
- 字节码查看
从代理对象反编译源码可以知道,代理对象继承于HelloService,拦截器调用intercept()方法,
intercept()方法由自定义MyMethodInterceptor实现,所以,最后调用MyMethodInterceptor中
的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。