还记得我在这篇博文:【小家Spring】Spring容器(含父子容器)的启动过程源码级别分析(含web.xml启动以及全注解驱动,和ContextLoader源码分析)
里留了几个非常重要,但是没有解释的方法。其中有一个非常重要的方法ApplicationContext#refresh()
方法就是提到两次但都暂时忽略了(因为有父子容器,所以会刷新两次容器~)
refresh()
方法是Spring容器启动的核心中的核心,逻辑也是异常的复杂,因为准备分两篇文章来叙述他的过程,以及源码的分析
Spring源码基于的Spring版本为:5.0.6.RELEASE(下同) Spring源码基于的Spring版本为:5.0.6.RELEASE(下同) Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)
Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean,这其中包含了一系列关键点。
我把这张图放在最开始的位置,初看可能觉得一脸懵逼,但是相信在接下来的阅读过程中,会一步一步的柳暗花明的~
简单分类如下:
BeanFactoryPostProcessor
):这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer
等等非常有用的工厂后处理器 接口的方法。工厂后处理器也是容器级的。InstantiationAwareBeanPostProcessor 和 BeanPostProcessor
这两个接口实现,一般称它们的实现类为“后处理器”BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean
这些接口的方法<bean>
的init-method
和destroy-method
指定的方法因为我们项目的案例是全注解驱动的,因此我们的容器实例为:AnnotationConfigWebApplicationContext
(若你是xml配置驱动,则为XmlWebApplicationContext
)
为了更方便了解容器类的继承关系,贴出如下类继承图:
refresh()
方法所有的ApplicationContext
子类都没重写,只有AbstractApplicationContext
里有实现过(接口定义在ConfigurableApplicationContext
),因此我们看起来也容易了,直接上源码~
此部分源码,把容器的刷新步骤体现得非常的清晰,十足的面向对象编程。因此我会保留Spring 英文备注的同事,把一些备注写在源码上~~~ 详细的下面都会具体再解释
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//容器刷新前的准备,设置上下文状态,获取属性,验证必要的属性等
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 获取新的beanFactory,销毁原有beanFactory、为每个bean生成BeanDefinition等 注意,此处是获取新的,销毁旧的,这就是刷新的意义
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//配置标准的beanFactory,设置ClassLoader,设置SpEL表达式解析器等
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.
//实例化并调用所有注册的beanFactory后置处理器(实现接口BeanFactoryPostProcessor的bean)。
//在beanFactory标准初始化之后执行 例如:PropertyPlaceholderConfigurer(处理占位符)
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//实例化和注册beanFactory中扩展了BeanPostProcessor的bean。
//例如:
//AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)
//RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法)
//CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//初始化国际化工具类MessageSource
initMessageSource();
// Initialize event multicaster for this context.
//初始化事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//模板方法,在容器刷新的时候可以自定义逻辑(子类自己去实现逻辑),不同的Spring容器做不同的事情
onRefresh();
// Check for listener beans and register them.
//注册监听器,并且广播early application events,也就是早期的事件
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//非常重要。。。实例化所有剩余的(非懒加载)单例Bean。(也就是我们自己定义的那些Bean们)
//比如invokeBeanFactoryPostProcessors方法中根据各种注解解析出来的类,在这个时候都会被初始化 扫描的 @Bean之类的
//实例化的过程各种BeanPostProcessor开始起作用~~~~~~~~~~~~~~
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//refresh做完之后需要做的其他事情
//清除上下文资源缓存(如扫描中的ASM元数据)
//初始化上下文的生命周期处理器,并刷新(找出Spring容器中实现了Lifecycle接口的bean并执行start()方法)。
//发布ContextRefreshedEvent事件告知对应的ApplicationListener进行响应的操作
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.
//如果刷新失败那么就会将已经创建好的单例Bean销毁掉
destroyBeans();
// Reset 'active' flag.
//重置context的活动状态 告知是失败的
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...
// 失败与否,都会重置Spring内核的缓存。因为可能不再需要metadata给单例Bean了。
resetCommonCaches();
}
}
}
通过上面的注释,已经能够比较宏观的了解到容器的一个初始化过程了,那么接下来,将针对每一个步骤,进行微观源码级别的解释说明。
protected void prepareRefresh() {
//记录容器启动时间,然后设立对应的标志位
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
// 打印info日志:开始刷新this此容器了
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
// 这是扩展方法,由子类去实现,可以在验证之前为系统属性设置一些值可以在子类中实现此方法
// 因为我们这边是AnnotationConfigApplicationContext,可以看到不管父类还是自己,都什么都没做,所以此处先忽略
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
//这里有两步,getEnvironment(),然后是是验证是否系统环境中有RequiredProperties参数值 如下详情
// 然后管理Environment#validateRequiredProperties 后面在讲到环境的时候再专门讲解吧
// 这里其实就干了一件事,验证是否存在需要的属性
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
// 初始化容器,用于装载早期的一些事件
this.earlyApplicationEvents = new LinkedHashSet<>();
}
AbstractApplicationContext#getEnvironment()
关于getEnvironment()
的顶层接口位于:EnvironmentCapable
,有如下实现(注意ConfigurableApplicationContext
是接口,所以其实上容器的实现只有AbstractApplicationContext
):
Demo代码如下:
@Autowired
private BeanFactory beanFactory;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
//web环境下
@Autowired
private HttpServletRequest request;
@Autowired
private HttpServletResponse response;
@Autowired
private HttpSession session;
@Autowired
private WebRequest webRequest;
@Override
public Object hello() {
System.out.println(beanFactory); //org.springframework.beans.factory.support.DefaultListableBeanFactory@3ff27f35
System.out.println(applicationContext); //Root WebApplicationContext: startup date [T ...
System.out.println(applicationEventPublisher); //Root WebApplicationContext: startup date [T ...
// 我们发现的是同一个Bean
System.out.println(System.identityHashCode(applicationEventPublisher) == System.identityHashCode(applicationContext)); //true
//web环境
// =================必须说明一点:这里注入的所有web对象,都是线程安全的=================
// 请求N次,每次输出的HashCode都是一样的,那怎么还没有线程安全问题呢?具体看下面分解原因
System.out.println(System.identityHashCode(request));
System.out.println(request.getClass()); //class com.sun.proxy.$Proxy22 这是个代理对象哟~~~~
System.out.println(request); //Current HttpServletRequest
System.out.println(response); //Current HttpServletResponse
System.out.println(session); //Current HttpSession
System.out.println(webRequest); //Current ServletWebRequest
return "service hello";
}
现状:我看到很多同事,还有小伙伴们在Controller层想要使用Servlet
源生API比如HttpServletRequest
的时候,让方法入参了去写,当你的Controller方法多了后(这是必然的),会让代码看起来十分的不优雅(重复工作太多)。
原因:把request放在方法入参里也不无道理。因为我们常识性的认为:由于Controller
是单例的,所以直接放在全局属性上,理论上肯定是有线程安全问题的。
迷惑点:为了证明这一点,然后每次请求都输出System.identityHashCode(request)
,发现HashCode是不变,因此可以确定的是,注入的request,肯定是同一个实例
线程安全的原因分析解释:
其实从上面一句request.getClass()
或许能看出端倪的,我们发现注入的是JDK的动态代理对象class com.sun.proxy.$Proxy22
(至于为何注入的是代理对象,请参考上面博文:细说Spring IOC容器的自动装配
这一篇有详细的分析讲解,代理类的处理器为:ObjectFactoryDelegatingInvocationHandler
),因此我们主要看看invoke
方法如下:
(图片所示为该处理器的调用地方和基本源码:)
public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) {
// 如果注入到的值为ObjectFactory类型(并且不是requiredType实例),就猪呢比下面的代理吧~~~
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue;
//autowiringValue 显示是实现了Serializable 接口的
// 并且requiredType是个接口(HttpServletRequest是接口,继承自ServletRequest)
// 所以此处注意了,只能根据接口进行注入才是线程安全的,如果注入实现类,线程就是不安全的(因为无法创建代理了) 但是显然我们不可能注入实现类的
if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
// 创建出来的代理对象,才是最终要被注入进去的值====
autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
}
else {
return factory.getObject();
}
}
return autowiringValue;
}
ObjectFactoryDelegatingInvocationHandler#invoke
:调用request的方法,都被代理到此处
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if (methodName.equals("equals")) {
// Only consider equal when proxies are identical.
return (proxy == args[0]);
}
else if (methodName.equals("hashCode")) {
// Use hashCode of proxy.
return System.identityHashCode(proxy);
}
else if (methodName.equals("toString")) {
return this.objectFactory.toString();
}
try {
// 核心在这里,每次调用的方法,实际上调用的是objectFactory.getObject()这个对象的对应方法,那么这个对象源码呢?
// beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
// 可以看出他是一个RequestObjectFactory类型,所以看下面getObject方法
return method.invoke(this.objectFactory.getObject(), args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
//RequestObjectFactory
private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
// 它每次返回的是和当前线程上下文绑定的一个request副本。至于怎么和上下文绑定的,下面贴出参考链接
// 有了这些解释,那肯定的这样注入的是线程安全的,不用再担心了
@Override
public ServletRequest getObject() {
return currentRequestAttributes().getRequest();
}
@Override
public String toString() {
return "Current HttpServletRequest";
}
}
request上下文是如何跟线程上下文绑定的,参考原理:【小家Spring】Spring MVC执行流程 FrameworkServlet、DispatcherServlet源码分析(processRequest、doDispatch)
小伙伴们以后要使用Servlet源生对象,不要只知道从方法入参里注入,看起来很不优雅,很不Spring MVC化,懂了这些原理来龙去脉后,相信可以放心的、安全的使用了~
从这方面可以看出,我们不得不佩服Spring的考虑周到。一个优秀的框架,绝对不仅仅是实现了某个功能而已,而是能让你用得舒服,用得爽 ,可扩展性非常强等一些附加属性比如下面的web容器
AbstractRefreshableWebApplicationContext
就会设置一些初始值:
@Override
protected void initPropertySources() {
ConfigurableEnvironment env = getEnvironment();
// 初始化web环境中的初始值(比如init等,这个后续会说)
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
}
}
@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
// 这个方法需要注意一下,默认是StandardEnvironment,但是它是protected方法设计,所以之类可以重写(如下图)
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}
//StandardServletEnvironment.initPropertySources(this.servletContext, null)
@Override
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
// 将 servletContext、servletConfig 添加到 propertySources里(ServletConfigPropertySource)
//ServletConfigPropertySource作用:reads init parameters from ServletConfig
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
}
它们都是web环境下的上下文,因此重写的方式也是一模一样:
//StandardServletEnvironment是web环境上下文里的Enviroment
@Override
protected ConfigurableEnvironment createEnvironment() {
return new StandardServletEnvironment();
}
StaticWebApplicationContext一般用于测试,几乎不使用
实际上就是重新创建一个bean工厂,并销毁原工厂。主要工作是创建DefaultListableBeanFactory实例,解析配置文件,注册Bean的定义信息
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
在spring中,基本上各司其职,每个类都有每个类的作用。其中refreshBeanFactory()
是具体的刷新BeanFactory
,负责这个工作做在类AbstractRefreshableApplicationContext#refreshBeanFactory
中,顾名思义这是专门用来刷新的:
@Override
protected final void refreshBeanFactory() throws BeansException {
// 判断是否已经存在BeanFactory,存在则销毁所有Beans,并且关闭BeanFactory
// 避免重复加载BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建具体的beanFactory,这里创建的是DefaultListableBeanFactory,最重要的beanFactory spring注册及加载bean就靠它
// createBeanFactory()这个方法,看下面,还有得说的
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 这句比较简单,就是把当前旧容器的一些配置值复制给新容器
// allowBeanDefinitionOverriding属性是指是否允对一个名字相同但definition不同进行重新注册,默认是true。
// allowCircularReferences属性是指是否允许Bean之间循环引用,默认是true.
// 这两个属性值初始值为空:复写此方法即可customizeBeanFactory
customizeBeanFactory(beanFactory);
// 这个就是最重要的了,加载所有的Bean配置信息,具体如下详细解释
// 它属于模版方法,由子类去实现加载的方式
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
createBeanFactory()
// 创建的时候就是new了一个工厂:DefaultListableBeanFactory 这个时候工厂里面所有东西都是默认值,很多还没有完成初始化属性的设置呢
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
// 给设置父的BeanFactory,若存在的话
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory);
}
// 父类空构造器有这么些语句
public AbstractAutowireCapableBeanFactory() {
super();
// 这里是重点。忽略自动装配。这里指定的都是接口。什么意思呢?
// ignoreDependencyInterface的真正意思是在自动装配时忽略指定接口的实现类中,对外的依赖。(这里面注意:@Autowired和它的关系,其实是有坑的,后续会专门讲解这个坑)
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
//找到父的,若存在就返回 若存在父容器就存在父的BeanFactory
@Nullable
protected BeanFactory getInternalParentBeanFactory() {
return (getParent() instanceof ConfigurableApplicationContext) ?
((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
}
AnnotationConfigWebApplicationContext#loadBeanDefinitions()
方法,加载Bean的定义 (XmlWebApplicationContext
的实现不一样,因为它是加载xml配置文件)
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
// 初始化这个脚手架 其实就是直接new出实例。具体做的工作,下面有相关博文链接
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
// 生成Bean的名称的生成器,如果自己没有setBeanNameGenerator(可以自定义),这里目前为null
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
//若我们注册了beanName生成器,那么就会注册进容器里面
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
//这是给reader和scanner注册scope的解析器 此处为null
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
// 此处注意了:annotatedClasses和basePackages一般是选其一(当然看到此处,他们是可以并存的)
//我们可以自己指定annotatedClasses 配置文件,同时也可以交给下面扫描
if (!this.annotatedClasses.isEmpty()) {
// 这里会把所有的配置文件输出=======info日志 请注意观察控制台
if (logger.isInfoEnabled()) {
logger.info("Registering annotated classes: [" +
StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
}
// 若是指明的Bean,就交给reader去处理,至于怎么处理,见上篇博文的doRegisterBean去怎么解析每一个Config Bean的
reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
// 也可以是包扫描的方式,扫描配置文件的Bean
if (!this.basePackages.isEmpty()) {
// 输出对应的info日志
if (logger.isInfoEnabled()) {
logger.info("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
// 这里重要了,scan方法具体做了什么事,上篇博文也有详细的介绍,请参阅
scanner.scan(StringUtils.toStringArray(this.basePackages));
}
// 此处的意思是,也可以以全类名的形式注册。比如可以调用setConfigLocations设置(这在xml配置中使用较多) 可以是全类名,也可以是包路径
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
reader.register(clazz);
} catch (ClassNotFoundException ex) {
// 发现不是全类名,那就当作包扫描吧
int count = scanner.scan(configLocation);
}
}
}
}
最开始涉及到两个类的初始化,请参考博文:
【小家Spring】Spring容器加载Bean定义信息的两员大将:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
有了这篇博文解释这两个类先行,理解上面loadBeanDefinitions
就简单太多了。至此,整个ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
这个步骤全部结束。
现在BeanFactory
已经创建了,并且Config配置文件的Bean定义已经注册完成了**(备注:其它单例Bean是还没有解析的)**
显然,下面的步骤大都把BeanFactory传进去了,都是基于此Bean工厂的了~~~
这个方法是配置工厂的标准上下文特征
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置beanFactory的classLoader为当前context的classLoader
beanFactory.setBeanClassLoader(getClassLoader());
// 设置EL表达式解析器(Bean初始化完成后填充属性时会用到)
// spring3增加了表达式语言的支持,默认可以使用#{bean.xxx}的形式来调用相关属性值
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 设置属性注册解析器PropertyEditor 这个主要是对bean的属性等设置管理的一个工具
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 将当前的ApplicationContext对象交给ApplicationContextAwareProcessor类来处理,从而在Aware接口实现类中的注入applicationContext等等
// 添加了一个处理aware相关接口的beanPostProcessor扩展,主要是使用beanPostProcessor的postProcessBeforeInitialization()前置处理方法实现aware相关接口的功能
// 类似的还有ResourceLoaderAware、ServletContextAware等等等等
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 下面是忽略的自动装配(也就是实现了这些接口的Bean,不要Autowired自动装配了)
// 默认只有BeanFactoryAware被忽略,所以其它的需要自行设置
// 因为ApplicationContextAwareProcessor把这5个接口的实现工作做了(具体你可参见源码) 所以这里就直接忽略掉
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 设置几个"自动装配"规则======如下:
// 如果是BeanFactory的类,就注册beanFactory
// 如果是ResourceLoader、ApplicationEventPublisher、ApplicationContext等等就注入当前对象this(applicationContext对象)
// 此处registerResolvableDependency()方法注意:它会把他们加入到DefaultListableBeanFactory的resolvableDependencies字段里面缓存这,供后面处理依赖注入的时候使用 DefaultListableBeanFactory#resolveDependency处理依赖关系
// 这也是为什么我们可以通过依赖注入的方式,直接注入这几个对象比如ApplicationContext可以直接依赖注入
// 但是需要注意的是:这些Bean,Spring的IOC容器里其实是没有的。beanFactory.getBeanDefinitionNames()和beanFactory.getSingletonNames()都是找不到他们的,所以特别需要理解这一点
// 至于容器中没有,但是我们还是可以@Autowired直接注入的有哪些,请看下图:
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 注册这个Bean的后置处理器:在Bean初始化后检查是否实现了ApplicationListener接口
// 是则加入当前的applicationContext的applicationListeners列表 这样后面广播事件也就方便了
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 检查容器中是否包含名称为loadTimeWeaver的bean,实际上是增加Aspectj的支持
// AspectJ采用编译期织入、类加载期织入两种方式进行切面的织入
// 类加载期织入简称为LTW(Load Time Weaving),通过特殊的类加载器来代理JVM默认的类加载器实现
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
// 添加BEAN后置处理器:LoadTimeWeaverAwareProcessor
// 在BEAN初始化之前检查BEAN是否实现了LoadTimeWeaverAware接口,
// 如果是,则进行加载时织入,即静态代理。
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注入一些其它信息的bean,比如environment、systemProperties、SystemEnvironment等
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
说个小细节:@Autowiredh和@Qualifier一起是用时,@Qualifier的值需保证容器里一定有,否则启动报错
这部分比较简单,就是设置一些标准的值,解释都放代码里了。
模版方法。因为beanFactory都准备好了,子类可以自己去实现自己的逻辑。
比如一些web的ApplicationContext,就实现了自己的逻辑,做一些自己的web相关的事情。此处我们就是web环境下,因此会进来AbstractRefreshableWebApplicationContext#postProcessBeanFactory
方法:
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//注册ServletContextAwareProcessor 这样任意Bean都可以很方便的获取到ServletContext了 同时忽略另外两个,因为ServletContextAwareProcessor 都把事情都做了
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
//注册web环境,包括request、session、golableSession、application
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
//注册servletContext、contextParamters、contextAttributes 、servletConfig单例bean
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
这里面两个工具方法,具体做了什么,请参考:
【小家Spring】spring-web包里的一些好用的工具介绍,WebUtils,RequestContextUtils,WebApplicationContextUtils等
invokeBeanFactoryPostProcessors执行BeanFactory后置处理器,当然前提是你已经在容器中注册过此处理器了。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
// 这里就是定制:如果loadTimeWeaver这个Bean存在,那么就会配置上运行时织入的处理器LoadTimeWeaverAwareProcessor
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
这里面我们必须先看看getBeanFactoryPostProcessors()
这个方法:
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
这里非常有意思。方法非常简单,但有意思在于:它不是返回Spring容器里面的Processors,而是你自己的注册的(你自己手动set的),也就是说我们自己手动调用set方法添加进去,就能够执行。并不需要自己配置@Bean或者在xml里配置
那么重点就在于PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
,它的代码可谓非常非常多:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
// 这个doc说明很清楚:不管怎么样,先执行BeanDefinitionRegistryPostProcessors
// 需要注意的是BeanDefinitionRegistryPostProcessors 为 BeanFactoryPostProcessor 的子接口 它新增了方法:void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
// BeanFactoryPostProcessor 的方法为;void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
// 所以BeanDefinitionRegistryPostProcessors,它可以我们介入,改变Bean的一些定义信息
Set<String> processedBeans = new HashSet<>();
// 只有此beanFactory 是BeanDefinitionRegistry 才能执行BeanDefinitionRegistryPostProcessor,才能修改Bean的定义嘛~
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 此处安放了两个容器,一个装载普通的BeanFactoryPostProcessor
// 另外一个装载和Bean定义有关的 BeanDefinitionRegistryPostProcessor
// 另外都是LinkedList,所以执行顺序和set进去的顺序是保持一样的
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
// 这里是我们自己的set进去的,若没set,这里就是空(若是Sprng容器里的,下面会处理,见下面)
// 从此处可以看出,我们手动set进去的,最最最最有限执行的
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
// 这里执行post方法,然后然后吧它缓冲起来了,放在了registryProcessors里
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
// 缓冲起来常规的处理器
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
// 接下来,就是去执行Spring容器里面的一些PostProcessor了。他们顺序doc里也写得很清楚:
// 先执行实现了PriorityOrdered接口的,然后是Ordered接口的,最后执行剩下的
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 先从容器中拿出来所有的BeanDefinitionRegistryPostProcessor 然后先执行PriorityOrdered
// 本例中有一个这个类型的处理器:ConfigurationClassPostProcessor(显然是处理@Configuration这种Bean的)
// 至于这个Bean是什么时候注册进去的,前面有。在loadBeanDefinitions()初始化AnnotatedBeanDefinitionReader的时候调用的AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)方法的时候,注册了6个Bean
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// processedBeans也顺带保存了一份,保存的是bean的Name哦~
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 此处缓冲起来(需要注意的是,是排序后,再放进去的 这样是最好的)
registryProcessors.addAll(currentRegistryProcessors);
// 这个方法很简单,就是吧currentRegistryProcessors里面所有的处理器for循环一个个的执行掉(本处只有ConfigurationClassPostProcessor,详见我的另一篇专门博文讲解)
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 此处把当前持有的执行对象给清空了,需要注意。以方便装载后续执行的处理器们
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 此处逻辑完全同上 处理实现Order接口的RegistryProcessors
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 最后执行,两个排序接口都没有实现的BeanDefinitionRegistryPostProcessor们,并且也缓存起来
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
// 现在,这里很明显:去执行BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
// 以及 顶层接口BeanFactoryPostProcessor的postProcessBeanFactory方法
// 我们当前环境regularPostProcessors长度为0.registryProcessors有一个解析@Configuration的处理器
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
// Invoke factory processors registered with the context instance.
// 若是普通的Bean工厂,就直接执行set进来的后置处理器即可(因为容器里就没有其它Bean定义了)
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// 下面就是开始执行BeanFactoryPostProcessor 基本也是按照上面的顺序来执行的
// 上面9个Bean,我们知道 也就ConfigurationClassPostProcessor是实现了此接口的。因此本环境下,只有它了,并且它在上面还已经执行了
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
// 这里面注意,已经执行过的后置处理器,就不要再执行了
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
ConfigurationClassPostProcessor
处理器解析: 【小家Spring】Spring解析@Configuration注解的处理器:ConfigurationClassPostProcessor(ConfigurationClassParser)
postProcessBeanDefinitionRegistry和postProcessBeanFactory
方法:
两者都存在于BeanDefinitionRegistryPostProcessor接口中,表明其既可以自定义BeanDefinition并注册进容器中也可以对beanFactory的修改
那为什么逻辑要先执行postProcessBeanDefinitionRegistry然后在执行postProcessBeanFactory呢?
因为postProcessBeanDefinitionRegistry是用来创建bean定义的,而postProcessBeanFactory是修改BeanFactory,当然postProcessBeanFactory也可以修改bean定义的。为了保证在修改之前所有的bean定义的都存在,所以优先执行postProcessBeanDefinitionRegistry。如不是以上顺序,会出先再修改某个bean定义的报错,因为此bean定义的还没有被创建。
至此,invokeBeanFactoryPostProcessors(beanFactory)
这一步就完成了。这一步主要做了:
这里注册Bean定义的时候有个小细节:我们都知道Spring支持到了FactoryBean的模式,所以这里如果发现注册的Bean为FactoryBean类型的话,会把自己以及getObject()出来的对象的Bean定义都注册上去。并且FactoryBean的名称为:beanName = FACTORY_BEAN_PREFIX + beanName; 这一点需要注意
上面5个步骤,已经Bean工厂完全准备好了,并且也注册好了所有的Bean的定义信息(此时Bean还并没有创建)。也完成了对配置文件的解析,可以说Spring IOC容器的大的准备工作已经完成了,在接下来的一篇博文里,会详细讲述到对Bean的一些初始化、以及操作~