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

项目拓展-Spring实现策略类统一管理

使用Spring将所有的策略分类进行统一管理


基类-Container基本加载容器

BeanContainer接口-定义基本方法

package com.kira.scaffoldmvc.Strategy;import java.util.Collection;
import java.util.Map;public interface BeanContainer<K, V> {V getBean(K k);Collection<V> getBeans();Map<K, V> getBeansMap();
}

DefaultBeanContainer-抽象类-定义Bean的初始化处理逻辑

连接ApplicationContextAware接口

为了获取Spring的上下文

Bean 能够获取 Spring 的 ApplicationContext(应用上下文),从而访问 Spring 容器中的其他 Bean 或资源


连接InitializingBean-执行Bean的初始化方法

afterPropertiesSet()方法进行初始化,将该Bean的类型Class赋值给成员变量,将该Bean的类型进行保留

并且在初始化的过程中执行loadBean()方法

loadBean()方法其实就是创建我们的BeanMap,对bean对象进行统一管理

这个createBeanMap()方法是抽象方法,我们会在子实现类对createBeanMap()方法进行重写

    public void loadBeans() {this.beanMap = this.createBeanMap();}

源代码
package com.kira.scaffoldmvc.Strategy;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;/*** 默认的Bean容器实现,用于管理和存储类型为V的策略Bean,通过键K进行索引* 实现了ApplicationContextAware接口以获取Spring应用上下文* 实现了InitializingBean接口以便在Bean属性设置完成后执行初始化逻辑* 实现了BeanContainer接口定义的核心方法*/
//ApplicationContextAware 接口,让 Bean 能够获取 Spring 的 ApplicationContext(应用上下文),从而访问 Spring 容器中的其他 Bean 或资源
//InitializingBean 接口,当一个 Bean 实现了 InitializingBean 接口,Spring 在完成该 Bean 的所有属性注入后(初始化),会自动调用 afterPropertiesSet() 方法
//类似于 XML 配置中的 init-method 或 @PostConstruct 注解
public abstract class DefaultBeanContainer<K, V> implements ApplicationContextAware, InitializingBean, BeanContainer<K, V> {// Spring应用上下文,用于获取容器中的Beanprotected ApplicationContext applicationContext;// 泛型参数V的实际Class类型,通过反射获取protected Class<?> type;// 存储键值对的内部映射,键为K,值为V类型的Beanprivate Map<K, V> beanMap;/*** 加载所有策略Bean到容器中* 调用抽象方法createBeanMap()获取映射关系并赋值给内部beanMap*/public void loadBeans() {this.beanMap = this.createBeanMap();}/*** 由子类实现的抽象方法,用于创建具体的Bean映射关系* 通常通过applicationContext.getBeansOfType()方法获取特定类型的所有Bean* @return 包含键值映射关系的Map*/protected abstract Map<K, V> createBeanMap();/*** Bean初始化完成后自动调用的方法* 1. 通过反射获取泛型参数V的实际类型* 2. 调用loadBeans()方法加载所有策略Bean*/@Overridepublic void afterPropertiesSet() {// 获取当前类的泛型父类类型Type genericSuperclass = this.getClass().getGenericSuperclass();// 转换为参数化类型以便获取泛型参数ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;// 获取实际的泛型参数数组(对于DefaultBeanContainer<K, V>有两个参数)Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();// 获取第二个泛型参数V的类型Type valueType = actualTypeArguments[1];// 处理泛型参数是带泛型的类型的情况(例如List<String>)if (valueType instanceof ParameterizedType) {this.type = (Class<?>) ((ParameterizedType) valueType).getRawType();} else {// 普通类型直接转换为Classthis.type = (Class<?>) actualTypeArguments[1];}// 加载所有策略Beanthis.loadBeans();}/*** 实现ApplicationContextAware接口的方法,由Spring自动调用注入应用上下文* @param applicationContext Spring应用上下文*/@Overridepublic void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}/*** 根据键获取对应的策略Bean* @param key 查找Bean的键* @return 对应的策略Bean,如果不存在则返回null*/@Overridepublic V getBean(K key) {return beanMap.get(key);}/*** 获取容器中所有策略Bean的集合* @return 包含所有策略Bean的集合*/@Overridepublic Collection<V> getBeans() {return new ArrayList<>(beanMap.values());}/*** 获取容器中所有策略Bean的不可变映射* @return 包含所有键值对的Map副本*/@Overridepublic Map<K, V> getBeansMap() {return new HashMap<>(beanMap);}
}

