SpringPlugin-Core在业务中的应用
2021-10-12 22:44
961 查看
前言
一直负责部门的订单模块,从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 { }
第三步 、定义具体的实现类(支付操作、关闭操作)
@Component public class PayOperator implements OrderOperatorPlugin { @Override public Optional<?> apply(OrderOperatorDTO opera 56c tor) { //支付操作 //doPay() return Optional.of("支付成功"); } @Override public boolean supports(OrderOperatorDTO operatorDTO) { return operatorDTO.getOperatorType() == OrderOperatorType.PAY; } } @Component public class ClosedOperator implements OrderOperatorPlugin { @Override public Optional<?> apply(OrderOperatorDTO operator) { //关闭操作 //doClosed() return Optional.of("关闭订单成功"); } @Override public boolean supports(OrderOperatorDTO operatorDTO) { return operatorDTO.getOperatorType() == OrderOperatorType.CLOSED; } }
这里要注意的是实现
supports方法,此方法返回的是一个
boolean值,直观的看起来就是一个选择器的条件,这里可直接认为,当
Support返回
True的时候,就找到了当前操作的实现类!
两个不同的实现类定义好,那么我们怎么找到具体的实现类呢?
最后、定义业务接口,和业务实现类
public interface OrderService { /** * 操作订单接口 * @param operator * @return */ Optional<?> operationOrder(OrderOperatorDTO operator); } @Service public class OrderServiceImpl implements OrderSe 56c rvice { @Resource PluginRegistry<OrderOperatorPlugin, OrderOperatorDTO> orderOperatorPluginRegistry; @Override public Optional<?> operationOrder(OrderOperatorDTO operator) { OrderOperatorPlugin pluginFor = orderOperatorPluginRegistry.getPluginFor(operator); return pluginFor.apply(operator); } }
在业务接口实现类里我们注入了
@Resource PluginRegistry<OrderOperatorPlugin, OrderOperatorDTO> orderOperatorPluginRegistry;
名字一定是 接口名 + Registry,我这里是
orderOperatorPluginRegistry至于为什么要这样写,等回我们分析源码的时候看一下。目前这样写就对了。
接下来我们测试下
@RunWith(SpringRunner.class) @SpringBootTest public class OrderOperatorPluginTest { @Resource OrderService orderService; @Resource ApplicationContext applicationContext; @Test public void test_operation_closed() { final OrderOperatorDTO operator = new OrderOperatorDTO(); operator.setOperatorType(OrderOperatorType.CLOSED); Optional<?> optionalO = orderService.operationOrder(operator); Assertions.assertEquals("关闭订单成功", optionalO.get()); } @Test public void ad8 test_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) { //当前我只注册了一个 插件 OrderOperatorPlugin Class<?>[] types = (Class[])((Class[])importingClassMetadata.getAnnotationAttributes(EnablePluginRegistries.class.getName()).get("value")); Class[] var4 = types; int var5 = types.length; ad0 //长度也就为1 for(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; }
相关文章推荐
- SpringBoot+ZooKeeper+ZKUI+Drools 实现应用配置中心及业务规则动态加载
- SpringAOP在江西省财政综合业务系统的应用方案
- grails 之 Spring Security Core Plugin 使用
- Spring事务是如何应用到你的业务场景中的?
- Grails 之 Acegi Plugin 转移到Spring Security Core Plugin
- 熟悉公司业务springboot和dataTable和validate在项目中的应用(1)
- 导入所需要的jar包: xwork-core-2.2.1.jarxwork-core-2.2.1.jar struts2-spring-plugin-2.2.1.jarstruts2-spring-plugin-2.2.1.jar struts2-cor
- springBoot事件监听 在项目实际业务中的异步应用
- spring-core组件详解——Environment应用上下文环境
- Spring Security Core Plugin - 5. 配置到安全URL的请求映射
- spring aop 应用场景
- 利用SpringCloud和Docker搭建普通互联网应用架构
- Struts2 conventionplugin + spring 自动扫描jar包中的action
- Spring Boot简单应用——会员管理系统
- 使用spring-loaded实现应用热部署
- struts+spring+hibernate的web应用 Dao层代码编写
- 详解设计模式在Spring中的应用
- spring cloud+dotnet core搭建微服务架构:配置中心
- Spring 5 的 WebFlux 开发反应式 Web 应用
- 用Spring Boot颠覆Java应用开发