spring 扩展功能心得(一)
spring作为现在最火的开发框架,熟练的使用spring和扩展功能,能大大提高开发效率
首先从spring的启动来看,spring启动的核心方法是 refresh 方法,该方法定义在AbstractApplicationContext.class
下面上代码 基于spring4.3.18,基于ClassPathXmlApplicationContext
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
//前置刷新工作,可以进行一些环境变量的校验
this.prepareRefresh();
//生成beanFactory 在生成过程中加载bean定义文件(spring.xml和spring注解等)
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//bean工厂准备工作
this.prepareBeanFactory(beanFactory);
try {
//加载postProcessBeanFactory
this.postProcessBeanFactory(beanFactory);
//调用postProcessBeanFactory,可以对bena工厂的属性以及对某些特定beanDefinition 修改属性
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册bean定义处理器,在bean进行初始化时,可以进行前置处理和后置处理
this.registerBeanPostProcessors(beanFactory);
//初始化message信息 国际化使用
this.initMessageSource();
//初始化时间转发器
this.initApplicationEventMulticaster();
//模板方法,需要自己自定义
this.onRefresh();
//注册监听器
this.registerListeners();
//实例化bean
this.finishBeanFactoryInitialization(beanFactory);
//完成bean加载,发送refresh完成事件
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
1 prepareRefresh 刷新前准备事件
可以重写initPropertySources方法,进行环境变量参数以及其他参数校验
demo如下
public class MyContext extends ClassPathXmlApplicationContext {
public MyContext(String...configLocations) {
super(configLocations);
}
public MyContext(String[] configLocations,boolean refresh) {
super(configLocations,refresh);
}
protected void initPropertySources(){
getEnvironment().setRequiredProperties("envir");
System.out.println( "envirment envir:"+getEnvironment().getSystemEnvironment().get("envir"));
}
public static void main(String[] args) {
ApplicationContext context = new MyContext("spring.xml");
}
}
在spring加载时,getEnvironment().setRequiredProperties() 方法,
在没有“envir” 环境变量时,抛出异常,在项目启动阶段将问题抛出,减少问题排查难度
2obtainFreshBeanFactory 生成beanFactory 加载bean定义文件
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//核心操作,由AbstractRefreshableApplicationContext 进行实现
this.refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
AbstractRefreshableApplicationContext.refreshBeanFactory()
protected final void refreshBeanFactory() throws BeansException {
//在获取到context后,可以进行手动refresh,在二次refresh时,需要销毁初始化创建的beanFactory
if (this.hasBeanFactory()) { //判断是否已经存在了beanFactory
this.destroyBeans(); //销毁所有bean对象,释放内存,主要是将存储bean和bean定义的map进行clear操作
this.closeBeanFactory();//关闭beanFactory,将序列化ID置为 null然后将beanFactory置为null
}
try {
//创建beanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
//设置序列化ID 默认为:启动类名+@+启动类对象的hashCode.toHexString
beanFactory.setSerializationId(this.getId());
//定义beanFactory 主要是设置是否允许Bean定义覆盖和循环引用(定义覆盖就是同一个名字有多个类,以后面的类为准)
this.customizeBeanFactory(beanFactory);
//加载bean定义文件,读取.xml文件
this.loadBeanDefinitions(beanFactory);
Object var2 = this.beanFactoryMonitor;
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
关于上面说到的允许Bean定义覆盖 可以参考一下demo 实现一个bean多定义,以后加载的bean为准
到这一步 已经完成了bean信息定义的加载,具体的怎么读取配置文件在此不做解析



