使用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应用上下文,用于获取容器中的Bean
protected ApplicationContext applicationContext;
// 泛型参数V的实际Class类型,通过反射获取
protected Class<?> type;
// 存储键值对的内部映射,键为K,值为V类型的Bean
private 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
*/
@Override
public 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 {
// 普通类型直接转换为Class
this.type = (Class<?>) actualTypeArguments[1];
}
// 加载所有策略Bean
this.loadBeans();
}
/**
* 实现ApplicationContextAware接口的方法,由Spring自动调用注入应用上下文
* @param applicationContext Spring应用上下文
*/
@Override
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 根据键获取对应的策略Bean
* @param key 查找Bean的键
* @return 对应的策略Bean,如果不存在则返回null
*/
@Override
public V getBean(K key) {
return beanMap.get(key);
}
/**
* 获取容器中所有策略Bean的集合
* @return 包含所有策略Bean的集合
*/
@Override
public Collection<V> getBeans() {
return new ArrayList<>(beanMap.values());
}
/**
* 获取容器中所有策略Bean的不可变映射
* @return 包含所有键值对的Map副本
*/
@Override
public 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>的映射表
*/
@Override
protected 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列表,不存在则创建新ArrayList
List<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 的映射表
*/
@Override
public 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 会覆盖先处理的 Bean
beansMap.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)
@Override
public 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;
@Override
public void close() {
log.info("Spring容器销毁,开始关闭线程池...");
shutdownAllExecutorServices();
}
//在 MultipleBeanContainer 和 DefaultBeanContainer 中,该方法的返回值会被用作存储策略 Bean 的 Map 集合的键(Key)
@Override
public 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("所有线程池已优雅关闭,所有任务执行完成");
// }));
}
//获取所有的关闭策略类
@Autowired
CloseStrategyContainer closeStrategyContainer;
// 同时保留@PreDestroy作为备选关闭方式
@PreDestroy
public void onDestroy() {
// 获取所有"close"类型的关闭策略,然后执行策略类的close()关闭方法
List<CloseStrategy> strategies = closeStrategyContainer.getBean("close");
if (strategies != null) {
for (CloseStrategy strategy : strategies) {
strategy.close(); // 执行关闭操作
}
}
}
}