当前位置: 首页 > news >正文

Spring Boot顶层接口实现类注入项目的方法

1、背景

 在项目中,我们通常会具有同一特性的业务类定义一个顶层接口,让业务类实现这个接口,通过接口规范来管理这些类。我们将这些实现接口的业务类交托给Spring容器接口后,有时候需要根据业务类型来选择动态选择对应的业务类阿里处理业务。这个时候就获取到这些业务类并进行管理,在需要时取出对应的业务类处理业务。如何管理就是本期要介绍的内容。
 以下是我定义的一个简单的顶层接口,它有两个方法,一个是提供类型的getType()方法,一个是处理业务的hanlde()方法。我们的任务就是对其实现类进行管理,当需要时可根据类型获取对应实现类。

public interface IBaseHandler {/*** 获取处理器类型* @return 处理器类型*/int getType();/*** 处理业务* @param t 业务数据* @param <T> 业务数据类型*/<T> void handler(T t);
}

2、简单的管理方法

 我们可以通过使用@Autowired注解将所有实现了IBaseHandler接口的类注入到项目当中,并在需要时遍历业务类对象,获取对应的对象来处理业务。代码如下所示:

    @Autowiredprivate List<IBaseHandler> handlers;/*** 处理业务* @param type 业务类型* @param data 业务数据* @param <T> 业务数据类型*/public <T> void handle(int type, T data) {handlers.stream().filter(handler -> handler.getType() == type).findAny().orElseThrow(() -> {// 获取不到业务类对象时打印日志并抛出异常log.error("Failed to get handler, type:{}", type);return new NoSuchElementException("No such handler");}).handler(data);}

3、更好的管理方法

1、简单管理方法的弊端

 上面的简单管理方法用起来方便,但是有两个弊端:
  (1)耦合度高,所有需要使用该接口的地方都需要进行注入再遍历的过程。
  (2)性能较差,每次执行业务之前都需要遍历一次列表。

2、解决

 我们可以使用一个工具类,提供静态方法来获取业务类。这样所有需要获取业务类的地方,就都可以通过该工具类一步获取到所需的业务类。代码如下:

1、工具类代码

@Slf4j
public class HandlerManager {/*** 按照type映射的处理器map*/private static Map<Integer, IBaseHandler> typeHandlerMap = new HashMap<>();/*** 按照类型映射的处理器map*/private static Map<Class<IBaseHandler>, IBaseHandler> clazzHandlerMap = new HashMap<>();/*** 初始化方法,项目启动时调用该方法来初始化map* @param applicationContext spring 上下文对象*/public static void init(ApplicationContext applicationContext) {List<IBaseHandler> handlers = new ArrayList<>();applicationContext.getBeansOfType(IBaseHandler.class).forEach((name, obj) -> handlers.add(obj));// 为了方便,两次循环构建map,一次循环也可以解决,不过人为定义的handler数量不多,一次循环性能提升不大typeHandlerMap = handlers.stream().collect(Collectors.toMap(IBaseHandler::getType, obj -> obj));clazzHandlerMap = handlers.stream().collect(Collectors.toMap(obj -> (Class<IBaseHandler>) obj.getClass(), obj -> obj));}public IBaseHandler getHandlerByType(int type) {return Optional.ofNullable(typeHandlerMap.get(type)).orElseThrow(() -> {// 获取不到处理器打印日志并抛出异常log.info("Failed to get handler, type:{}", type);return new NoSuchElementException("No such  handler error");});}public IBaseHandler getHandlerByClass(Class<IBaseHandler> clazz) {return Optional.ofNullable(clazzHandlerMap.get(clazz)).orElseThrow(() -> {// 获取不到处理器打印日志并抛出异常log.info("Failed to get handler, clazz:{}", clazz);return new NoSuchElementException("No such  handler error");});}}

2、调用工具类的init方法

 由于工具类提供的是静态方法,因此无法通过注入的方式来获取到所有的IBaseHanlder,所以需要借助其他可注入IBaseHanlder的类来初始化管理对象,以下是方法:

/*** 项目初始化类* 继承ApplicationContextAware,实现setApplicationContext,可获取ApplicationContext来获取上下文*/
@Component
public class ApplicationInit implements ApplicationContextAware {@Autowiredprivate List<IBaseHandler> handlers;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {// 调用处理器工具类初始化方法HandlerManager.init(applicationContext);}
}

相关文章:

  • 【复旦邱锡鹏教授《神经网络与深度学习公开课》笔记】线性分类模型损失函数对比
  • 深度学习500问——Chapter12:网络搭建及训练(1)
  • 50.Python-web框架-Django中引入静态的bootstrap样式
  • 基于springSecurity的双token机制(accesToken,refreshToken)以及如何刷新token
  • windows文件及文件夹加密后无法解除加密
  • python tensorflow 各种神经元
  • Java 读取Excel导入数据库,形成树状结构
  • 基于若依的ruoyi-nbcio流程管理系统增加所有任务功能(一)
  • Flask快速入门(路由、CBV、请求和响应、session)
  • 数据结构-算法和算法分析
  • Kafka 负载均衡挑战及解决思路
  • 深入理解预处理
  • Microsoft Edge 查看已保存账号的密码
  • 排序算法及源代码
  • OpenCV--形态学
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • MySQL主从复制读写分离及奇怪的问题
  • Python 基础起步 (十) 什么叫函数?
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • vue--为什么data属性必须是一个函数
  • WePY 在小程序性能调优上做出的探究
  • 从输入URL到页面加载发生了什么
  • 技术胖1-4季视频复习— (看视频笔记)
  • 聊聊directory traversal attack
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 如何设计一个比特币钱包服务
  • 实现简单的正则表达式引擎
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 我的面试准备过程--容器(更新中)
  • 一些css基础学习笔记
  • 智能合约Solidity教程-事件和日志(一)
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • Linux权限管理(week1_day5)--技术流ken
  • 大数据全解:定义、价值及挑战
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • $NOIp2018$劝退记
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (C++17) std算法之执行策略 execution
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (附源码)spring boot基于小程序酒店疫情系统 毕业设计 091931
  • (利用IDEA+Maven)定制属于自己的jar包
  • (六)激光线扫描-三维重建
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • ****三次握手和四次挥手
  • .net core 3.0 linux,.NET Core 3.0 的新增功能
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .net 微服务 服务保护 自动重试 Polly
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • .NET开源、简单、实用的数据库文档生成工具
  • .NET项目中存在多个web.config文件时的加载顺序