AI智能
改变未来

SpringPlugin-Core在业务中的应用


前言

一直负责部门的订单模块,从php转到Java也是如此,换了一种语言来实现订单相关功能。那么Spring里有很多已经搭建好基础模块的设计模式来帮助我们解耦实际业务中的逻辑,用起来非常的方便!就比如我们的订单操作模块。生成订单后,有很多操作。比如:取消、支付、关闭….等等。那么用设计模式的思想去处理这些不同的操作,最好用的就是策略模式来解决它们!把不同的操作分配到不同的实现类里去。这不,我发现了一个不错的东西

Spring plugin

!

Spring Plugin

Spring plugin

这个小东西我也是在看一些开源项目才看到的,感觉还不错。就立马拿来用了下,把它带到我们业务场景里去。这不,带大家体验下。

下面用

Spring plugin

来重构下订单的相关操作实现。这里我们只模拟,支付和关闭的操作。最后再来简单分析下

Spring plugin

的原理

实战

首先呢、定义一个操作类型的枚举类,来边界下当前我们系统支持的操作类型!

public enum OrderOperatorType {/*** 关闭*/CLOSED,/*** 支付*/PAY;}

第二步、定义操作接口,实现

Spring plugin

Plugin<S>

接口,和配置插件

public interface OrderOperatorPlugin extends Plugin<OrderOperatorDTO> {/*** 定义操作动作* @param operator* @return*/public Optional<?> apply(OrderOperatorDTO operator);}//配置插件,插件写好了,我们要让插件生效!@Configuration@EnablePluginRegistries({OrderOperatorPlugin.class})public class OrderPluginConfig {}

第三步 、定义具体的实现类(支付操作、关闭操作)

