随手记录9:静态类中使用spring托管类,自定义加载类
简介
项目中有很多通用的处理类需要加载到内存中;而且实现静态方法注入使用这些对象内容;这些对象一般有统一的父类(接口/抽象类);需要在项目启动就将我们指定的对象加载到内存中
demo下载
项目结构
里面需要介绍的类
1. CapitalFileHandleContext对外暴露静态方法 里面有个静态的map通过capitalNo获取真正的执行的类
2. BaseCapitalFileHandle这个是底层的基类接口 提供对应的方法
3. AbstractBaseCapitalFileHandle 抽象类 提供抽象方法
4. XinWangCapitalFileHandle/NongShangCapitalFileHandle 具体的实现类内容;
5. ClassFinder 就是一个工具类扫描指定包路径下面的所有的class对象;在静态代码块中加载到内存中去
加载方式
1.通过静态代码块扫描需要加载的类的包路径
静态代码块中通过我们指定的包路径进行扫描获取到所有的class类文件然后加到到本地
通过Class.newInstance 创建对象 然后根据capitalNo 获取不到类型的设置到Map容器中
这种方式不需要将初始化对象交给spring管理简单 清爽;
public class CapitalFileHandleContext{
private ApplicationContext applicationContext;
private static Logger logger = LoggerFactory.getLogger(CapitalFileHandleContext.class);
private static final String DEFAULT_PACKAGE = "com.khy.handle.impl";//指定扫描某个包路径下面的全部class类
//加载方式1-->通过静态代码块;指定加载代码中某个包路径下面的类,然后完成对应方法的调用;
public static Map<String,BaseCapitalFileHandle>map = new ConcurrentHashMap<>();
static{
logger.info("init 初始化 BaseCapitalFileHandle 的相关接口内容...");
if(map.isEmpty()){
//获取当前包下面所有符合条件的类
Set<Class<?>> classes = ClassFinder.getClasses(DEFAULT_PACKAGE);
Iterator<Class<?>> iter = classes.iterator();
while(iter.hasNext()){
Class<?> clz = iter.next();
if(BaseCapitalFileHandle.class.isAssignableFrom(clz)){
BaseCapitalFileHandle processor = null;
try {
processor = (BaseCapitalFileHandle)clz.newInstance();
} catch (InstantiationException e) {
logger.error("初始化 BaseCapitalFileHandle 处理者工厂反射创建实例失败...退出",e);
System.exit(-1);
} catch (IllegalAccessException e) {
logger.error("初始化 BaseCapitalFileHandle 处理者工厂反射创建实例失败...退出",e);
System.exit(-1);
}
map.put(processor.getCapitalNo(), processor);
}
}
logger.info("BaseCapitalFileHandle 初始化完毕...共加载{}种处理者",map.size());
}
}
}
2. 通过applicationContext 对象获取
需要通过CapitalFileHandleContext 添加 @Component 被spring 扫描加载 然后通过实现 ApplicationContextAware类,实现setApplicationContext 方法 获取ApplicationContext
通过@PostConstruct 在spring初始化完成之后 可以通过applicationContext获取spring中所有符合条件的实现类然后处理 这种需要将对象交给spring管理;
@Component
public class CapitalFileHandleContext implements ApplicationContextAware{
private ApplicationContext applicationContext;
//加载方式2-->通过@PostConstruct 注解然后在spring 加载完类之后调用该方法从applicationContext中获取需要加载的类内容然后完成类的加载
public static Map<String,BaseCapitalFileHandle>map2 = new ConcurrentHashMap<>();
@PostConstruct
public void init2(){
logger.info("init2 初始化 BaseCapitalFileHandle的相关接口内容...");
if(map2.isEmpty()){
try {
Map<String, BaseCapitalFileHandle> baseResultNotifyHandlers = applicationContext.getBeansOfType(BaseCapitalFileHandle.class);
if(MapUtils.isNotEmpty(baseResultNotifyHandlers)){
baseResultNotifyHandlers.entrySet().stream().forEach(e->{
map2.put(e.getValue().getCapitalNo(), e.getValue());
});
}
} catch (Exception e) {
logger.error("初始化资方文件处理类实例失败...退出"+e.getMessage(),e);
System.exit(-1);
}
logger.info("BaseCapitalFileHandle初始化完毕...共加载{}种处理者",map.size());
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
3.通过实现InitializingBean 接口
需要加载的类实现 InitializingBean 接口 afterPropertiesSet方法 ;然后将对象设置到CapitalFileHandleContext 中的maps容器中去;也需要将对象交给spring管理 但是比方式二要简单 而且CapitalFileHandleContext 不要交给spring管理.
public class CapitalFileHandleContext{
//加载方式3-->通过抽象类实现InitializingBean 在spring初始化完类调用afterPropertiesSet方法里面完成具体的操作内容;
public static Map<String,BaseCapitalFileHandle>map3 = new ConcurrentHashMap<>();
}
public abstract class AbstractBaseCapitalFileHandle implements BaseCapitalFileHandle,InitializingBean {
public abstract <T>void capitalHandleFile(T t);
@Override
public <T> void handleFile(T t) {
capitalHandleFile(t);
}
@Override
public void afterPropertiesSet() throws Exception {
CapitalFileHandleContext.map3.put(getCapitalNo(), this);
}
}
controller 中静态调用
@RestController
@RequestMapping("loadBean")
public class LoadBeanController {
@RequestMapping("get")
public String test(String type){
JSONObject json = new JSONObject();
CapitalFileHandleContext.handleFile(type, json);
return "LoadBeanController 方法执行完毕";
}
}
完整版的 CapitalFileHandleContext
package com.khy.handle;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.khy.utils.ClassFinder;
@Component
public class CapitalFileHandleContext implements ApplicationContextAware{
private ApplicationContext applicationContext;
private static Logger logger = LoggerFactory.getLogger(CapitalFileHandleContext.class);
private static final String DEFAULT_PACKAGE = "com.khy.handle.impl";//指定扫描某个包路径下面的全部class类
//加载方式1-->通过静态代码块;指定加载代码中某个包路径下面的类,然后完成对应方法的调用;
public static Map<String,BaseCapitalFileHandle>map = new ConcurrentHashMap<>();
//加载方式3-->通过抽象类实现InitializingBean 在spring初始化完类调用afterPropertiesSet方法里面完成具体的操作内容;
public static Map<String,BaseCapitalFileHandle>map3 = new ConcurrentHashMap<>();
static{
logger.info("init 初始化 BaseCapitalFileHandle的相关接口内容...");
if(map.isEmpty()){
Set<Class<?>> classes = ClassFinder.getClasses(DEFAULT_PACKAGE);
Iterator<Class<?>> iter = classes.iterator();
while(iter.hasNext()){
Class<?> clz = iter.next();
if(BaseCapitalFileHandle.class.isAssignableFrom(clz)){
BaseCapitalFileHandle processor = null;
try {
processor = (BaseCapitalFileHandle)clz.newInstance();
} catch (InstantiationException e) {
logger.error("初始化 BaseInterface 处理者工厂反射创建实例失败...退出",e);
System.exit(-1);
} catch (IllegalAccessException e) {
logger.error("初始化BaseInterface处理者工厂反射创建实例失败...退出",e);
System.exit(-1);
}
map.put(processor.getCapitalNo(), processor);
}
}
logger.info("BaseInterface处理工厂初始化完毕...共加载{}种处理者",map.size());
}
}
//加载方式2-->通过@PostConstruct 注解然后在spring 加载完类之后调用该方法从applicationContext中获取需要加载的类内容然后完成类的加载
public static Map<String,BaseCapitalFileHandle>map2 = new ConcurrentHashMap<>();
@PostConstruct
public void init2(){
logger.info("init2 初始化 BaseCapitalFileHandle的相关接口内容...");
if(map2.isEmpty()){
try {
Map<String, BaseCapitalFileHandle> baseResultNotifyHandlers = applicationContext.getBeansOfType(BaseCapitalFileHandle.class);
if(MapUtils.isNotEmpty(baseResultNotifyHandlers)){
baseResultNotifyHandlers.entrySet().stream().forEach(e->{
map2.put(e.getValue().getCapitalNo(), e.getValue());
});
}
} catch (Exception e) {
logger.error("初始化资方文件处理类实例失败...退出"+e.getMessage(),e);
System.exit(-1);
}
logger.info("BaseCapitalFileHandle初始化完毕...共加载{}种处理者",map.size());
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static <T>void handleFile(String capitalNo, T t) {
Assert.hasText(capitalNo, "获取文件处理类capitalNo不为空capitalNo="+capitalNo);
BaseCapitalFileHandle capitalFileHandle = map.get(capitalNo);
Assert.notNull(capitalFileHandle, "未获取到文件处理类capitalNo="+capitalNo);
capitalFileHandle.handleFile(t);
capitalFileHandle = map2.get(capitalNo);
Assert.notNull(capitalFileHandle, "未获取到文件处理类capitalNo="+capitalNo);
capitalFileHandle.handleFile(t);
capitalFileHandle = map3.get(capitalNo);
Assert.notNull(capitalFileHandle, "未获取到文件处理类capitalNo="+capitalNo);
capitalFileHandle.handleFile(t);
}
}