Spring扩展点探索之prepareRefresh

只需低头努力,剩下的交给时光,时间会公平地帮你处理这一切~

前言

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的扩展点,当然例子中的扩展很简单,实际项目中大家可以根据情况来做自己的扩展,后面会陆续介绍其他的扩展点,请大家持续关注!

本文源自头条号:果子爸聊技术

本站是提供个人知识管理的网络存储空间,所有内容均来源于网络,不代表本站观点。如发现有害或侵权内容与我们联系。