Spring-涉及到的设计模式汇总
一、单例
项目配置:配置在Spring容器中的Bean几乎都是单例,比如Controller、Service、Facade、Dao这些无状态的Bean。
RSA加解密用到的BouncyCastleProvider,使用饿汉式单例
二、代理模式
项目配置:Shiro权限管理、Spring事务管理器、线程池异步注解
1、利用注解AOP解决后台管理系统用户操作日志记录;
接口请求响应参数打印、参数校验、MDC线程追踪、统一异常处理
2、利用Mybatis的Interceptor接口,来实现读写分离
三、享元模式
项目配置:常量池的String对象、缓存、数据库连接池、线程池
利用Mybatis的Interceptor接口,来实现读写分离的时候,将某个语句对应某个库缓存到ConcurrentHashMap中,如果存在则直接取,不存在则保存。
四、观察者模式
工具框架自带:ZOOKEEPER的WATCHER、REDIS发布订阅
消息队列发布订阅、SPRING的ApplicationEventhe ApplicationListener
五、模板方法模式
框架:
MYBATIS:BaseExecutor和SimpleExecutor等子类,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler
protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;
protected abstract List doFlushStatements(boolean isRollback) throws SQLException;
protected abstract List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
渠道系统对接第三方接口运用模板方法:
1、调用验证组件验证请求参数
2、拼装请求报文,并根据特定编码将报文转换为byte[]数组
3、调用通信组件发起HTTP请求
4、处理响应的二进制报文
5、返回响应
基本上对接大部分第三方接口都是这种模式,因此需要继承重写的主要就是第2、4步骤,验证组件和通信组件可以另外配置一个工厂,其中的流程异常全部都在父类中
validator.validate(req)
byte[] request = buildRequestBytes(req)
byte[] response = transferHandler.send(request)
resp = resolveResponse(response)
return response
银行ABS系统:
封包、解包、赎回、转让、调整接口,处理方法都是:
1、数据库插入一条处理中调用记录
2、异步任务处理
3、构造返回响应
所以需要重写的只有第二步实际任务处理
另外4个接口的任务处理也有同样的步骤:
1、下载FTP文件
2、文件处理
3、更新数据库调用记录处理后的状态
实际上需要重写的也只有第二步文件处理
六、工厂+策略模式
解锁新姿势:探讨复杂的 if-else 语句“优雅处理”的思路
额度系统针对不同资方有不同额度策略,举个简单例子,就还款而言,有的循环额度资方还款恢复额度,而有的是半循环额度资方还款不恢复用户额度,还有的资方可能还款时候还要做某些操作。正常情况肯定免不了if-else或者switch来选择处理方式,当策略变多的时候代码就会比较繁杂。因此采用这俩种模式来解决if-else问题。
接口
public abstract class AbstractRepaymentCallbackHandler {
public abstract void increase(DTO dto);
}
多个实现类及重写方法,这边瞎写一下
public class Handler1 extends AbstractRepaymentCallbackHandler{
...
}
public class Handler2 extends AbstractRepaymentCallbackHandler{
...
}
public class Handler3 extends AbstractRepaymentCallbackHandler{
...
}
工厂 把上面三个类及对应名称put进去,这些都是Spring的Bean
public class HandlerProcessor{
private Map repaymentCallbackHandlerMap = new HashMap<>()
publi void increase(CompanyInfo company,DTO dto){
repaymentCallbackHandlerMap.get(company.getRepaymentCallbackHandler()).increase(dto);
}
}
数据库保存资方对应处理器关系,比如资方ID 1 -> "handler1" 等等
这样最终在需要调用increase的时候就只要handlerProcessor.increase就行了,已经做好了配置,不用管什么资方用什么处理器。另外get那一部可以拆分,没配置的资方取一个默认处理器。
另外Spring环境的工厂还可以这样注入:
/**
* UC API降级处理器工厂
*
* @Date 2020/12/26
**/
@Component
public class DegradeHandlerFactory implements ApplicationContextAware {
private Map degradeHandlerFactory;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map beansMap = applicationContext.getBeansOfType(UcApiDegradeHandler.class);
degradeHandlerFactory = beansMap.values()
.stream()
.collect(Collectors.toMap(UcApiDegradeHandler::getHandlerKey, Function.identity()));
}
/**
* 获取对应接口的降级处理器
*
* @param handlerKey
* @return
*/
public UcApiDegradeHandler getHandler(String handlerKey) {
return degradeHandlerFactory.get(handlerKey);
}
}
七、适配器
Mybatis日志适配器:具体的可以关注这几个类
org.apache.ibatis.logging.LogFactory
Log
Slf4jImpl
事实上可以理解为:LogFactory工厂按照各种日志实现类的优先级去尝试加载一种日志实现类,所有日志操作都抽象为Log接口,然后Log接口的方法实现(比如Slf4jImpl)再去调用真正的日志实现。这里目的就是为了各种不同的日志实现提供一个统一的接入接口
Mybatis日志适配器
八、建造者模式
Lombok @Builder