场景介绍
实际项目上中遇到交易使用多种支付方式,如微信原生支付,微信小程序支付,微信公众号支付,支付宝之支付等等等。我们将支付做成接口,微信支付、支付宝支付做成不同的实现类,根据需求调用不同的实现类的方法;简化多个if判断,switch case 使用。 (上述思想怎么感觉也有点像设计模式—策略模式呢,改天对比一下)
我们有两种实现思路:
1 基于@Autowired
2 基于getBeansOfType+ApplicationContextAware接口的
https://blog.csdn.net/Better000/article/details/105247431
https://blog.csdn.net/puhaiyang/article/details/86697359
上述两个链接讲解的是基于@Autowired实现策略模式;
https://www.cnblogs.com/zhoading/p/14663454.html
基于getBeansOfType的看这个链接就能会了,这里需要补充得就是applicationContextAware得作用【https://www.jianshu.com/p/4c0723615a52】
简单总结:
web项目中,spring管理项目所有bean,我们可以通过 ApplicationContext appContext = new ClassPathXmlApplicationContext(“applicationContext-common.xml”);
AbcService abcService = (AbcService)appContext.getBean(“abcService”);
的方式获取容器中的bean,但是这样就会存在一个问题:因为它会重新装载applicationContext-common.xml并实例化上下文bean,如果有些线程配置类也是在这个配置文件中,那么会造成做相同工作的的线程会被启两次。一次是web容器初始化时启动,另一次是上述代码显示的实例化了一次。当于重新初始化一遍!!!!这样就产生了冗余。解决方法
不用类似new ClassPathXmlApplicationContext()的方式,从已有的spring上下文取得已实例化的bean。通过ApplicationContextAware接口进行实现。 当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。 换句话说,就是这个类可以直接获取spring配置文件中,所有有引用到的bean对象。
1基于@Autowired (简单)
首先说一下spring Autowired 注解除了我们正常使用的之外还有一点:
@Autowired标注作用于 Map 类型时,如果 Map 的 key 为 String 类型,则 Spring 会将容器中所有类型符合 Map 的 value 对应的类型的 Bean 增加进来,用 Bean 的 id 或 name 作为 Map 的 key。非常牛X的操作。
需要注意的是:应用于map的时候key必须为String类型(实现类的名字)
下面是网上的例子
public class x{
@Autowired //@Autowired标注作用于 Map 类型时,如果 Map 的 key 为 String 类型,则 Spring 会将容器中所有类型符合 Map 的 value 对应的类型的 Bean 增加进来,用 Bean 的 id 或 name 作为 Map 的 key。非常牛X的操作。
private Map<String, PayStrategy> payStategies;
@RequestMapping(value = "/pay",method = RequestMethod.GET)
public Object pay(int storeType, String version, int channel,.....) {
PayStrategy payStrategy = null;
PayChannelStrategyEnum payChannelStrategyEnum = PayChannelStrategyEnum.getPayChannelStrategyEnum(channel);
if (payChannelStrategyEnum == null) {
outMap.put("code", "fail");
outMap.put("messge", "支付通道异常");
return outMap;
}
for (Map.Entry<String, PayStrategy> entry : payStategies.entrySet()) { //这里是关键了,便利这个map
if (payChannelStrategyEnum.getPayStrategy().equals(entry.getValue().getClass().getSimpleName())) {
payStrategy = entry.getValue();
}
}
if (payStrategy != null) {
Map<String, Object> params = new ConcurrentHashMap<String, Object>();
params.put("storeType",storeType);
params.put("version",version);
。。。。。。
Map map = payStrategy.doPay(params);
return map;
}
}
}
下面是公司pay.core的实际例子
着重看看这个就够了
/**
*注册所有策略,并提供获取具体策略实现类的方法;
*/
@Component("fundPayServiceContext")
public class FundPayServiceContext {
@Autowired
private final Map<String, IFundPayService> strategyMap = new ConcurrentHashMap<>(PlatformEunm.values().length);
//这里其实不用实例化的;只写private final Map<String, IFundPayService> strategyMap;就够了
//这里就是自动注册了所有策略接口的实现类;
//这里是获取具体策略的实现对象
public IFundPayService getService(Long tenantId) { //参数是传进来的,不用纠结
FundPayServiceEunm parkEnum = FundPayServiceEunm.valueOf(tenantId); //枚举
if (Objects.isNull(parkEnum)) {
parkEnum = FundPayServiceEunm.ERP_BASE_PLATFORM;//枚举
}
return strategyMap.get(parkEnum.getServiceName()); // 从map中取出想要的bean 枚举
}
}
-------------------------------------------------------------------
/*枚举 这个就是个辅助,上一个类用到这个而已*/
public enum FundPayServiceEunm {
ERP_BASE_PLATFORM(PlatformConstants.ERP_TENANT_ID, "fundPayService", "ERP平台"),
MALL_PLATFORM(PlatformConstants.MALL_TENANT_ID, "mallFundPayService", "商城平台"),
;
private Long tenantId;
private String serviceName;
private String desc;
FundPayServiceEunm(Long tenantId, String serviceName, String desc) {
this.tenantId = tenantId;
this.serviceName = serviceName;
this.desc = desc;
}
--------------------------------------------------------------------
/*策略接口*/
public interface IFundPayService {
/** 接口方法:支付 */
FundTransferQRVo pay(AllinPayQRCodeDto allinPayQRCodeDto) throws Exception;
----------------------------------------------------------------------------
/*具体策略实现类1 erp平台*/
@Service("fundPayService") //本实例中根据这个value获取bean
@Slf4j
public class FundPayService implements IFundPayService {
--------------------------------------------------------------------------
/*具体策略实现类2 商城平台*/
@Service("mallFundPayService")//本实例中根据这个value获取bean
@Slf4j
public class MallFundPayService implements IFundPayService {
2 基于getBeansOfType (代码多,但是可读性高)
这个就是基于spring得技术(需要配合ApplicationContextAware.java一起),相对来说代码稍微多了点, 但是可读性要好了很多!! 后续再补充吧;
https://www.cnblogs.com/zhoading/p/14663454.html
https://blog.csdn.net/qq_39237801/article/details/112299013
1 需求:
在springboot项目中,为了方便,我们可能需要获取某一个接口下面的所有实现类,根据名称进行匹配使用。
2 示例 (参照下面的实例,我写了一个demo放到了gitee上;https://gitee.com/binC_2016/getServiceImpls)
- 1 ```java package com.yang.config;
import com.yang.workOrder.service.IRootService; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component;
import java.util.Map;
/**
explain:获取应用上下文并获取相应的接口实现类 */ @Component public class ServiceLocator implements ApplicationContextAware {
/**
用于保存接口实现类名及对应的类 */ private Map
map; /**
- 获取应用上下文并获取相应的接口实现类
- @param applicationContext
@throws BeansException */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { //根据接口类型返回相应的所有bean map = applicationContext.getBeansOfType(IRootService.class); //关键点 getBeansOfType }
/**
- 获取所有实现集合
@return */ public Map
getMap() { return map; } /**
- 获取对应服务
- @param key
- @return */ public IRootService getService(String key) { return map.get(key); } }
2. 接口
```java
package com.yang.workOrder.service;
import com.alibaba.fastjson.JSONObject;
import com.yang.workOrder.entity.WorkOrder;
/**
* service层接口
*/
public interface IRootService {
/** 开始流程*/
boolean startProcess(WorkOrder workOrder);
}
- 实现1 (策略实现1) ```java package com.yang.workOrder.service.impl;
import com.alibaba.fastjson.JSONObject; import com.yang.workOrder.entity.WorkOrder; import com.yang.workOrder.service.IRootService; import org.springframework.stereotype.Service; import lombok.extern.slf4j.Slf4j;
/**
- service层接口实现类A1
*/
@Service(“A_001”)
@Slf4j
public class RootA001ServiceImpl implements IRootService {
@Override
public boolean startProcess(WorkOrder workOrder) {
} }return false;
4. 实现2 (策略实现2)
```java
package com.yang.workOrder.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.yang.workOrder.entity.WorkOrder;
import com.yang.workOrder.service.IRootService;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
/**
* service层接口实现类A2
*/
@Service("A_002")
public class RootA002ServiceImpl implements IRootService {
@Override
public boolean startProcess(WorkOrder workOrder) {
return false;
}
}
- 获取到了所有IRootService的实现类