设计模式是在软件设计中反复出现的一些问题的解决方案的经验总结。它们是一种被广泛接受的最佳实践,可用于解决特定类型的问题或完成特定类型的任务。六大设计原则为设计模式提供理论支持,它们分别是:
单一职责原则:应该有且仅有一个原因引起类的变更
里氏替换原则:所有引用父类的地方必须能透明地使用其子类的对象
依赖倒置原则:面向接口编程,依赖抽象而非细节
接口隔离原则:接口尽量细化,接口中的方法尽可能的少
迪米特法则:一个对象应该对其他对象有最少的了解
开闭原则:对拓展开放,对修改关闭
HSF中使用了哪些经典的设计模式呢?
▐ 责任链模式
定义:
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
介绍:
想要在HSF流程发生的过程中对其进行拓展,需要实现ProtocolInterceptor,它的继承树如下图所示。
ProtocolInterceptor实现了Protocol接口,里面只增加了一个方法void setProtocol(Protocol protocol);,其目的就是形成一个Protocol链条,这样就能将ProtocolInterceptor的扩展点拼装到流程链条上。
HSF提供了AbstractDelegateProtocolInterceptor,可以通过继承该抽象类,重写List<ServiceURL> export();等方法,轻松的实现流程的扩展。
链的构建
为了链能正常运行起来,首先需要构建链。HSF是通过以下方式拼装流程这条链的:
Protocol protocol = HSFServiceContainer.getInstance(Protocol.class);
List<ProtocolInterceptor> handlers = HSFServiceContainer.getInstances(ProtocolInterceptor.class);
// 堆代码 duidaima.com
//init
Protocol last = protocol;
for (int i = handlers.size() - 1; i >= 0; i--) {
handlers.get(i).setProtocol(last);
last = handlers.get(i);
}
return last;
HSFServiceContainer.getInstances(ProtocolInterceptor.class);会返回优先级从高到低的xxxProtocolInterceptor(通过@Order(int)注解排序,值越小优先级越高),最后返回的是优先级最高的ProtocolInterceptor节点。
链的执行:
抽象类和具体的实现类在export服务导出这个场景下的执行流程如下。
public abstract class AbstractDelegateProtocolInterceptor implements ProtocolInterceptor {
protected Protocol protocol;
@Override
public List<ServiceURL> export(ServiceMetadata serviceMetadata, InvocationHandler invocationHandler) {
return protocol.export(serviceMetadata,invocationHandler);
}
}
@Order(250)
public class EagleEyeProtocolInterceptor extends AbstractDelegateProtocolInterceptor {
/**
* container信息(edas)
*/
private ContainerInfo containerInfo = HSFServiceContainer.getInstance(ContainerInfo.class);
@Override
public List<ServiceURL> export(ServiceMetadata serviceMetadata, InvocationHandler invocationHandler) {
if (containerInfo.isSupportContainer()) {
serviceMetadata.addProperty(HSFConstants.CONTAINER_ID_KEY, containerInfo.getContainerId());
}
return protocol.export(serviceMetadata, invocationHandler);
}
}
此处具体的实现类以「EagleEye的启动阶段拦截」为例,需要在调用protocol.export(serviceMetadata, invocationHandler);之前编写业务代码。
▐ 代理模式
定义:
为其他对象提供一种代理以控制对这个对象的访问。
介绍:
服务消费方使用代理模式调用服务提供方的方法,获取返回结果。服务消费方通过代理类与服务提供方建立TCP连接,进行网络通信,将方法和入参传输给服务提供方后,服务提供方通过反射调用指定方法,得到结果,再通过网络将结果传给服务消费方。
创建代理对象:
Object proxy = proxyFactory.getProxy(metadata, decorateInterfaces);
public Object getProxy(ServiceMetadata metadata, Class<?>... interfacesArray) {
try {
JdkProxyInvocationHandler jdkProxyInvocationHandler = new JdkProxyInvocationHandler(metadata);
Object instance = Proxy.newProxyInstance(metadata.getIfClazz().getClassLoader(), interfacesArray, jdkProxyInvocationHandler);
jdkProxyInvocationHandler.init(instance);
return instance;
} catch (Throwable t) {
throw new HSFException("failed to generate jdk proxy",t);
}
}
调用方法:
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
ApplicationModelFactory.setCurrentApplication(serviceMetadata.getApplicationModel());
ConsumerMethodModel methodModel = serviceMetadata.getConsumerServiceModel().getMethodModel(method);
return InvocationUtil.invoke(methodModel, args);
}
▐ 观察者模式
定义:
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
介绍:
以服务消费方监听路由规则为例,服务消费方通过RegistryProtocolInterceptor与注册中心进行交互时,会根据当前路由规则构建相应的监听器,监听路由规则的变化,保证调用服务提供方的方法时使用的是最新的路由规则。
注册监听器:
public void registerListener(Object listener) {
synchronized (eventBus) {
if (lastRule != null) {
eventBusHelp.register(listener);
eventBusHelp.post(lastRule);
eventBusHelp.unregister(listener);
}
eventBus.register(listener);
}
}
▐ 装饰模式
定义:
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
介绍:
服务消费方生成调用方法的代理对象的时候,会指定代理对象实现了哪些接口,这些接口都是经过装饰的。
装饰接口:
/**
* 使用该接口对客户端元数据进行处理,返回需要装饰的接口
*/
@Shared
@Scope(Scope.Option.SINGLETON)
public interface ProxyDecorator {
/**
* 用来装饰当前的调用接口
*
* @param serviceMetadata 客户端元数据
* @return 装饰接口,如果不进行装饰返回null
*/
Class<?> decorate(ServiceMetadata serviceMetadata);
}
// 生成调用远程HSF服务的代理
ProxyDecoratorGenerator proxyDecoratorGenerator = HSFServiceContainer.getInstance(
ProxyDecoratorGenerator.class);
// 获取装饰后的接口
Class<?>[] decorateInterfaces = proxyDecoratorGenerator.getDecorateInterfaces(metadata);
ProxyFactory proxyFactory = HSFServiceContainer.getInstance(ProxyFactory.class, metadata.getProxyStyle());
Object proxy = proxyFactory.getProxy(metadata, decorateInterfaces);
Method[] methods = proxyFactory.getMethods(proxy);