上篇文章是关于Spring容器初始化以及根据容器获取bean的方法扩展等,然后涉及到系统初始化工厂,说在下一篇文章说一下这个问题。
有兴趣可以了解一下上篇文章:Spring容器初始化,根据容器获取Bean,初始化工厂应该在什么时候运行
一个好的顶层设计,一个好的设计模式,一个合适的设计模式,会让这块的业务更加明确,功能更加完善,代码更好梳理,让开发更加简单,让代码更加优美~
那么,怎么写好一个具有良好扩展性的初始化工厂呢?
首先我们需要抽象出来几个接口:
1、接口:获取我的名字
public interface IName {
/**
* 获取名称
* @return 名字
*/
public String getName();
}
这个接口就一个方法,从这个方法能获取实现类定义的名称。
2、接口:定义优先级
public interface IPriority {
public int PRIORITY_DEAULT = 5;
/**
* 返回优先级。
* 优先级建议为0-10. 5为默认优先级.
* 0表示优先级最高 10表示最低
* @return
*/
public int priority();
}
既然是一个初始化工厂,肯定不会只有一个业务需要初始化,如果有多个业务交错,那就有可能涉及到执行的先后顺序问题,那么可以实现这个接口来定义优先级,让我们的各个业务能按顺序初始化,
3、接口:初始化接口
/**
* 定义初始化接口。定义初始化和销毁。
* <i>服务器规范接口</i>
* @version 1.0
*/
public interface IInit extends IName{
/**
* 定义初始化接口
* @param conf
*/
public void init(ServletConfig conf);
/**
* 定义销毁接口
* @param conf
*/
public void destroy();
}
这个接口定义了初始化系统和销毁系统
那么这三个接口就基本上满足了初始化工厂的功能,下面说一下实现。
接口的具体实现:
首先是一个抽象的实现类,对上面定义的三个接口进行部分实现及扩展:
public abstract class AbstractInit implements IInit, IPriority, IName {
private Logger logger = LoggerFactory.getLogger(AbstractInit.class);
@Override
public void init(ServletConfig conf) {
try {
doInit(conf);
} catch (Exception e) {
if(exitOnException()){
logger.error("【"+getName()+"】数据初始化异常,应用程序停止...",e);
System.exit(0);
}else{
logger.warn("【"+getName()+"】数据初始化异常,应用程序继续运行...",e);
}
}
}
/**
* 初始化方法
* @param conf
* @throws Exception
*/
public abstract void doInit(ServletConfig conf) throws Exception;
@Override
public void destroy() {
try {
doDestroy();
} catch (Exception e) {
logger.error("【{}】数据销毁异常",getName(),e);
}
}
/**
* 销毁方法
* @param conf
* @throws Exception
*/
public abstract void doDestroy();
/**
* 默认异常将停止启动。
*/
public boolean exitOnException() {
return true;
}
@Override
public int priority() {
return PRIORITY_DEAULT;
}
}
这个抽象类实现了三个接口,但是只实现了IInit中的初始化方法和销毁方法,并且新定义了2个抽象方法,执行初始化doInit和执行销毁doDestroy方法,并且设置优先级为默认5,子类如果不重写,那么久默认该初始化业务为5.
这里有个exitOnException()方法,这个方法是什么意思呢,因为在初始化的业务中,可能存在某些业务初始化失败不影响系统的运行,不影响系统启动后的其他业务,但是也有些业务初始化失败会导致系统部分功能不可用,或者更严重的问题,这个时候就需要系统中断运行了,去检测问题了。那么具体哪个实现类出现异常需要停止允许系统,就由子类去重写这个方法!
下面这个实现类就是系统初始化的总工厂,具体的业务实现就由这个工厂来实现:
/**
* 系统配置总工厂
* @version 1.0
*/
@Service
public class InitConfigFactory implements IInit{
private static final Logger logger = LoggerFactory.getLogger(InitConfigFactory.class);
private List<AbstractInit> factorys = new ArrayList<AbstractInit>();
@Override
public String getName() {
return "系统初始化";
}
/**
* 系统初始化
*/
public void init(ServletConfig conf){
logger.info("----------------------系统初始化----------------------");
logger.info("#########扫描初始化工厂#########");
//获取AbstractInit的所有子类,然后循环获取子类实例,并且加入到初始化队列factorys中
List<Class<AbstractInit>> list = ClassUtils.getChilderClass(AbstractInit.class, false);
for (Class<AbstractInit> c : list) {
try {
//该方法上篇博文有,从Spring容器获取Bean实例,文章第一段有链接,可查看
AbstractInit factory = SpringContext.getBean(c);
factorys.add(factory);
} catch (Exception e) {
logger.error("# 实例化工厂☆☆"+c.getSimpleName()+"☆☆异常,程序运行停止"+c,e);
System.exit(0);
}
}
//这里是进行优先级排序,初始化队列中的初始化业务对象根据各自的优先级在队列中进行排序,PriorityComparator排序类下面会给出代码
Collections.sort(factorys, new PriorityComparator());
logger.info("#########扫描完成,开始初始化#########");
logger.info("");
//循环执行各个子类的init方法,其实执行的就是各个子类实现的doInit方法
for (AbstractInit f : factorys) {
logger.info("#########开始初始化【"+f.getName()+"】#########");
f.init(conf);
logger.info("#########完成初始化【"+f.getName()+"】#########");
}
logger.info("----------------------系统初始化----------------------");
}
/**
* 系统销毁
*/
public void destroy(){
logger.info("----------------------系统资源回收----------------------");
for (AbstractInit f : factorys) {
logger.info("#########开始销毁系统【"+f.getName()+"】#########");
f.destroy();
logger.info("#########完成销毁系统【"+f.getName()+"】#########");
}
logger.info("----------------------系统资源回收----------------------");
}
}
看一下根据优先级对队列排序的类:
/**
* 实现{@link IPriority}按照优先级排序功能
* @version 1.0
*/
public class PriorityComparator implements Comparator<IPriority> {
@Override
public int compare(IPriority o1, IPriority o2) {
return o1.priority() - o2.priority();
}
}
这样调用各个子类实例的priority()方法对List进行排序就实现了各个子类的优先级排序。
这样就实现了各业务初始化的优先级概念了。
下面写一个具体的业务实现类来看一下:
/**
* 某业务实现类
* @version 1.0
*/
@Service
public class TestInit extends AbstractInit {
private ReentrantLock lock=new ReentrantLock();
@Override
public void doDestroy() {
//空实现具体的销毁时执行方法
}
@Override
public String getName() {
return "测试业务实现类";
}
/**
* 重写doInit方法
*/
@Override
public void doInit(ServletConfig conf) throws Exception {
try {
lock.lock();
//具体的测试业务初始化实现,在这里进行
} catch (Exception e) {
throw e;
}finally{
lock.unlock();
}
}
@Override
public int priority() {
//重新定义优先级为6
return 6;
}
}
到具体的业务实现类的时候,只需要实现具体的业务就行了,其他的处理父类已经处理过了,这样扩展性是不是就强了很多呢?
其实这种写法不止于初始化,这里主要想表现的是写法,这种写法可能在其他业务稍作改造也是可以用的。
如果有什么建议或者意见,欢迎指正,所学尚浅,见谅~