Java静态代理
Jdk动态代理
java代理模式
即Proxy Pattern,23种java常用设计模式之一。代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问。
原理:
代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
应用场景:
假设有一组对象都实现同一个接口,实现同样的方法,但这组对象中有一部分对象需要有单独的方法,传统的笨办法是在每一个应用端都加上这个单独的方法,但是代码重用性低,高。
public interface IPerson {//定义代理接口类 public abstract void sleep(); public abstract void eating();}
实现类:
//实现类public class Person implements IPerson{ public void sleep(){ System.out.println("睡觉中!"); } public void eating(){ System.out.println("正在吃饭中!"); }
静态代理类:
public class PersonProxy implements IPerson { private IPerson person; private Logger logger = Logger.getLogger(String.valueOf(PersonProxy.class)); public PersonProxy(Person person) { this.person = person; } @Override public void sleep() { logger.info("开始执行时间: "+ new Date()); person.eating(); logger.info("执行结束时间: "+ new Date()); } @Override public void eating() { logger.info("开始执行时间:"+ new Date()); person.sleep(); logger.info("执行结束时间: "+ new Date()); }}
测试类:
/** * 静态代理 */ @Test public void persontest(){ IPerson proxy = new PersonProxy(new Person()); proxy.eating(); proxy.sleep(); }
静态代理的弊端:
一个代理接口只能服务于一种类型的对象.对于稍大点的项目根本无法胜任.
3 解决方案2-动态代理
在JDK1.3之后加入了可协助开发的动态代理功能.不必为特定对象与方法编写特定的代理对象,使用动态代理,可以使得一个处理者(Handler)服务于各个对象.
一个处理者的类设计必须实现java.lang.reflect.InvocationHandler接口.
通过InvocationHandler接口实现的动态代理只能代理接口的实现类.
动态代理概念及类图
动态代理跟静态代理一个最大的区别就是:动态代理是在运行时刻动态的创建出代理类及其对象。上篇中的静态代理是在编译的时候就确定了代理类具体类型,如果有多个类需要代理,那么就得创建多个。还有一点,如果Subject中新增了一个方法,那么对应的实现接口的类中也要相应的实现这些方法。
动态代理的做法:在运行时刻,可以动态创建出一个实现了多个接口的代理类。每个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接 口的实现。当使用者调用了代理对象所代理的接口中的方法的时候,这个调用的信息会被传递给InvocationHandler的invoke方法。在 invoke方法的参数中可以获取到代理对象、方法对应的Method对象和调用的实际参数。invoke方法的返回值被返回给使用者。这种做法实际上相 当于对方法调用进行了拦截。
类图如下所示:
动态代理实现:
处理者代理类:
public class DynaProxyHandler implements InvocationHandler { private Logger logger = Logger.getLogger(String.valueOf(DynaProxyHandler.class)); private Object target;//被代理对象 public void setTarget(Object target) { this.target = target; } public DynaProxyHandler(IPerson persons) { this.target=persons; } public DynaProxyHandler() { } @Override public Object invoke(Object proxy,Method method,Object[] args) throws Throwable { logger.info("执行开始时间:" + new Date()); // System.out.println(method); Object result = method.invoke(target, args); logger.info("执行结束时间:" + new Date()); return result;//返回method执行结果 }}
生产代理对象的工厂:
/** * 动态代理工厂 */public class DynaProxyFactory { //obj为被代理对象 public static Object getProxy(Object obj){ DynaProxyHandler handler = new DynaProxyHandler(); CjlibProxy cjlibProxy=new CjlibProxy(); handler.setTarget(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler); }}
动态代理测试:
//测试动态代理 @Test public void DynaProxyHandler(){ IPerson person = (IPerson) DynaProxyFactory.getProxy(new Person()); //返回代理类,代理类是JVM在内存中动态创建的,该类实现传入的接口数组的全部接口(的全部方法). person.eating(); person.sleep(); }
将静动态结合测试:
@Test public void agentAndDynaProxyHandler(){ //是我们要代理的真实对象 IPerson persons = (IPerson) new Person(); //我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的 InvocationHandler handler = new DynaProxyHandler(persons); /* * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象 * 第二个参数person1.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上 */ IPerson person = (IPerson) Proxy.newProxyInstance(handler.getClass().getClassLoader(), persons.getClass().getInterfaces(), handler); person.eating(); person.sleep(); }
Cjlib动态代理:
代理类:
public class CjlibProxy implements MethodInterceptor{ private Enhancer enhancer=new Enhancer(); //创建一个方法来完成创建代理对象 public Object createInstance(Class c){ //设置公共类接口 enhancer.setSuperclass(c); enhancer.setCallback(this); return enhancer.create(); //创建代理类对象. } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("===================="); methodProxy.invokeSuper(o,objects); System.out.println("=================结束"); return null; }}
测试类:
/** * Cjlib动态代理 */ @Test public void cjlibTest(){ IPerson iPerson= (IPerson) new Person(); InvocationHandler invocationHandler=new DynaProxyHandler(iPerson); IPerson person = (IPerson) Proxy.newProxyInstance(iPerson.getClass().getClassLoader(), iPerson.getClass().getInterfaces(), invocationHandler); person.eating(); person.sleep(); }