概念
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
描述
我举一个现实生活的例子,你如果是房东,你需要把自己的房子出租被别人使用,在这个过程中,会有很多房客会来咨询你、或看房,而你又不想浪费时间和别人进行交谈协商,只是想把房子租出去,此时你是不是想到了房地产中介,此时你和中介签订一个合同把房子托付给了中介,让中介帮你把房子租出去。那些租房的人通过中介拿到你的房子的使用权,这个过程就是代理的过程,我就是委托者,中介就是代理者。代理模式又分为静态代理和动态代理。
静态代理
静态代理由程序猿创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的.class文件就已经存在了。
- 创建一个连接委托者和代理者的接口(类似你和中介签订的出租房屋的合同)
public interface AbstractCommonInterface {
void run();
}
- 创建委托者
public class MyService implements AbstractCommonInterface {
//在这里面还有配置服务的其他方法
@Override
public void run() {
//启动服务器
System.out.println("服务器启动了");
}
}
- 创建代理者
/**
这代理里我们可以做一些其他的工作,比如在这里我们进行账户认证
*/
public class MyServiceProxy implements AbstractCommonInterface {
private String userName;
private String passWord;
private MyService myService;
public MyServiceProxy(String userName,String passWord){
this.userName = userName;
this.passWord = passWord;
myService = new MyService();
}
private boolean checkUser(){
if (userName =="admin"&&passWord=="admin"){
return true;
}else {
return false;
}
}
@Override
public void run() {
//checkUser()就是启动服务业务前做的操作
if (checkUser()){
System.out.println("验证通过,启动代理");
myService.run();
//事后做的业务
System.out.println("代理实现,继续其他工作");
}else {
System.out.println("验证没通过");
}
}
}
- 创建调用者
public class Client {
@Test
public void test(){
MyServiceProxy serviceProxy = new MyServiceProxy("admin","admin");
serviceProxy.run();
}
}
动态代理
在程序运行时运用反射机制动态创建而成。
我们重点讲java动态代理机制。这个机制的核心是InvocationHandler(接口)和Proxy(类),我们先学会怎么使用java动态代理,再来研究它是怎么实现的。
- 创建一个连接委托者和代理者的接口
- 创建委托者
这俩步和静态代理的代码一样的。
- 创建代理者,这个是由java的代理机制来实现,我们只要继承InvocationHandler就行了
public class MyInvocationHandler implements InvocationHandler {
/**
* 因为需要处理真实角色,所以要把真实角色传进来
*/
MyService myService ;
private String userName;
private String passWord;
public MyInvocationHandler(String userName,String passWord) {
this.userName=userName;
this.passWord=passWord;
this.myService = new MyService();
}
private boolean checkUser(){
if (userName =="admin"&&passWord=="admin"){
return true;
}else {
return false;
}
}
/**
*
* @param proxy 代理类
* @param method 正在调用的方法
* @param args 方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (checkUser()){
System.out.println("验证通过,启动代理");
return method.invoke(myService,args);
}else {
System.out.println("验证没通过");
return null;
}
}
}
- 创建调用者
public class Client {
@Test
public void test(){
MyInvocationHandler myInvocationHandler = new MyInvocationHandler("root","admin");
//委托者委托的所有动作,如上面举的列子,假如这个房子存在出售和出租的俩个动作,
//但你只委托中介出租房屋,那么中介是无法拿去销售的。
AbstractCommonInterface proxyClass = (AbstractCommonInterface) Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[]{AbstractCommonInterface.class},
myInvocationHandler);
proxyClass.run();
}
}
在这个动态代理的过程,我们通过Proxy拿到委托者委托的所有动作的接口,通过这个接口的动作控制委托者的行为。
接下来我们来分析下创建代理者和调用者的代码,通过上面的代码我们知道,创建代理者就是继承了InvocationHandler去实现invoke方法。我们先看下源码:
public interface InvocationHandler {
/**
* @param proxy the proxy instance that the method was invoked on
*
* @param method the {@code Method} instance corresponding to
* the interface method invoked on the proxy instance.
*
* @param args an array of objects containing the values of the
* arguments passed in the method invocation on the proxy instance,
* @return the value to return from the method invocation on the
* proxy instance.
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
通过者个方法会返回委托对象委托到接口里的动作集合器,我们在上代码中采用return method.invoke(myService,args),其中myService是我们的委托对象,因此,我们传不同的委托类,它就产生不同的委托对象委托到接口的动作集合器。
然后我们再看看调用者的代码,我们需要拿到代理对象,Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法,我们主要看看这个方法的参数,第一个参数是类加载器,第二个参数类的集合,(也就是说,可以存在多个类,产生多个代理),第三个参数是InvocationHandler,我们创建的动态代理对象。