Java 代理

代理模式UML类图

 




代理模式



1. 静态代理



 









Java代码  




/**    
 * 为被代理的类提供一个接口,是为了提高代理的通用性,凡是实现了该接口的类,都可以被代理    
 * 这里其实就是运用了java面向对象的多态性    
 */     
public interface IHello {      
    public void sayHello();      
}      
/**    
 * 被代理的类,最根本的想法就是想用另外一个类来代理这个类,给这个类添加一些额外的东西    
 * 我们只需要创建另外一个类引用这个类就行了    
 */     
public class Hello implements IHello      
{      
    public void sayHello(){      
        System.out.println("被代理的方法");      
    }      
}     
/**    
 * 静态代理类,其实就是(被代理类的)接口的另外一种实现,    
 * 用来代替原来的被代理类    
 * @author qiuxy    
 */     
public class StaticProxy implements IHello {    
    IHello hello;      
    public StaticProxy(IHello hello) {      
        this.hello = hello;      
    }      
    /**    
     * 重新实现了sayHello()方法,这种实现其实就是在被代理类实现该方法中添加一些额外的东西, 以实现代理的作用    
*/     
    public void sayHello() {      
        System.out.println("在被代理的对象之前执行");      
        // 被代理的对象执行方法      
        hello.sayHello();      
        System.out.println("在被代理的对象之前执行");      
    }      
}     
/**    
 * 测试类    
 * @author qiuxy    
 */     
public class Test {      
    public static void main(String[] args) {      
        //产生一个被代理对象,只要实现了Ihello接口的对象,都可以成为被代理对象      
        //这里就是利用接口的好处,但这个也有局限性,就是只限于某种接口      
        IHello hello = new Hello();      
        //产生一个代理对象      
        StaticProxy sp = new StaticProxy(hello);      
        //执行代理对象的sayHello()方法,这个方法在被代理的方法前后添加了其他代码      
        sp.sayHello();      
    }      
}    






 



2. 动态代理



 









Java代码  




import java.lang.reflect.InvocationHandler;      
import java.lang.reflect.Method;      
/**    
 * 代理处理器,这个代理处理器实现了InvocationHandler这个接口,    
 * 这个接口的提供了一个invoke方法,并且传入三个参数(被代理的对象,被代理的方法,方法的参数数组)    
 * 这个invoke方法会在被代理的方法之前被调用    
 */     
public class MyProxyHandler implements InvocationHandler {      
    //被代理的对象      
    Object delegate;       
    //构造函数,在构在这个代理处理器时,传入要被代理的对象      
    public MyProxyHandler(Object delegate) {           
    this.delegate = delegate;      
    }      
    //被代理的方法之前会调用的方法      
    public Object invoke(Object proxy, Method method, Object[] args)   throws Throwable {    
        System.out.println("我在被代理的方法之前执行");      
        //被代理的方法开始执行      
        method.invoke(delegate, args);      
        System.out.println("我在被代理的方法之后执行");      
        return null;      
    }      
}     
import java.lang.reflect.Proxy;      
/**    
 * 测试类    
 */     
public class Test      
{      
    public static void main(String[] args)      
    {      
        Hello hello = new Hello();      
        //产生一个代理处理器对象      
        MyProxyHandler mph = new MyProxyHandler(hello);      
        //通过反射获得代理类,这里必须转换成代理类的接口类型      
        //这个代理对象其实是java动态生成一个被代理类的接口的另外一个实现类      
        IHello myProxy = (IHello)Proxy.newProxyInstance(hello.getClass().getClassLoader()  , hello.getClass().getInterfaces(), mph);      
        //代理类执行方法      
        myProxy.sayHello();      
    }      
     
}  

代理模式



代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。



代理模式一般涉及到的角色有:



抽象角色:声明真实对象和代理对象的共同接口;



代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。



真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。(参见文献1)



以下以《Java与模式》中的示例为例:



抽象角色:



abstract public class Subject



{



    abstract public void request();



}



真实角色:实现了Subject的request()方法。



public class RealSubject extends Subject



{



       public RealSubject()



       {



       }



      



       public void request()



       {



              System.out.println("From real subject.");



       }



}



代理角色:



public class ProxySubject extends Subject



{



    private RealSubject realSubject;  //以真实角色作为代理角色的属性



      



       public ProxySubject()



       {



       }



 



       public void request()  //该方法封装了真实对象的request方法



       {



        preRequest(); 



              if( realSubject == null )



        {



                     realSubject = new RealSubject();



              }



        realSubject.request();  //此处执行真实对象的request方法



        postRequest();



       }



 



    private void preRequest()



    {



        //something you want to do before requesting



    }



 



    private void postRequest()



    {



        //something you want to do after requesting



    }



}



客户端调用:



Subject sub=new ProxySubject();



Sub.request();



       由以上代码可以看出,客户实际需要调用的是RealSubject类的request()方法,现在用ProxySubject来代理RealSubject类,同样达到目的,同时还封装了其他方法(preRequest(),postRequest()),可以处理一些其他问题。



       另外,如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。



 



2.动态代理类



       Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:



