https://github.com/admin4j/spring-plugin
基于Spring实现,极轻巧的设计模式插件
https://github.com/admin4j/spring-plugin
Last synced: 10 months ago
JSON representation
基于Spring实现,极轻巧的设计模式插件
- Host: GitHub
- URL: https://github.com/admin4j/spring-plugin
- Owner: admin4j
- License: apache-2.0
- Created: 2023-09-12T07:22:49.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2024-05-14T07:02:42.000Z (almost 2 years ago)
- Last Synced: 2024-05-15T13:31:01.131Z (almost 2 years ago)
- Language: Java
- Size: 30.3 KB
- Stars: 8
- Watchers: 1
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# 一行代码搞定Spring策略模式
在Spring中大量使用策略模式来简化`if/else`代码,比如Spring Security 的各种`AuthenticationProvider`等等,但是实现方式过于麻烦,使用重复套路来实现。
## 一般基于Spring的策略实现
> 场景:关于用户订单充值(订单支付同理),我们都知道,现今的支付方式是非常的多的,例如:支付宝、微信、银联、钱包(各个APP的账户余额)等等。
**查询实体Query:**
```
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChargeQuery {
private BigDecimal money;
private String channel;
}
```
**支付接口**
```
public interface PayWayHandler {
String handler(ChargeQuery query);
}
```
**阿里支付功能实现**
```
@Service
@Order(9)
public class AliPayWayHandler implements PayWayHandler {
/**
* 支持什么类型
*
* @return
*/
@Override
public String support() {
return "Ali";
}
@Override
public String handler(ChargeQuery query) {
System.out.println("query = " + query);
return "使用了" + support() + "支付了";
}
}
```
**微信支付实现**
```
@Service
@Order(12)
public class WxPayWayHandler implements PayWayHandler {
/**
* 支持什么类型
*
* @return
*/
@Override
public String support() {
return "Wx";
}
@Override
public String handler(ChargeQuery query) {
System.out.println("query = " + query);
return "使用了" + support() + "支付了";
}
}
```
### **支付调用**
```
Map payWayHandlerMap = context.getBeansOfType(PayWayHandler.class);
ChargeQuery chargeQuery = new ChargeQuery(new BigDecimal(100), "Ali");
for (PayWayHandler payWayHandler : payWayHandlerMap.values()) {
//匹配到支持的渠道类型
if (chargeQuery.getChannel().equals(payWayHandler.support())) {
payWayHandler.handler(chargeQuery);
break;
}
}
```
可以看到这边通过for循环来查找实现bean,虽然相比不用策略模式使用`if/else`
简单多了。但是遇到其他的业务或者其他的策略模式,这边的for循环逻辑还是需要再写一遍。基于封装原则,为了减少重复代码,我为大家提供了`spring-plugin`
工具类,实现一行代码搞定列策略模式。下面进入正文。
## spring-plugin实现策略模式
### POM引入
```
com.admin4j.spring
spring-plugin
0.8.1
```
[最新版查看:https://central.sonatype.com/artifact/com.admin4j.spring/spring-plugin](https://central.sonatype.com/artifact/com.admin4j.spring/spring-plugin)
### 实现代码
```
//"Ali" 支付
ChargeQuery aliChargeQuery = new ChargeQuery(new BigDecimal(100), "Ali");
String handler = ProviderManager.load(PayWayHandler.class, aliChargeQuery.getChannel()).handler(aliChargeQuery);
```
最终使用`String handler = ProviderManager.load(PayWayHandler.class, aliChargeQuery.getChannel()).handler(aliChargeQuery);`
一行代码搞定了策略模式,减少了重复代码块。
### 实现原理
实现原理也是相当的简单,看一遍就懂了
```
public class ProviderManager {
private ProviderManager() {
}
/**
* Spring 的 IOC 容器,默认为空。
* 默认使用了 SpringUtils(admin4j-common-spring包里) 来获取ApplicationContext。如果不想多引入`admin4j-common-spring`包的话,可将他排除
*/
public static ApplicationContext APPLICATION_CONTEXT;
private static final Map>, Collection>> CACHED_PROVIDERS = new ConcurrentHashMap<>();
/**
* 加载 Provider
*
* @param providerClass 给定的Class
* @param support 支持的策略
* @return 最终的支持策略的 Provider
*/
public static > T load(Class providerClass, String support) {
Collection providers = loadProvider(providerClass);
for (Provider> provider : providers) {
if (Objects.equals(provider.support(), support)) {
return (T) provider;
}
}
return null;
}
/**
* 返回所有的 Provider
*
* @param providerClass 给定的Class
* @return 所有的 Provider
*/
public static > Collection all(Class providerClass) {
return loadProvider(providerClass);
}
/**
* 通过class获取所有的 beans
*/
private static > Collection loadProvider(Class providerClass) {
return (Collection) CACHED_PROVIDERS.computeIfAbsent((Class>) providerClass, key -> {
if (APPLICATION_CONTEXT == null) {
APPLICATION_CONTEXT = SpringUtils.getApplicationContext();
}
Map beansOfType = APPLICATION_CONTEXT.getBeansOfType(providerClass);
Collection values = beansOfType.values();
ArrayList ts = new ArrayList<>(values);
AnnotationAwareOrderComparator.sort(ts);
return (Collection>) ts;
});
}
}
```