IBeanType

package com.kira.scaffoldmvc.Strategy;public interface IBeanType<K> {K beanType();}

在子类中返回对应变量,这个变量是作为MultipleBeanContainer和DefaultBeanContainer的Key来管理对应的策略类的


多实例Bean容器-MultipleBeanContainer

将同一类 用List<>进行统一管理

例如Map<策略实现类父类.Class,List<策略实现类>>

也就是用一个Key,管理多个策略实现类

并且已经写好了按照Order优先级顺序加载

package com.kira.scaffoldmvc.Strategy;import org.springframework.core.annotation.AnnotationAwareOrderComparator;import java.util.*;
import java.util.stream.Collectors;/*** 多实例Bean容器,用于管理同一类型键对应多个策略Bean的场景* 继承自DefaultBeanContainer,泛型参数K为键类型,V为策略Bean类型且需实现IBeanType接口* 容器中存储的Value类型为List<V>,支持同一键对应多个策略Bean*/
public abstract class MultipleBeanContainer<K, V extends IBeanType<K>> extends DefaultBeanContainer<K, List<V>> {/*** 创建Bean映射关系的核心方法(由父类DefaultBeanContainer调用)* 实现逻辑:* 1. 从Spring容器中获取所有指定类型的策略Bean* 2. 按beanType()方法的返回值对Bean进行分组* 3. 对每组Bean按@Order注解排序(或实现Ordered接口)* @return 键为K、值为List<V>的映射表*/@Overrideprotected Map<K, List<V>> createBeanMap() {// 获取Spring容器中所有类型为this.type的Bean实例(值类型为V)Collection<V> beanList = (Collection<V>) this.applicationContext.getBeansOfType(this.type).values();// 使用Stream API对Bean进行分组处理Map<K, List<V>> beanMap = beanList.stream()// 过滤掉beanType()返回null的无效Bean.filter(bean -> bean.beanType() != null)// 分组归约操作:// - 初始值:容量为8的HashMap// - 累加器:将每个Bean按beanType()分组到List中// - 组合器:并行流时合并两个Map(此处简单返回a).reduce(new HashMap<>(8), (beansMap, bean) -> {// 获取当前Bean对应的键(通过IBeanType接口的beanType()方法)K beanType = bean.beanType();// 从Map中获取该键对应的Bean列表,不存在则创建新ArrayListList<V> existedBeanList = beansMap.getOrDefault(beanType, new ArrayList<>());// 将当前Bean添加到列表中existedBeanList.add(bean);// 更新Map中的列表beansMap.put(beanType, existedBeanList);return beansMap;}, (a, b) -> a); // 并行流时的合并逻辑(此处无实际作用)// 对每个键对应的Bean列表按@Order注解或Ordered接口排序for (List<V> beans : beanMap.values()) {AnnotationAwareOrderComparator.sort(beans);}return beanMap;}
}

单实例Bean容器-SingleBeanContainer

单个Key对应单个Value

也就是一个策略对应一个策略,之前那个是用List<>将同一策略的类用List收集起来

这个就是通过一个策略父类能找到一个实现类

并且已经写好了按照Order优先级顺序加载

package com.kira.scaffoldmvc.Strategy;import org.springframework.beans.factory.InitializingBean;import java.util.Collection;
import java.util.HashMap;
import java.util.Map;/*** 单实例 Bean 容器,用于管理每个键对应单个策略 Bean 的场景* 继承自 DefaultBeanContainer,泛型参数 K 为键类型,V 为策略 Bean 类型且需实现 IBeanType 接口* 容器中存储的每个键对应唯一的策略 Bean,若存在重复键会被覆盖*/
public abstract class SingleBeanContainer<K, V extends IBeanType<K>> extends DefaultBeanContainer<K, V> implements InitializingBean {/*** 创建 Bean 映射关系的核心方法(由父类 DefaultBeanContainer 调用)* 实现逻辑:* 1. 从 Spring 容器中获取所有指定类型的策略 Bean* 2. 按 beanType() 方法的返回值作为键,将 Bean 存入 Map* 3. 若存在相同键的 Bean,后处理的 Bean 会覆盖先处理的 Bean* @return 键为 K、值为 V 的映射表*/@Overridepublic Map<K, V> createBeanMap() {// 获取 Spring 容器中所有类型为 this.type 的 Bean 实例(值类型为 V)Collection<V> beans = (Collection<V>) this.applicationContext.getBeansOfType(this.type).values();// 使用 Stream API 将 Bean 按 beanType() 分组到 Map 中return beans.stream()// 过滤掉 beanType() 返回 null 的无效 Bean.filter(bean -> bean.beanType() != null)// 归约操作:将每个 Bean 按 beanType() 作为键存入 Map.reduce(new HashMap<>(8), (beansMap, bean) -> {// 若存在相同键的 Bean,后处理的 Bean 会覆盖先处理的 BeanbeansMap.put(bean.beanType(), bean);return beansMap;}, (a, b) -> a); // 并行流时的合并逻辑(此处无实际作用)}
}

使用MultipleBeanContainer实现多个策略类组合优雅关闭Java线程 

关闭策略方法接口-CloseStrategy

这是一个关闭策略接口,连接IBeanType

因为这是在java程序关闭的时候执行的自定方法

所以只有一个方法,也就是close()

package com.kira.scaffoldmvc.ShutDownHook;import com.kira.scaffoldmvc.Strategy.IBeanType;public interface CloseStrategy extends IBeanType<String> {void close();}

IBeanType<>的意义

package com.kira.scaffoldmvc.Strategy;public interface IBeanType<K> {K beanType();
}

在子类中返回对应变量,这个变量是作为MultipleBeanContainer和DefaultBeanContainer的Key来管理对应的策略类的


CloseStrategyContainer-管理所有的Close关闭策略

这是一个容器,里面通过键值对的方式装填了所有的CloseStrategy关闭策略实现类

package com.kira.scaffoldmvc.ShutDownHook;import com.kira.scaffoldmvc.Strategy.MultipleBeanContainer;
import org.springframework.stereotype.Component;/*** 关闭策略容器,用于管理所有实现了 CloseStrategy 接口的策略*/
@Component
public class CloseStrategyContainer extends MultipleBeanContainer<String, CloseStrategy> {}

ThreadPoolCloseStrategy-线程池关闭策略实现类

"close"字符串作为Key来管理所有的关闭策略

