枚举的高阶用法之枚举里写方法以及注入spring的bean
1、前言
一般我们使用枚举都是用来定义一些常量。比如我们需要一个表示订单类(pc订单、手机订单)的常量,那我们就可以使用枚举来实现,如下:
@AllArgsConstructor
public enum OrderTypeEnum{PC("PC", "电脑端"),PHONE("PHONE", "手机端");private String name;private String value;}
接着再写一下根据name查找对应枚举的方法,枚举就算完成了。但比如我们的业务场景是这样的:我们有一个OrderTypeService接口及其实现类。
public interface OrderTypeService {String processPc(String order);String processPhone(String order);
}
@Service
public class OrderTypeServiceImpl implements OrderTypeService {@Overridepublic String processPc(String order) {//具体的处理pc订单的业务逻辑System.out.println("开始处理pc订单:" + order);return null;}@Overridepublic String processPhone(String order) {//具体的处理phone订单的业务逻辑System.out.println("开始处理phone订单:" + order);return null;}
}
根据接口的方法名我们一眼就知道,processPc是用来处理PC订单的;processPhone是用来处理PHONE订单的。然后再实际调用这两个方法的地方就需要我们进行if-else的判断。这里的if-else判断的缺点是:代码扩展性很差,如果以后又增加了其它订单类型,我们还需要改这里的if-else逻辑。
if (OrderTypeEnum.PC.equals(orderTypeEnum)) {orderTypeService.processPc("order");} else if (OrderTypeEnum.PHONE.equals(orderTypeEnum)) {orderTypeService.processPhone("order");}
2、思考
针对以上if-else判断存在的问题,那我们能不能把调用各自业务逻辑的代码挪到枚举里呢?肯定是可以的,本期我们就来实现一下。
2.1、通过@PostConstruct注解
在枚举内定义BeanInjector,再通过PostConstruct注解的方法给枚举的orderTypeService属性注入bean。
@AllArgsConstructor
public enum OrderTypeEnum {PC("PC", "电脑端") {@Overridepublic void handle(String order) {orderTypeService.processPc(order);}},PHONE("PHONE", "手机端") {@Overridepublic void handle(String order) {orderTypeService.processPhone(order);}};private String name;private String value;protected static OrderTypeService orderTypeService;public abstract void handle(String order);@Componentpublic static class BeanInjector {@Autowiredprivate OrderTypeService orderTypeService;@PostConstructpublic void postConstruct() {OrderTypeEnum.orderTypeService = this.orderTypeService;}}
}
调用代码:
OrderTypeEnum pcOrderType = OrderTypeEnum.PC;pcOrderType.handle("1");
输出结果:
开始处理pc订单:1
2.2、在枚举内实现ApplicationContextAware回调接口,获取到ApplicationContext,再从context里获取我们需要的bean
@AllArgsConstructor
public enum OrderTypeEnum {PC("PC", "电脑端") {@Overridepublic void handle(String order) {OrderTypeService orderTypeService = OrderTypeEnum.ApplicationContextProvider.getApplicationContext().getBean(OrderTypeService.class);orderTypeService.processPc(order);}},PHONE("PHONE", "手机端") {@Overridepublic void handle(String order) {OrderTypeService orderTypeService = OrderTypeEnum.ApplicationContextProvider.getApplicationContext().getBean(OrderTypeService.class);orderTypeService.processPhone(order);}};private String name;private String value;public abstract void handle(String order);@Componentpublic static class ApplicationContextProvider implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {context = applicationContext;}public static ApplicationContext getApplicationContext() {return context;}}
}
调用代码同2.1
输出结果同2.1
2.3、还是需要实现ApplicationContextAware接口,但这次不是直接使用ApplicationContext,而是把ApplicationContext里的bean值直接注入到我们的枚举字段中。
public enum OrderTypeEnum {PC("PC", "电脑端") {@Overridepublic void handle(String order) {orderTypeService.processPc(order);}},PHONE("PHONE", "手机端") {@Overridepublic void handle(String order) {orderTypeService.processPhone(order);}};private String name;private String value;OrderTypeEnum(String name, String value) {this.name = name;this.value = value;}public abstract void handle(String order);@AutowiredOrderTypeService orderTypeService;
}
@Component
public class OrderTypeEnumInjector implements ApplicationContextAware {@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {for (OrderTypeEnum orderTypeEnum : OrderTypeEnum.values()) {applicationContext.getAutowireCapableBeanFactory().autowireBean(orderTypeEnum);}}
}
调用代码同2.1
输出结果同2.1
这里重点是使用applicationContext.getAutowireCapableBeanFactory().autowireBean。它可以把枚举中使用了@Autowired注解的字段和applicationContext中的bean根据类型和名称做匹配,匹配到之后就会把bean注入到该字段中。从而枚举中的orderTypeService就有值了。
3、延申
applicationContext.getAutowireCapableBeanFactory().autowireBean能否给普通的类(没有被spring管理)的字段注入bean呢?答案也是可以的,这里最好把这个普通对象定义成单例的,这样我们给字段注入一次bean就可以一直使用了,否则每次new 的时候还需要重新注入bean。
public class OrderTypeManager {private OrderTypeManager(){}private static OrderTypeManager orderTypeManager = null;public synchronized static OrderTypeManager getInstance(){if(orderTypeManager == null){orderTypeManager = new OrderTypeManager();}return orderTypeManager;}@Autowiredprivate OrderTypeService orderTypeService;public void test(){orderTypeService.processPhone("2");}
}
如上定义了一个单例的OrderTypeManager,但是OrderTypeManager没有被spring所管理,那我们怎么把OrderTypeService这个bean注入到orderTypeService字段里呢?
@Component
public class OrderTypeEnumInjector implements ApplicationContextAware {@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {for (OrderTypeEnum orderTypeEnum : OrderTypeEnum.values()) {applicationContext.getAutowireCapableBeanFactory().autowireBean(orderTypeEnum);}OrderTypeManager orderTypeManager = OrderTypeManager.getInstance();applicationContext.getAutowireCapableBeanFactory().autowireBean(orderTypeManager);}
}
调用代码:
OrderTypeManager orderTypeManager = OrderTypeManager.getInstance();orderTypeManager.test();
输出结果:
开始处理phone订单:2
相关文章:
枚举的高阶用法之枚举里写方法以及注入spring的bean
1、前言 一般我们使用枚举都是用来定义一些常量。比如我们需要一个表示订单类(pc订单、手机订单)的常量,那我们就可以使用枚举来实现,如下: AllArgsConstructor public enum OrderTypeEnum{PC("PC", "电脑端"),PHONE("PHONE", "手机端&quo…...
游戏开发面试题2
网络游戏分为客户端和服务端,你能说说客户端和服务端都干了一些什么工作吗? 客户端(Client) 客户端是玩家直接交互的部分,主要负责用户界面、输入处理、渲染和部分逻辑处理。具体工作包括: 用户界面&…...
华为机试题-单车道汽车通行时间-Java
代码在最后面 1 题目描述 M(1 ≤ M ≤ 20)辆车需要在一条不能超车的单行道到达终点,起点到终点的距离为 N(1 ≤ N ≤ 400)。 速度快的车追上前车后,只能以前车的速度继续行驶,求最后一辆车到达…...
6-5,web3浏览器链接区块链(react+区块链实战)
6-5,web3浏览器链接区块链(react区块链实战) 6-5 web3浏览器链接区块链(调用读写合约与metamask联动) 6-5 web3浏览器链接区块链(调用读写合约与metamask联动) 这里就是浏览器端和智能合约的交…...
C# 多态性
C# 多态性 介绍 多态性是面向对象编程(OOP)的一个核心概念,它允许不同类的对象对同一消息做出响应,并产生不同的结果。在C#中,多态性主要通过继承、接口和虚方法来实现。本文将深入探讨C#中的多态性,包括其原理、实现方式以及在实际编程中的应用。 原理 多态性允许将…...
Visual Studio 安装程序无法执行修复或更新
一.问题场景 出现问题的场景:当你的VS已经安装但是无法在工具中下载新组件或者卸载了当时一直无法安装。 二.问题原因 如果计算机上的 Visual Studio 实例已损坏,则可能会出现此问题。 三.解决方法 如果之前尝试修复或更新 Visual Studio 失败&…...
C#与PLC通信——如何设置电脑IP地址
前言: 我们与PLC通过以太网通信时,首先要做的就是先设置好电脑的IP,这样才能实现上位机电脑与PLC之间的通信,并且电脑的ip地址和PLC的Ip地址要同处于一个网段,比如电脑的Ip地址为192.168.1.1,那么PLC的Ip地…...
Milvus 核心设计(1) ---- 数据一致性的等级及使用场景
目录 背景 Milvus的数据一致性 设置数据一致性等级 等级类型 PACELC定理 level 详细解释 Strong Bounded staleness Session Eventually 总结 背景 分布式上的可扩展性是个比较重要的concept。Chroma 核心之前写过了,他的最大优势在于轻量级且好用。Milvus相对Ch…...
EasyCVR视频技术:城市电力抢险的“千里眼”,助力抢险可视化
随着城市化进程的加速和电力需求的不断增长,电力系统的稳定运行对于城市的正常运转至关重要。然而,自然灾害、设备故障等因素常常导致电力中断,给城市居民的生活和企业的生产带来严重影响。在这种情况下,快速、高效的电力抢险工作…...
【Wamp】局域网设备访问WampServer | 使用域名访问Wamp | Wamp配置HTTPS
局域网设备访问WampServer 参考:https://www.jianshu.com/p/d431a845e5cb 修改Apache的httpd.conf文件 D:\Academic\Wamp\program\bin\apache\apache2.4.54.2\conf\httpd.conf 搜索 Require local 和Require all denied,改为Require all granted <…...
采用自动微分进行模型的训练
自动微分训练模型 简单代码实现: import torch import torch.nn as nn import torch.optim as optim# 定义一个简单的线性回归模型 class LinearRegression(nn.Module):def __init__(self):super(LinearRegression, self).__init__()self.linear nn.Linear(1, 1) …...
k8s怎么配置secret呢?
在Kubernetes中,配置Secret主要涉及到创建、查看和使用Secret的过程。以下是配置Secret的详细步骤和相关信息: ### 1. Secret的概念 * Secret是Kubernetes用来保存密码、token、密钥等敏感数据的资源对象。 * 这些敏感数据可以存放在Pod或镜像中&#x…...
算法篇 滑动窗口 leetcode 长度最小的子数组
长度最小的子数组 1. 题目描述2. 算法图分析2.1 暴力图解2.2 滑动窗口图解 3. 代码演示 1. 题目描述 2. 算法图分析 2.1 暴力图解 2.2 滑动窗口图解 3. 代码演示...
数据库作业d8
要求: 一备份 1 mysqldump -u root -p booksDB > booksDB_all_tables.sql 2 mysqldump -u root -p booksDB books > booksDB_books_table.sql 3 mysqldump -u root -p --databases booksDB test > booksDB_and_test_databases.sql 4 mysql -u roo…...
前后端数据交互设计到的跨域问题
前后端分离项目的跨域问题及解决办法 一、跨域简述 1、问题描述 这里前端vue项目的端口号为9000,后端springboot项目的端口号为8080 2、什么是跨域 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域 当前页面url被请求页面url是否…...
非洲猪瘟监测设备的作用是什么?
TH-H160非洲猪瘟监测设备的主要作用是迅速、准确地检测出非洲猪瘟病毒,从而帮助控制和预防疫情的扩散。这些设备利用先进的生物传感技术和PCR分子生物学方法,能够在极短的时间内提供精确的检测结果<sup>1</sup><sup>2</sup><…...
移动硬盘损坏无法读取?专业恢复策略全解析
在数字化信息爆炸的今天,移动硬盘作为我们存储和传输大量数据的重要工具,其安全性和稳定性直接关系到个人与企业的数据安全。然而,当移动硬盘突然遭遇损坏,无法正常读取时,我们该如何应对?本文将深入探讨移…...
神经网络以及简单的神经网络模型实现
神经网络基本概念: 神经元(Neuron): 神经网络的基本单元,接收输入,应用权重并通过激活函数生成输出。 层(Layer): 神经网络由多层神经元组成。常见的层包括输入层、隐藏层…...
java中压缩文件的解析方式(解析文件)
背景了解:java中存在IO流的方式,支持我们对文件进行读取(Input,从磁盘到内存)或写入(output,从内存到磁盘),那么我们在面对 “zip”格式或者 “rar” 格式的压缩文件&…...
巧用 VScode 网页版 IDE 搭建个人笔记知识库!
[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ] 巧用 VScode 网页版 IDE 搭建个人笔记知识库! 描述:最近自己在腾讯云轻量云服务器中部署了一个使用在线 VScode 搭建部署的个人Markdown在线笔记,考虑到在线 VScode 支持终…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
