动态代理
一、静态代理
代理的背后一般至少有一个实际对象,代理的外部功能和实际对象一般是一样的,
用户与代理打交道,不直接接触实际对象。代理存在的价值:
1)节省成本比较高的实际对象创建开销,按需延迟加载,创建代理时
并不正真创建实际对象,而只是保存实际对象的地址,在需要时再加载或者创建。
2)执行权限检查,代理检查权限后再调用实际对象。
3)屏蔽网络的差异性和复杂性,代理在本地,而实际对象在其他服务器上,调用
本地代理时,本地代理请求其他服务器。
静态代理示例:
public class SimpleStaticProxy { //服务接口 static interface IService { void sayHello(); } //服务类 static class RealService implements IService { @Override public void sayHello() { System.out.println("hi"); } } //代理类 static class TraceProxy implements IService { private IService realService; public TraceProxy(IService realService) { this.realService = realService; } @Override public void sayHello() { System.out.println("Start say hi"); realService.sayHello(); System.out.println("End say hi"); } } public static void main(String[] args) { RealService service = new RealService(); TraceProxy traceProxy = new TraceProxy(service); traceProxy.sayHello(); } }
静态代理缺陷:如果每个类都需要代理,我们需要为每个类都创建代理类,
实现所有接口,这个工作量相当大。
二、Java SDK代理
所谓动态代理,代理类是动态生成的。
1.用法
public class SimpleJDKDynamicProxy { interface IService { void sayHello(); void sayGoodBye(); } static class RealService implements IService { @Override public void sayHello() { System.out.println("hi"); } @Override public void sayGoodBye() { System.out.println("GoodBye world!"); } } static class SimpleInvocateHandler implements InvocationHandler { private Object realObj; public SimpleInvocateHandler(Object realObj) { this.realObj = realObj; } /** * @param proxy 表示代理对象本身,注意它不是被代理的对象,这个参数用处不大 * @param method 表示正在被调用的方法 * @param args 表示方法的参数 * */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Start " + method.getName()); Object result = method.invoke(realObj, args); System.out.println("End " + method.getName()); return result; } } public static void main(String[] args) { IService realService = new RealService(); IService proxyService = (IService) Proxy.newProxyInstance(IService.class.getClassLoader(), new Class<?>[]{IService.class}, new SimpleInvocateHandler(realService)); proxyService.sayHello(); proxyService.sayGoodBye(); } }
/** * @param loader 类加载器 * @param interfaces 代理类要实现的接口列表 * @param h 该接口定义了invoke方法,对代理接口所有的方法调用都会转给该方法 * @return 可以转换为interfaces数组中的某个接口类型,注意只能转换为接口不能转换为具体的类 * */ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
2.基本原理
创建proxyService的代码可以用如下的代码代替:
//创建代理类定义,类定义会被缓存 Class<?> proxyCls = Proxy.getProxyClass(IService.class.getClassLoader(), new Class<?>[] { IService.class }); //获取代理类的构造方法 Constructor<?> ctor = proxyCls.getConstructor(new Class<?>[] { InvocationHandler.class }); InvocationHandler handler = new SimpleInvocationHandler(realService); //创建代理类对象 IService proxyService = (IService) ctor.newInstance(handler);
final class $Proxy0 extends Proxy implements SimpleJDKDynamicProxyDemo.IService { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); } public final boolean equals(Object paramObject) { return((Boolean) this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } public final void sayHello() { this.h.invoke(this, m3, null); } public final String toString() { return (String) this.h.invoke(this, m2, null); } public final int hashCode() { return ((Integer) this.h.invoke(this, m0, null)).intValue(); } static { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName( "laoma.demo.proxy.SimpleJDKDynamicProxyDemo$IService") .getMethod("sayHello",new Class[0]); m2 = Class.forName("java.lang.Object") .getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object") .getMethod("hashCode", new Class[0]); } }
三、cglib动态代理
Java SDK动态代理的局限,它只能为接口创建代理,返回的代理对象也只能转换到某个接口类型。
public class SimpleCGLibDemo { static class RealService { public void sayHello() { System.out.println("hello"); } } static class SimpleInterceptor implements MethodInterceptor { @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("start " + method.getName()); Object result = methodProxy.invokeSuper(object, args); System.out.println("end " + method.getName()); return result; } } private static <T> T getProxy(Class<T> cls) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(cls); enhancer.setCallback(new SimpleInterceptor()); return (T) enhancer.create(); } public static void main(String[] args) { RealService proxy = getProxy(RealService.class); proxy.sayHello(); } }
cglib是通过继承实现的,具体原理略。