只需低头努力,剩下的交给时光,时间会公平地帮你处理这一切~
前言
Spring作为优秀的框架,被很多开发者使用,只要是做Java开发的,就一定会知道Spring框架。
Spring作为Java开发框架的标配,它所表现出来的优秀特性大大降低了企业开发过程中的复杂性
在前面我通过几篇源码的文章,分析了Spring是如何把Bean注册到容器中的、Spring是如何获取容器中的Bean的、Spring是如何实现AOP的
有兴趣可以去了解一下
那Spring这么优秀的框架,在扩展性方面自然也是极好的,我们知道Spring整个框架是个很庞大的集体,里面包括很多东西
Spring容器在启动过程中,有很多步骤,如初始化、加载Bean、国际化、事件广播等,在很多步骤中Spring都预留了接口给你来进行扩展,让你在使用Spring框架的过程中,可以做很多个性化的操作
从这个层面来讲,我们在使用Spring框架的时候,不光是把Bean对象交给Spring来管理,你也可以介入进去,可以干涉注册到Spring容器中的Bean
下面我们就一起来探索一下,Spring有哪些扩展点?
refresh()方法
了解过Spring源码的朋友肯定知道refresh()方法,如果连这个方法都不知道,那你百分之百没有看过Spring源码
refresh()方法可以说是Spring框架的核心,它串起了整个Spring容器的启动过程,你把这个方法里面的逻辑搞清楚了,那你对Spring的整体脉络就会有一个清晰的认识
下面我们就来看一下refresh()方法
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//容器启动前的准备工作
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//告诉子类刷新内部Bean工厂,解析Bean并注册到容器中(此时还没有初始化)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//准备BeanFactory,设置beanFactory类加载器,添加多个beanPostProcesser
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//允许子类上下文中对beanFactory做后期处理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//调用BeanFactoryPostProcessor各个实现类的方法
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册 BeanPostProcessor 的实现类
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化ApplicationContext的MessageSource
initMessageSource();
// Initialize event multicaster for this context.
// 初始化事件广播
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//初始化子类特殊bean
onRefresh();
// Check for listener beans and register them.
//注册事件监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 初始化所有singleton bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 广播事件,ApplicationContext初始化完成
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
方法主体总共12个方法
- prepareRefresh() 容器启动前的准备工作
- obtainFreshBeanFactory() 告诉子类刷新内部Bean工厂,解析Bean并注册到容器中(此时还没有初始化)
- prepareBeanFactory(beanFactory) 准备BeanFactory,设置beanFactory类加载器,添加多个beanPostProcesser
- postProcessBeanFactory(beanFactory) 允许子类上下文中对beanFactory做后期处理
- invokeBeanFactoryPostProcessors(beanFactory) 调用BeanFactoryPostProcessor各个实现类的方法
- registerBeanPostProcessors(beanFactory) 注册 BeanPostProcessor 的实现类
- initMessageSource() 初始化ApplicationContext的MessageSource
- initApplicationEventMulticaster() 初始化事件广播
- onRefresh() 初始化子类特殊bean
- registerListeners() 注册事件监听器
- finishBeanFactoryInitialization(beanFactory) 初始化所有singleton bean
- finishRefresh() 广播事件,ApplicationContext初始化完成
大部分方法都是为了完成注册和初始化,整个refresh()方法执行完成之后,基本上容器就启动完成了
prepareRefresh()方法
我们今天先来看一下prepareRefresh()方法,它是容器启动之前准备工作
protected void prepareRefresh() {
// 记录开始启动的时间
this.startupDate = System.currentTimeMillis();
//设置关闭状态为false
this.closed.set(false);
//设置激活状态为true
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
//初始化上下文环境中的占位符
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
//校验所有必须的属性
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
这里就出现了第一个扩展点,我们可以看到initPropertySources()是空的
protected void initPropertySources() {
// For subclasses: do nothing by default.
}
在Spring里面有很多这种空的方法,很多人在看源码的时候可能不太理解,为什么会调用一个空的方法,其实这是Spring为你预留的口子,就是让你自由发挥的地方
既然initPropertySources()是空的,那我们就来自己实现一下
public class MyAnnotationConfigApplicationContext extends AnnotationConfigApplicationContext {
public MyAnnotationConfigApplicationContext(String... basePackages){
super(basePackages);
}
@Override
protected void initPropertySources() {
super.initPropertySources();
getEnvironment().getSystemProperties().put("action","run");
getEnvironment().setRequiredProperties("KEY");
}
}
这里我继承了AnnotationConfigApplicationContext,实现了initPropertySources()方法,在里面添加了一个系统属性,并且标记“KEY”为必须的参数
下面我们来测试一下
public class AnnotionBeanTest {
public static void main(String[] args){
MyAnnotationConfigApplicationContext applicationContext = new MyAnnotationConfigApplicationContext("org.kxg.springDemo");
}
}
启动后发现报如下的错误:
Exception in thread "main" org.springframework.core.env.MissingRequiredPropertiesException: The following properties were declared as required but could not be resolved: [KEY]
at org.springframework.core.env.AbstractPropertyResolver.validateRequiredProperties(AbstractPropertyResolver.java:146)
at org.springframework.core.env.AbstractEnvironment.validateRequiredProperties(AbstractEnvironment.java:523)
at org.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:603)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:518)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:101)
at org.kxg.springDemo.refresh.prepare.MyAnnotationConfigApplicationContext.<init>(MyAnnotationConfigApplicationContext.java:8)
at org.kxg.springDemo.AnnotionBeanTest.main(AnnotionBeanTest.java:8)
从异常信息可以看到,这里是缺少必须参数的Exception,这里可以用来验证系统启动的一些必须参数
我们把“KEY”加到系统参数中,再来看一下
public class AnnotionBeanTest {
public static void main(String[] args){
System.setProperty("KEY","VAL");
MyAnnotationConfigApplicationContext applicationContext = new MyAnnotationConfigApplicationContext("org.kxg.springDemo");
}
}
启动容器,一切正常,至此我们就完成了第一个Spring的扩展点,当然例子中的扩展很简单,实际项目中大家可以根据情况来做自己的扩展,后面会陆续介绍其他的扩展点,请大家持续关注!
如果感觉对你有些帮忙,请收藏好,你的关注和点赞是对我最大的鼓励!
如果想跟我一起学习,坚信技术改变世界,请关注【Java天堂】公众号,我会定期分享自己的学习成果,第一时间推送给您