@Componentpublic class PayOperator implements OrderOperatorPlugin {@Overridepublic Optional<?> apply(OrderOperatorDTO opera56ctor) {//支付操作//doPay()return Optional.of(\"支付成功\");}@Overridepublic boolean supports(OrderOperatorDTO operatorDTO) {return operatorDTO.getOperatorType() == OrderOperatorType.PAY;}}@Componentpublic class ClosedOperator implements OrderOperatorPlugin {@Overridepublic Optional<?> apply(OrderOperatorDTO operator) {//关闭操作//doClosed()return Optional.of(\"关闭订单成功\");}@Overridepublic boolean supports(OrderOperatorDTO operatorDTO) {return operatorDTO.getOperatorType() == OrderOperatorType.CLOSED;}}

这里要注意的是实现

supports

方法,此方法返回的是一个

boolean

值,直观的看起来就是一个选择器的条件,这里可直接认为,当

Support

返回

True

的时候,就找到了当前操作的实现类!

两个不同的实现类定义好,那么我们怎么找到具体的实现类呢?

最后、定义业务接口,和业务实现类

public interface OrderService {/*** 操作订单接口* @param operator* @return*/Optional<?> operationOrder(OrderOperatorDTO operator);}@Servicepublic class OrderServiceImpl implements OrderSe56crvice {@ResourcePluginRegistry<OrderOperatorPlugin, OrderOperatorDTO> orderOperatorPluginRegistry;@Overridepublic Optional<?> operationOrder(OrderOperatorDTO operator) {OrderOperatorPlugin pluginFor = orderOperatorPluginRegistry.getPluginFor(operator);return pluginFor.apply(operator);}}

在业务接口实现类里我们注入了

@ResourcePluginRegistry<OrderOperatorPlugin, OrderOperatorDTO> orderOperatorPluginRegistry;

名字一定是 接口名 + Registry,我这里是

orderOperatorPluginRegistry

至于为什么要这样写,等回我们分析源码的时候看一下。目前这样写就对了。

接下来我们测试下

@RunWith(SpringRunner.class)@SpringBootTestpublic class OrderOperatorPluginTest {@ResourceOrderService orderService;@ResourceApplicationContext applicationContext;@Testpublic void test_operation_closed() {final OrderOperatorDTO operator = new OrderOperatorDTO();operator.setOperatorType(OrderOperatorType.CLOSED);Optional<?> optionalO = orderService.operationOrder(operator);Assertions.assertEquals(\"关闭订单成功\", optionalO.get());}@Testpublic voidad8test_operation_pay() {final OrderOperatorDTO operator = new OrderOperatorDTO();operator.setOperatorType(OrderOperatorType.PAY);Optional<?> optionalO = orderService.operationOrder(operator);Assertions.assertEquals(\"支付成功\", optionalO.get());}}

这个运行结果是没有问题的,可以自己把代码下载下来,跑一下~~??

感受

如果我把整个订单的流程都当作不同的插件来开发的话…创建订单是一个流程、在这个流程的过程中,我们分别在不同的位置插入不同的插件。比如下图!


最后,这只把所以

Plugin

组织起来,是不是就可以搞定一套完整的订单流程了,而我们做的只是面对插件开发,把注意力集中到某个插件中就可以了呢?或许下次订单重构的时候,我可以会这样的去尝试下!

源码重点分析

首先看下注册插件的注释

EnablePluginRegistries

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documented@Import({PluginRegistriesBeanDefinitionRegistrar.class})public @interface EnablePluginRegistries {Class<? extends Plugin<?>>[] value();}

value

属性是一个数组,必须实现

Plugin

接口,这个是定义插件的基本条件~。

再看

Import

注释,

PluginRegistriesBeanDefinitionRegistrar

实现了

ImportBeanDefinitionRegistrar

接口,这个有点味道了,

public class PluginRegistriesBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {}

之前我有一个文章是分析相关加载类到容器的一篇文章,请看下面文章的介绍。

ImportBeanDefinitionRegistrar的作用

直接看核心代码

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//当前我只注册了一个 插件 OrderOperatorPluginClass<?>[] types = (Class[])((Class[])importingClassMetadata.getAnnotationAttributes(EnablePluginRegistries.class.getName()).get(\"value\"));Class[] var4 = types;int var5 = types.length;ad0//长度也就为1for(int var6 = 0; var6 < var5; ++var6) {Class<?> type = var4[var6];//是FactoryBean 见名思义。PluginRegistryFactoryBean#getObject 的方法最终返回的是 OrderAwarePluginRegistry 看名字是支持排序的功能。BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(PluginRegistryFactoryBean.class);builder.addPropertyValue(\"type\", type);AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();Qualifier annotation = (Qualifier)type.getAnnotation(Qualifier.class);if (annotation != null) {AutowireCandidateQualifier qualifierMetadata = new AutowireCandidateQualifier(Qualifier.class);qualifierMetadata.setAttribute(AutowireCandidateQualifier.VALUE_KEY, annotation.value());beanDefinition.addQualifier(qualifierMetadata);}//插件上没有添加 Qualifier 所以为null, nulll的话就给拼接上 Registry! 这就是为啥注入的时候用 插件名 + Registry、另外 PluginRegistryFactoryBean实现了PluginRegistry。String beanName = annotation == null ? StringUtils.uncapitalize(type.getSimpleName() + \"Registry\") : annotation.value();registry.registerBeanDefinition(beanName, builder.getBeanDefinition());}}

那么注入容器后,调用

getPluginFor

找到当前策略的实现类。

// OrderAwarePluginRegistry 类public T getPluginFor(S delimiter) {Iterator var2 = super.getPlugins().iterator();Plugin plugin;do {if (!var2.hasNext()) {return null;}plugin = (Plugin)var2.next();//这里判断 supports的方法 返回true时即跳出Loop} while(plugin == null || !plugin.supports(delimiter));return plugin;}//另外 super.getPlugins里 会调用 initializa的方法,即插件是支持排序功能的,只要在插件上加入Order()注释即可。protected List<T> initialize(List<T> plugins) {List<T> result = super.initialize(plugins);Collections.sort(result, this.comparator);return result;}

代码在GitHub

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » SpringPlugin-Core在业务中的应用