    //在 MultipleBeanContainer 和 DefaultBeanContainer 中,该方法的返回值会被用作存储策略 Bean 的 Map 集合的键(Key)@Overridepublic String beanType() {//close作为Key,存储所有的关闭策略return "close";}
package com.kira.scaffoldmvc.ShutDownHook;import com.kira.scaffoldmvc.Strategy.IBeanType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;@Slf4j
@Component
public class ThreadPoolCloseStrategy implements CloseStrategy {@Autowired(required = false)private Map<String, ThreadPoolExecutor> threadPoolExecutorMap;@Overridepublic void close() {log.info("Spring容器销毁,开始关闭线程池...");shutdownAllExecutorServices();}//在 MultipleBeanContainer 和 DefaultBeanContainer 中,该方法的返回值会被用作存储策略 Bean 的 Map 集合的键(Key)@Overridepublic String beanType() {//close作为Key,存储所有的关闭策略return "close";}/*** 优雅关闭所有线程池,确保所有任务执行完成*/public void shutdownAllExecutorServices() {if (threadPoolExecutorMap != null && !threadPoolExecutorMap.isEmpty()) {threadPoolExecutorMap.forEach((name, executor) -> {log.info("正在关闭线程池: " + name);shutdownExecutorServiceCompletely(name, executor);});}}/*** 优雅关闭线程池,确保所有任务执行完成** @param poolName 线程池名称* @param executor 线程池实例*/private void shutdownExecutorServiceCompletely(String poolName, ExecutorService executor) {// 停止接收新任务executor.shutdown();// 等待所有任务执行完成,不设置超时try {// 定期检查线程池状态while (!executor.awaitTermination(5, TimeUnit.SECONDS)) {// 输出剩余任务信息,方便监控if (executor instanceof ThreadPoolExecutor) {ThreadPoolExecutor threadPool = (ThreadPoolExecutor) executor;log.info("线程池[{}]关闭中: 活跃线程数={}, 队列任务数={}, 已完成任务数={}, 总任务数={}",poolName,threadPool.getActiveCount(),threadPool.getQueue().size(),threadPool.getCompletedTaskCount(),threadPool.getTaskCount());}}log.info("线程池[{}]已完全关闭,所有任务执行完成", poolName);} catch (InterruptedException ie) {// 被中断时,继续尝试关闭log.info("线程池[{}]关闭过程被中断,继续尝试关闭...", poolName);Thread.currentThread().interrupt();//将中断标志为设为true,方面后面逻辑拓展//当我们抛出错误后,为了保证这个线程池的任务执行完我们选择继续等待,而不是shutdownNow()// 注意:这里不调用shutdownNow(),确保任务完成}}}

@PreDestory-实现Java程序的优雅关闭

获取关闭策略类,通过Bean拿出所有的关闭策略然后调用close()方法进行执行

package com.kira.scaffoldmvc;import com.kira.scaffoldmvc.ShutDownHook.CloseStrategy;
import com.kira.scaffoldmvc.ShutDownHook.CloseStrategyContainer;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;@SpringBootApplication
@Slf4j
public class ScaffoldMvcApplication {@Autowired(required = false)private Map<String, ThreadPoolExecutor> threadPoolExecutorMap;public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(ScaffoldMvcApplication.class, args);// 获取应用实例ScaffoldMvcApplication application = context.getBean(ScaffoldMvcApplication.class);//        // 注册 JVM 关闭钩子
//        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
//            log.info("JVM 关闭钩子触发,开始优雅关闭线程池...");
//            application.shutdownAllExecutorServices();
//            log.info("所有线程池已优雅关闭,所有任务执行完成");
//        }));}//获取所有的关闭策略类@AutowiredCloseStrategyContainer closeStrategyContainer;// 同时保留@PreDestroy作为备选关闭方式@PreDestroypublic void onDestroy() {// 获取所有"close"类型的关闭策略,然后执行策略类的close()关闭方法List<CloseStrategy> strategies = closeStrategyContainer.getBean("close");if (strategies != null) {for (CloseStrategy strategy : strategies) {strategy.close(); // 执行关闭操作}}}}
http://www.xdnf.cn/news/1062883.html

相关文章:

  • 【Elasticsearch】脚本(Script)
  • Duende Identity Server学习之一:认证服务器及一个Oidc/OAuth认证、用于Machine 2 Machine的客户端
  • 零基础学习Redis(12) -- Java连接redis服务器
  • 跟着AI学习C# Day29
  • 【LeetCode#第198题】打家劫舍(一维dp)
  • 【论文笔记】【强化微调】T-GRPO:对视频数据进行强化微调
  • MySQL误删数据急救指南:基于Binlog日志的实战恢复详解
  • ESP32 ESP-IDF Ubuntu平台工具链的标准设置
  • 山姆·奥特曼:从YC到OpenAI,硅谷创新之星的崛起
  • 01-驱动开发开篇
  • 冰箱压缩机电机驱动板【电源部分】
  • ARCGIS国土超级工具集1.6更新说明
  • 跟着AI学习C# Day27
  • 华为云Flexus+DeepSeek征文|基于华为云一键部署Dify LLM 应用构建 PPT 生成助手的开发与实践
  • 力扣-72.编辑距离
  • 构建高效智能体系统:从简单到复杂,找到最适合你的解决方案
  • 3D可视化数字孪生智能服务平台-物联网智控节能控、管、维一体化技术架构
  • Gartner《AI-Driven Methods for Cost-Efficiency》学习心得
  • 类图:软件世界的“建筑蓝图”
  • 【Python】List
  • 结构体的嵌套问题
  • FPGA基础 -- Verilog 的属性(Attributes)
  • python+uniapp基于微信小程序的高校二手商品交易系统
  • Maven并行构建
  • 饼图:数据可视化的“切蛋糕”艺术
  • 大数据治理域——计算管理
  • windows清理系统备份文件夹WinSxS文件夹清理
  • 大数据Hadoop集群搭建
  • mysql server层做了什么
  • nginx的下载与安装 mac