代理模式
代理模式,为其他对象提供一种代理以控制对这个对象的访问。
在一些开源框架或中间件产品中,代理模式会非常常见。使用的时候越简便,框架在背后做的事就可能越复杂。这里面往往都体现着代理模式的应用,颇有移花接木的味道。
1、Dubbo
Dubbo作为一个RPC框架,其中有一个很重要的功能就是:
提供高性能的基于代理的远程调用能力,服务以接口为粒度,为开发者屏蔽远程调用底层细节。
这里我们关注两个重点:
- 面向接口代理;
- 屏蔽调用底层细节。
比如有一个库存服务,它提供一个扣减库存的接口。
public interface StorageDubboService {
int decreaseStorage(StorageDTO storage);
}
在别的服务里,需要扣减库存的时候,就会通过Dubbo引用这个接口,也比较简单。
@Reference
StorageDubboService storageDubboService;
使用起来很简单,可StorageDubboService只是一个普通的服务类,并不具备远程调用的能力。
Dubbo就是给这些服务类,创建了代理类。通过ReferenceBean来创建并返回一个代理对象。
public class ReferenceBean<T>{
@Override
public Object getObject() {
return get();
}
public synchronized T get() {
if (ref == null) {
init();
}
return ref;
}
}
在使用的时候,实则调用的是代理对象,代理对象完成复杂的远程调用。比如连接注册中心、负载均衡、集群容错、连接服务器发送消息等功能。
2、MyBatis
还有一个典型的应用,就是经常在用的MyBatis。在使用的时候,一般只操作Mapper接口,然后MyBatis会找到对应的SQL语句来执行。
public interface UserMapper {
List<User> getUserList();
}
如上代码,UserMapper也只是一个普通的接口,它是怎样最终执行到SQL语句的呢?
答案也是代理。当MyBatis扫描到定义的Mapper接口时,会将其设置为MapperFactoryBean,并创建返回一个代理对象。
protected T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
代理对象去通过请求的方法名找到MappedStatement对象,调用执行器,解析SqlSource对象来生成SQL,执行并解析返回结果等。