Java中的代理

来源:互联网 发布:消防工程师题库软件 编辑:程序博客网 时间:2024/06/07 02:02
1. 什么是代理
我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,“委托者”对我们来说是不可见的;其次,微商代理主要以朋友圈的人为目标客户,这就相当于为厂家做了一次对客户群体的“过滤”。我们把微商代理和厂家进一步抽象,前者可抽象为代理类,后者可抽象为委托类(被代理类)。通过使用代理,通常有两个优点,并且能够分别与我们提到的微商代理的两个特点对应起来:
优点一:可以隐藏委托类的实现;

优点二:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。

2. 代理例子和角色分析

我们在这里举个例子:就是我们通过中介找房子。而中介就是个代理。下面按照这个例子然后进行代理的角色分型,已经在java中的实现。

代理的角色分配大致为一下四种:

1,抽象角色:一般使用接口和抽象类来实现。在上述例子中,就是定义一个Rent接口,用来租房子。

2,真实角色:被代理的角色。在上述例子中,就是房主要出租房子,在此定义一个Host类,实现Rent接口,然后行使租房子。

3,代理角色:代理真实角色做一些事情,然后会有一些附属操作。在上述例子中,中介在此定义一个Proxy类,实现Rent接口。就是中介代理房主租房子,然后再代理类中会有一个房主的实例,来行使租房子的行为,然后附属操作就是带房客看房子和收费等。

4,客户:使用代理角色的一些操作。在上述例子中,在此定义一个Client类,然后行使代理的一些操作,然后成功租下房子。

3. 静态代理
若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。下面是我们的实现。

Rent.java:就是接口

package jym;public interface Rent {public void rent();}
Host.java,房主类

package jym;public class Host implements Rent{public void rent() {System.out.println("出租房子");}}
Proxy.java  代理类

package jym;public class Proxy implements Rent{private Host host;public Proxy() {}public Proxy(Host host) {this.host=host;}public void setHost(Host host) {this.host = host;}//租房public void rent() {seeHouse();host.rent();fareHouse();}//看房private void seeHouse() {System.out.println("带课看房子");}//收费private void fareHouse() {System.out.println("收中介费");}}
Client.java  客户类

package jym;public class Client {public static void main(String[] args) {Host host=new Host();Proxy proxy=new Proxy(host);proxy.rent();}}
输出结果:

带课看房子
出租房子
收中介费

4. 使用动态代理

Rent.java  接口

package jym;public interface Rent {public void rent();}
Host.java 房主类

package jym;public class Host implements Rent{public void rent() {System.out.println("出租房子");}}

invocationHandler 是代理实例的调用处理程序 实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法.详解如下:

Objectinvoke(Object proxy,

              Method method,

              Object[] args)

             throws Throwable

在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。

参数:proxy - 在其上调用方法的代理实例

method - 对应于在代理实例上调用的接口方法的 Method 实例。Method对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。

args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。

返回:从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。如果此方法返回的值为 null 并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出


ProxyInouationHandler.java  动态代理类

package jym;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyInovationHandler implements InvocationHandler{private Object target;public void setTarget(Object target) {this.target = target;}/* * 生成代理类 * */public Object getProxy() {return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}/* * proxy是代理类 * method 代理类的调用处理程序的方法对象 *  * */public Object invoke(Object proxt,Method method,Object[] args) throws Throwable {//seeHouse();log(method.getName());Object result=method.invoke(target, args);//fareHouse();return result;}public void log(String methodName) {System.out.println("执行"+methodName+"方法");}}
因为在动态代理类中新增了代理类的调用处理程序的方法对象,所以我们在这里添加了一个UserService.java接口和实现类,把代理的一些公共方法放到这里,具体代码如下;

UserService.java 代理公共方法接口

package service;public interface UserService {public void seeHouse();public void fareHouse();}
UserServiceIm.java 代理公共方法的接口实现:

package service;public class UserServiceImp implements UserService {@Overridepublic void seeHouse() {System.out.println("看房子");}@Overridepublic void fareHouse() {System.out.println("收取中介费");}}
Client.java 客户类:

package jym;import service.UserService;import service.UserServiceImp;public class Client {public static void main(String[] args) {UserService userService=new UserServiceImp();ProxyInovationHandler pih = new ProxyInovationHandler();pih.setTarget(userService);UserService proxy=(UserService)pih.getProxy();proxy.fareHouse();}}
输出结果:

执行fareHouse方法
收取中介费