近期接触了一个项目里面用到了动态代理,自己发现对动态代理的理解还不够深入,于是重新对代理进行了学习。 学习自https://blog.csdn.net/luanlouis/article/details/24589193 动态代理的一部分代码引用自某博客,当时未保存博客地址,故无法给出引用。
定义一个接口
public class Station implements TicketService { @Override public void sellTicket() { System.out.println("\n\t售票.....\n"); } @Override public void inquire() { System.out.println("\n\t问询。。。。\n"); } @Override public void withdraw() { System.out.println("\n\t退票......\n"); } }实现了这个接口
这时如果需要在售票前显示一下金额,直观的解决方式是直接在sellTicket加入一个显示金额的语句
public class Station implements TicketService { @Override public void sellTicket() { System.out.println("\n\t显示金额.....\n"); System.out.println("\n\t售票.....\n"); } @Override public void inquire() { System.out.println("\n\t问询。。。。\n"); } @Override public void withdraw() { System.out.println("\n\t退票......\n"); } }但是这种方式并不合理,因为这个实现类并不是仅仅在此被调用,还会被其他地方使用,直接修改会影响其他程序调用。
这时可以使用静态代理方法 方法的核心是生成一个静态代理类,将原对象通过构造方法传递给代理类,代理对象调用代理类的方法实际上是通过原对象调用原方法。
public class Client { private static final Logger LOGGER = LoggerFactory.getLogger(Client.class); //静态代理 将原对象 通过构造方法 传入到 代理类中,代理对象调用方法 实际是原对象去调用 public static void main(String[] args) { LOGGER.trace("请求参数:content:{}", "1111"); StationProxy stationProxy=new StationProxy(new Station()); stationProxy.sellTicket(); } }新建一个原始类对象,通过构造方法将原始变量赋值给代理类里的Station station属性。代理对象调用代理类中的sellTicket方法。
public class StationProxy implements TicketService { private Station station; public StationProxy(Station station) { this.station = station; } @Override public void sellTicket() { // 1.做真正业务前,提示信息 System.out.println("××××您正在使用车票代售点进行购票,每张票将会收取5元手续费!××××"); // 2.调用真实业务逻辑 station.sellTicket(); // 3.后处理 System.out.println("××××欢迎您的光临,再见!××××\n"); } @Override public void inquire() { station.inquire(); } @Override public void withdraw() { station.withdraw(); } }代理类方法中 通过原始类的对象调用原始类的方法
由上面静态代理可知,实现代理是通过代理类中的原始对象调用原始方法实现的。而JDK动态代理时通过InvocationHandler,由反射实现的。
定义一个接口
public class RealSubject implements Subject { @Override public void rent() { System.out.println("I want to rent my house"); } @Override public void hello(String str) { System.out.println("hello: " + str); } }实现这个接口
public class InvocationHandlerImpl implements InvocationHandler { // 这个就是我们要代理的真实对象 private Object subject; // 构造方法,给我们要代理的真实对象赋初值 public InvocationHandlerImpl(Object subject) { this.subject = subject; } @Override public Object invoke(Object object, Method method, Object[] args) throws Throwable { // 在代理真实对象前我们可以添加一些自己的操作 System.out.println("before rent house"); System.out.println("Method:" + method); // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(subject, args); // 在代理真实对象后我们也可以添加一些自己的操作 System.out.println("after rent house"); return null; } }实现了InvocationHandler接口,并重写invoke方法。
public class ClienDynamic { public static void main(String[] args) { // 我们要代理的真实对象 Subject realSubject = new RealSubject(); // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的 InvocationHandler handler = new InvocationHandlerImpl(realSubject); /* * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象 * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上 */ Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject .getClass().getInterfaces(), handler); System.out.println(subject.getClass().getName()); subject.rent(); subject.hello("world"); } }测试类 动态代理的结果
上面的代码中通过这种方式创建代理对象,并通过代理对象去调用,注意调用的方法是生成的代理类里对应的方法。
try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h});Proxy.newProxyInstance()方法中有一段这个代码,先是把我们自定义的handler 赋值给了代理类,然后新建了代理类的对象返回。
这一步我目前理解是生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码(.class文件),然后用参数里的classLoader加载这个代理类。
然后通过反编译软件可以看到如下代码(以下代码来自于参考博客里的例子,方法名是不一致的)
import com.foo.proxy.Rechargable; import com.foo.proxy.Vehicle; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; /** 生成的动态代理类的组织模式是继承Proxy类,然后实现需要实现代理的类上的所有接口,而在实现的过程中,则是通过将所有的方法都交给了InvocationHandler来处理 */ public final class ElectricCarProxy extends Proxy implements Rechargable, Vehicle { private static Method m1; private static Method m3; private static Method m4; private static Method m0; private static Method m2; public ElectricCarProxy(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } public final boolean equals(Object paramObject) throws { try { // 方法功能实现交给InvocationHandler处理 return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final void rent() throws { try { // 方法功能实现交给InvocationHandler处理 this.h.invoke(this, m3, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final void hello() throws { try { // 方法功能实现交给InvocationHandler处理 this.h.invoke(this, m4, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() throws { try { // 方法功能实现交给InvocationHandler处理 return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() throws { try { // 方法功能实现交给InvocationHandler处理 return (String)this.h.invoke(this, m2, null); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static { try { //为每一个需要方法对象,当调用相应的方法时,分别将方法对象作为参数传递给InvocationHandler处理 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName("com.foo.proxy.Rechargable").getMethod("recharge", new Class[0]); m4 = Class.forName("com.foo.proxy.Vehicle").getMethod("drive", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } }测试类中调用对应的方法,即调用了上面代理类里对应的方法,如:
public final void rent() throws { try { // 方法功能实现交给InvocationHandler处理 this.h.invoke(this, m3, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } }this.h 即由Proxy.newProxyInstance()传递进来的InvocationHandler handler = new InvocationHandlerImpl(realSubject); handler对象。 我们可以看到 代理类继承与Proxy类,ElectricCarProxy extends Proxy,handler属性定义于Proxy类中。
public class Proxy implements java.io.Serializable { private static final long serialVersionUID = -2222568056686623797L; /** parameter types of a proxy class constructor */ private static final Class<?>[] constructorParams = { InvocationHandler.class }; /** * a cache of proxy classes */ private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); /** * the invocation handler for this proxy instance. * @serial */ protected InvocationHandler h;最終this.h.invoke(this, m3, null);其实是调用了InvocationHandlerImpl中的重写的invoke方法。
@Override public Object invoke(Object object, Method method, Object[] args) throws Throwable { // 在代理真实对象前我们可以添加一些自己的操作 System.out.println("before rent house"); System.out.println("Method:" + method); // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(subject, args); // 在代理真实对象后我们也可以添加一些自己的操作 System.out.println("after rent house"); return null; } }方法内部再通过反射,执行原始类里的对应的方法。