(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, J2EEjava语言JDK1.4APIjavalangObject.html">Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。




(2).Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:



Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。



Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。



Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。



 



       所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。(参见文献3)



    在使用动态代理类时,我们必须实现InvocationHandler接口,以第一节中的示例为例:



抽象角色(之前是抽象类,此处应改为接口):



public interface Subject



{



    abstract public void request();



}



具体角色RealSubject:同上;



 



代理角色:



import java.lang.reflect.Method;



import java.lang.reflect.InvocationHandler;



 



public class DynamicSubject implements InvocationHandler {



  private Object sub;



 



  public DynamicSubject() {



  }



 



  public DynamicSubject(Object obj) {



    sub = obj;



  }



 



 



  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {



    System.out.println("before calling " + method);



 



    method.invoke(sub,args);



 



    System.out.println("after calling " + method);



    return null;



  }



 



}



 



       该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值;此外,在该类还实现了invoke方法,该方法中的



method.invoke(sub,args);



其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,args为执行被代理对象相应操作所需的参数。通过动态代理类,我们可以在调用之前或之后执行一些相关操作。



客户端:



import java.lang.reflect.InvocationHandler;



import java.lang.reflect.Proxy;



import java.lang.reflect.Constructor;



import java.lang.reflect.Method;



 



public class Client



{



 



    static public void main(String[] args) throws Throwable



       {



      RealSubject rs = new RealSubject();  //在这里指定被代理类



      InvocationHandler ds = new DynamicSubject(rs);  //初始化代理类



         Class cls = rs.getClass();



      //以下是分解步骤



      /*



      Class c = Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces()) ;



      Constructor ct=c.getConstructor(new Class[]{InvocationHandler.class});



      Subject subject =(Subject) ct.newInstance(new Object[]{ds});



     */



     //以下是一次性生成



      Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(),



                                 cls.getInterfaces(),ds );



 



      subject.request();



}



       通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系(参见文献2)。



本文出自seven的测试人生公众号最新内容请见作者的GitHub页:http://qaseven.github.io/





时间: 2024-08-01 21:36:42

Java 代理的相关文章

轻松掌握Java代理模式_java

和大家一起聊一聊java代理模式 1.静态代理 1.1静态代理的代理类和和被代理的类都要维护一个共同的接口.  public interface IUserDao { void save(); } 1.2被代理的类,目标对象  public class UserDao implements IUserDao{ @Override public void save() { System.out.println("-----已经保存数据!!!------"); } } 1.3代理对象  p

在使用JAVA代理调用webservice的时候报错,请问有谁认识这中错。万分感激

问题描述 我在lotus使用java代理调用一个webservice,但是每次运行到Serviceservice=newService();的时候就报下面的错误2009-03-2422:01:38HTTPJVM:log4j:WARNNoappenderscouldbefoundforlogger(org.apache.axis.i18n.ProjectResourceBundle).2009-03-2422:01:39HTTPJVM:log4j:WARNPleaseinitializethelo

Java代理模式

一.Java代理模式 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 代理模式结构图 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别.通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性. 更通俗的说,代理解决的问题当两个类需

java代理 jdk动态代理应用案列_java

java代理有jdk动态代理.cglib代理,这里只说下jdk动态代理,jdk动态代理主要使用的是java反射机制(既java.lang.reflect包) 原理是(歌手.经纪人做例子): 建立一个公共的接口,比如:歌手public interface Singer: 用具体的类实现接口,比如:周杰伦,他是歌手所以实现Singer这个类,class MySinger implements Singer 建立代理类,这里也就是经纪人,他需要实现InvocationHandler类,并重写invok

用java代理改写LS中的Evaluate函数的问题

问题描述 本人在帮助中查看到LS的Evaluate函数对应的java函数是evaluate,但是evaluate中不支持@Command,@DbManager,@DbName,@DbTitle,@DDEExecute,@DDEInitiate,@DDEPoke,@DDETerminate,@DialogBox,@PickList,@PostedCommand,@Prompt,and@ViewTitle.函数.现在LS语句如下:Evaluate(|@Name([CN];@DBLookup("&qu

java代理模式与反射机制

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.  代理模式一般涉及到的角色有:  抽象角色:声明真实对象和代理对象的共同接口:  代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象.同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装.  真实角色:代理角色所代

Java代理模式详解

代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被为拖累执行后的后续处理. 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别.通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性. 更通俗的说,代理解决的问题当两个类需要通信时,引入第三方代理类,将两个类的

java代理模式与动态代理模式详解_java

1.代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 生活中的例子:过年加班比较忙,没空去买火车票,这时可以打个电话到附近的票务中心,叫他们帮你买张回家的火车票,当然这会附加额外的劳务费.但要清楚票务中心自己并不卖票,只有火车站才真正卖票,票务中心卖给你的票其实是通过火车站实现的.这点很重要!

Java代理机制

1 引言 我们书写执行一个功能的函数时,经常需要在其中写入与功能不是直接相关但很有必要的代 码,如日志记录,信息发送,安全和事务支持等,这些枝节性代码虽然是必要的,但它会带 来以下麻烦: 枝节性代码游离在功能性代码之外,它下是函数的目的,这是对OO是一种破坏 枝节性代码会造成功能性代码对其它类的依赖,加深类之间的耦合,而这是OO系统所竭 力避免的 枝节性代码带来的耦合度会造成功能性代码移植困难,可重用性降低 从法理上说,枝节性代码应该`监视'着功能性代码,然后采取行动,而不是功能性代码 `通知'