Java 代理模式

来源:互联网 发布:失败 无助 知乎 编辑:程序博客网 时间:2024/06/17 03:13

     写一点代理模式的个人理解

     代理模式可以说是:本来由A去执行的方法,但是A不去执行,由B去代A执行。

     代理可分为静态代理和动态代理,静态代理中用代理类也实现了接口的方法。动态代理中用到了反射。

     先看一下静态代理的草图:

  

Real和代理类Proxy同时实现了接口,在客户端调用时直接调用代理类即可,然后代理类中的Real对象再去调用真正实现的方法,这样便形成了代理,达到了使用代理的目的。

优点是:代理类将真实类的方法封装了起来,可以在调用真正实现方法时添加前置和后置方法。

缺点是:实现一个代理类会多出很多的代码,造成了冗余,而且这个代理类必须事先存在。

不写这个代码了。

  动态代理实现,先贴代码:

package Proxy;import java.lang.reflect.*;interface BusinessFoo{void foo();} interface BusinessBar{String bar(String message);}class BusinessFooImpl implements BusinessFoo{@Overridepublic void foo() {// TODO Auto-generated method stubSystem.out.println("BusinessFooImpl.foo()");}}class BusinessBaeImpl implements BusinessBar{@Overridepublic String bar(String message) {// TODO Auto-generated method stubSystem.out.println("BusinessBarImpl.bar()");return message;}}class BusinessImplProxy implements InvocationHandler{private Object obj;   //obj是真正实现方法的对象BusinessImplProxy(){}BusinessImplProxy(Object obj){this.obj = obj;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// TODO Auto-generated method stubObject result = null;doBefore();result = method.invoke(obj, args);  //去调用真正的方法 foo()和bar()doAfter();return result;}public  void  doBefore() {System.out.println("Do something before Business logic");}public void doAfter() {System.out.println("Do something after Business logic");}public static Object factory(Object obj){Class<?> cls = obj.getClass();   System.out.println("cls.getClass is:"+cls.getClass());System.out.println("obj的类型是:"+obj.getClass().getName());Class<?>[] interfaces  = cls.getInterfaces();for(Class<?> itf : interfaces){System.out.println(itf.getName());}System.out.println("ClassLoader is: "+cls.getClassLoader());  //ClassLoader is: sun.misc.Launcher$AppClassLoader@1372a1areturn Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), new BusinessImplProxy(obj));         //返回一个代理对象  getClassLoader()表示该运行时类 //的加载,getInterfaces()是得到运行时类的实现接口,动态代理只是实现了接口,没有实现抽象类,new BusinessImplProxy(obj)则表示真正对///象}}public class DymnaticProxy {public static void main(String[] args) {// TODO Auto-generated method stubBusinessFooImpl bFooImpl = new BusinessFooImpl();BusinessFoo bf = (BusinessFoo)BusinessImplProxy.factory(bFooImpl);  bf.foo();  //去调用invoke();这一块调用哪个真正的方法,invoke中则去调用哪个System.out.println();BusinessBaeImpl bbar = new BusinessBaeImpl();BusinessBar bb = (BusinessBar)BusinessImplProxy.factory(bbar);String messageString  = bb.bar("Hello world"); //去调用invoke();System.out.println(messageString);}}


代理类必须得实现InvocationHandle的接口,该接口中有一个invoke方法。

newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法由程序员来指定参数动态返回需要的代理类,而invoke(Object proxy,Method method, Object[] args) 方法则是由JVM在运行时动态调用的。当执行“bb.bar("Hello,World");”方法时,JVM动态指派“调用处理器”,向外层invoke传递参数,并调用method.invoke(obj,args)真正执行!


BusinessImplProxy.Factory静态方法用来动态生成代理类(“代理角色”),在运行时根据不同的业务逻辑接口BusinessFoo和BusinessBar,在运行时分别动态生成了代理角色。“抽象角色”、“代理角色”以及调用处理器(实现InvocationHandler接口的类)这三者都可以改变,所以说JAVA的动态代理十分强大。


在动态代理使用过程中有几个重要的类:Proxy,Method,Class<?>. 还有这个InvocationHandler接口。

Proxy类只能从子类为InvocationHandler构造一个Proxy实例,Proxy类的无参构造函数为私有,禁止实例化。

 /**     * the invocation handler for this proxy instance.     * @serial     */    protected InvocationHandler h;    /**     * Prohibits instantiation.     */    private Proxy() {    }    /**     * Constructs a new <code>Proxy</code> instance from a subclass     * (typically, a dynamic proxy class) with the specified value     * for its invocation handler.     *     * @param   h the invocation handler for this proxy instance     */    protected Proxy(InvocationHandler h) {this.h = h;    }
<span style="font-size:14px;"></span>

获得代理类的方法:
 public static Class<?> getProxyClass(ClassLoader loader,                                          Class<?>... interfaces)throws IllegalArgumentException
通过ClassLoader 和 Interfaces就可以获得一个运行时的代理类的Class对象。

newProxyInstance()这个静态方法的作用是获得代理类的实例:

 public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces,  InvocationHandler h)throws IllegalArgumentException    {if (h == null) {    throw new NullPointerException();}/* * Look up or generate the designated proxy class. */Class cl = getProxyClass(loader, interfaces);/* * Invoke its constructor with the designated invocation handler. */try {    Constructor cons = cl.getConstructor(constructorParams);    return (Object) cons.newInstance(new Object[] { h });} catch (NoSuchMethodException e) {    throw new InternalError(e.toString());} catch (IllegalAccessException e) {    throw new InternalError(e.toString());} catch (InstantiationException e) {    throw new InternalError(e.toString());} catch (InvocationTargetException e) {    throw new InternalError(e.toString());}    }
通过上面的getProxyClass方法获得代理类的运行时对象,再经过反射获得构造器,然后构造一个新实例。
该方法返回的是一个Object类型的对象,进行强制类型转换后就可以变成要使用的类型了。

再看上面调用实现接口的方法:bf.foo();
这句调用的是InvocationHandler中的方法:
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {

该方法有三个参数:第三个参数是一个Object类型的数组,它传递的是foo()的参数,第二个参数是Method类的对象,这个类要关注一下。

Method类封装了一些方法,比如获得方法的名称,修饰符,返回类型,异常等等,这个类和Class类关系很大,通常用于反射,可以通过Class对象获取类运行时方法信息:getMothods(),然后返回的就是Method类型对象。在Class类中其他的也一样,可以通过方法getConstructor()获得构造器,返回的是一个Constructor对象,这些都有相应的类型。然后再调用相应类中的方法。
 Method类中有一个invoke():
ublic Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,           InvocationTargetException
在上面的例子中调用before()后,就调用的是这个方法,该方法的第一个参数是一个对象,第二个参数表示方法的参数,但是没有该方法,实际上调用InvocationHandler接口中的invoke方法的时候,Method的对象就是传递的foo这个方法,而现在的对象则表示 bf,写法则和普通的写法不同,用到了反射。


还有Class<?>这个类,这个是反射用到的类,获取类的运行时对象,然后可以通过 构造实例访问类的方法,属性等等,也可以获得类的所有信息,这些信息都是在运行时获得的,有时候在编译的时候无法获得要运行哪个类,这时候用反射就和知道要运行哪个类一样的去获得该类的信息。该类中返回的很多对象都是另一些类型的,这些和反射联系的很紧密,所以有时候也需要看看。

InvocationHandler这个接口里就只有一个方法:
 public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
实现该接口就相当于是代理类。


先写这些



0 0