在java静态代理模式这篇博客中我已经说明了,静态代理虽然可以实现我们的需求,但是不满足单一职责,于是我们就要对这一方法做出改进,我们的解决办法就是使用java的动态代理,java有自己的一个代理机制,这个代理机制可以动态实现代理 动态代理和静态代理最根本的区别就是耦合的时期.因为要将新的业务横切到原有业务类中,无论如何都会进行耦合,但是耦合的时期就很关键了,动态代理在运行期间才能确认如何耦合,在运行期间才会生成一个代理对象. 下面是java动态代理的代码实现:
此类是专门用来生成代理对象的类就是一个工厂,用来生成代理对象 /** * 要根据原有业务类和业务对象生成代理对象 * 原有业务类UserServiceImpl 目标类 * 原有业务对象就是UserServiceImpl对象 目标对象 * 解释名词:原有业务类就叫做目标类 * 原有业务对象就叫做目标对象 * @author Administrator * */ public class JDKProxy { /** * 此方法专门用来生成代理对象的类 * 就是一个工厂方法,专门用来生成目标对象所对应的代理对象 * 此方法是一个通用的方法,方法的参数是Object,说明接收任意对象,生成代理对象 * targetObject 可以是UserServiceImpl对象 * 也可以是ProductorServiceImpl对象 * 等... * @param targetObject 目标对象 * @return 代理对象 就是针对targetObject的代理对象 */ public static Object getProxyObject(Object targetObject){ Object proxyObject=null; /** * Proxy类是jdk类库中自带的类 * 其中newProxyInstance方法是一个静态的方法 * 此方法有三个参数 * 参数一:类加载器 任意类都可以获取类加载器,只能获取,本质就是为了定位类路径 * 参数二:Class[] 数组,获取目标对象所对应的类的所有接口 * 要求jdk动态代理,目标类必须有接口,否则无法用jdk生成代理对象 * 代理对象和目标对象是兄弟关系,因为两个对象有共同的接口 * 参数三:必须是InvocationHandler接口对象 * 此方法的本质就是用jdk动态创建出代理类(在运行的时候才动态创建代理类)的 * 字节码,这个字节码就是代理类的字节码,通过代理类的字节码生成代理对象 * 此代理类的字节码一定实现业务接口,并重写了接口方法,在接口方法中调用invoke方法 */ proxyObject=Proxy.newProxyInstance( targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), new TransactionHandler(targetObject)); return proxyObject; } } 这是Proxy.newProxyInstance方法的第三个参数对象,此类实现了InvocationHandler接口,并重写了该接口的Invoke方法,Proxy类的newProxyInstance方法在底层肯定会回调invoke方法,在调用的时候就是耦合的时刻,这样就生成了一个代理对象. public class TransactionHandler implements InvocationHandler { private Object targetObject; public TransactionHandler(Object targetObject){ this.targetObject=targetObject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object returnValue=null; TransactionManager tm=new TransactionManager(); try{ tm.begin(); returnValue=method.invoke(targetObject, args);//执行原有业务 tm.commit(); }catch(Exception e){ tm.rollback(); e.printStackTrace(); } return returnValue; } } 下面是生成的代理对象 final class $Proxy0 extends Proxy implements IUser { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } public final boolean equals(Object paramObject) throws { try { 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 sayHello(String paramString) throws { try { this.h.invoke(this, m3, new Object[] { paramString }); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() throws { try { return (String)this.h.invoke(this, m2, null); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() throws { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName("com.tarena.core.IUser").getMethod("sayHello", new Class[] { Class.forName("java.lang.String") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } }从这个代理类中可以看出来,此代理对象确实回调了invoke方法.(如果对于策略模式研究的深入的话这就不难理解了). 其实还有一种动态代理的方式那就是使用第三方工具,cglib,这个代理方式要比java自带的代理机制要强大,因为java动态代理必须有使用前提,那就是目标对象必须要继承自某一接口,但是cglib则没有这个限制,对于cglib的使用我会在下篇博客中具体描述. 对java动态代理的总结: 动态代理总结: 1.原有业务功能没有被修改,新业务功能也添加了,遵守了开闭原则 2.原有的业务类,新功能的业务类都是独立类,遵守单一职责 3.静态代理类是由程序员创建的,动态代理类是由工具创建的(jdk,cglib) 4.每一个业务类都对应至少一个静态代理类,编译期间确定代理类,开发效率低,执行效率高 每一个业务类对应一个动态代理类,运行期间确定代理类,开发效率高,执行效率低 动态代理有缓存,存储代理类字节码,效率也不会太低 5.动态代理和静态代理的代理对象还是一个都不能少 6.用动态代理和静态代理,在没有特殊处理的前提下,只能给业务中的所有 方法横切新功能 7.静态代理是用静态代理类把原有业务和新业务耦合在一起 动态代理是用动态代理类回调指定接口的方法, 用指定接口的子实现把原有的业务和新业务耦合在一起 8.静态代理类和动态代理类都要实现对应的业务接口 9.通过jdk或cglib生成代理类,通过代理类实例化代理对象