@Slf4j
@Component
public class ThirdChannelWaybillService {
Map<String, ThirdChannelWaybillHandler> thirdChannelWaybillHandlerHashMap = new HashMap<>();
private synchronized ThirdChannelWaybillHandler getProcessWaybillHandler(String thirdChannel){
ThirdChannelWaybillHandler thirdChannelWaybillHandler = thirdChannelWaybillHandlerHashMap.get(thirdChannel);
if (thirdChannelWaybillHandler == null){
Map<String, ThirdChannelWaybillHandler> thirdChannelWaybillHandlerMap = ApplicationUtils.beanMap(ThirdChannelWaybillHandler.class);
for (ThirdChannelWaybillHandler handler : thirdChannelWaybillHandlerMap.values()) {
if (!thirdChannelWaybillHandlerHashMap.containsKey(handler.getThirdChannel())){
thirdChannelWaybillHandlerHashMap.put(handler.getThirdChannel(), handler);
}
}
}
return thirdChannelWaybillHandlerHashMap.get(thirdChannel);
}
public Response addWaybill(ThirdWaybillParam param){
ThirdChannelWaybillHandler processWaybillHandler = this.getProcessWaybillHandler(param.getThirdChannelCode());
return processWaybillHandler.addWaybill(param);
}
}
1. 单例模式(Singleton Pattern)
在 getProcessWaybillHandler
方法中,使用了 synchronized
关键字确保方法线程安全,并且通过 thirdChannelWaybillHandlerHashMap
来缓存每个 thirdChannel
对应的 ThirdChannelWaybillHandler
实例。这种做法在一定程度上保证了对于每个 thirdChannel
,该 ThirdChannelWaybillHandler
只会创建一次,并且在之后的调用中重用这个实例。可以认为这里是对 ThirdChannelWaybillHandler
对象的 单例模式 的一种变体,尤其是在多线程环境下。
具体分析:
thirdChannelWaybillHandlerHashMap.get(thirdChannel)
负责从缓存中获取对应的ThirdChannelWaybillHandler
。- 如果缓存中没有相应的处理器 (
thirdChannelWaybillHandler == null
),则通过ApplicationUtils.beanMap(ThirdChannelWaybillHandler.class)
加载所有的ThirdChannelWaybillHandler
实例,并将其添加到缓存中 (thirdChannelWaybillHandlerHashMap.put(handler.getThirdChannel(), handler)
)。 - 由于使用了
synchronized
,此方法确保在多线程环境下,同一时刻只有一个线程可以加载ThirdChannelWaybillHandler
实例,从而防止了重复加载和线程安全问题。
2. 工厂模式(Factory Pattern)
getProcessWaybillHandler
方法本质上是一个工厂方法,负责根据 thirdChannel
创建或返回相应的 ThirdChannelWaybillHandler
实例。虽然并不完全符合传统的工厂模式(因为没有显式的工厂类),但它的行为符合工厂模式的基本思想:根据某种条件(thirdChannel
)动态返回不同的实例。
具体分析:
ApplicationUtils.beanMap(ThirdChannelWaybillHandler.class)
实际上是根据ThirdChannelWaybillHandler
类型加载相关实例,这种方式与工厂模式中的实例化过程类似。- 然后通过
thirdChannelWaybillHandlerHashMap.put
将创建的实例缓存下来,以便后续调用。
以下获取一个Map类型的Bean实例
Map<String, ThirdChannelWaybillHandler> thirdChannelWaybillHandlerMap = ApplicationUtils.beanMap(ThirdChannelWaybillHandler.class);
@Slf4j
@Component
public class ApplicationUtils implements ApplicationContextAware {
private static final String NOT_EXIST_ERRMSG = "bean.not.exist";
private static final String NOT_REPO_ERRMSG = "clazz.not.repository";
private static final String NOT_SERVICE_ERRMSG = "clazz.not.service";
@Setter
private static ApplicationContext applicationContext;
/**
* 获取一个Bean实例
*
* @param clazz 目标Bean实例类型
* @param <T> 目标Bean范型限制
* @return Bean实例,如果Bean不存在,则抛出FrameworkException异常
*/
public static <T> T bean(Class<T> clazz) {
if (applicationContext == null) {
throw new BusinessException(CommonExceptionCode.DEFAULT_ERROR.getErrCode(), NOT_EXIST_ERRMSG);
}
Map beans = applicationContext.getBeansOfType(clazz);
T t = (T) beans.values().stream().findFirst().orElse(null);
if (t == null) {
throw new BusinessException(CommonExceptionCode.DEFAULT_ERROR.getErrCode(), NOT_EXIST_ERRMSG);
}
return t;
}
/**
* 获取一个Map类型的Bean实例
*
* @param clazz 目标Bean实例类型
* @param <T> 目标Bean范型限制
* @return Bean实例,如果Bean不存在,则抛出FrameworkException异常
*/
public static <T> Map<String, T> beanMap(Class<T> clazz) {
if (applicationContext == null) {
throw new BusinessException(CommonExceptionCode.DEFAULT_ERROR.getErrCode(), NOT_EXIST_ERRMSG);
}
Map<String, T> beans = applicationContext.getBeansOfType(clazz);
if (beans == null) {
throw new BusinessException(CommonExceptionCode.DEFAULT_ERROR.getErrCode(), NOT_EXIST_ERRMSG);
}
return beans;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (ApplicationUtils.applicationContext == null) {
ApplicationUtils.applicationContext = applicationContext;
}
}