关注「Java视界」公众号,获取更多技术干货

【一篇搞懂】Sping 容器启动过程详解

准备工作:

看源码当然要打断点,一步步跟着看更直观,示例代码如下:

@EnableAspectJAutoProxy
@Configuration
public class AopOneConfig {

    @Bean
    public AopOne aopOne() {
        return new AopOne();
    }

    @Bean
    public AopOneAspect oneAspect() {
        return new AopOneAspect();
    }
}
    @Test
    public void test1() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopOneConfig.class);
        AopOne bean = applicationContext.getBean(AopOne.class);
        bean.compute(10, 1);
    }

一、 基本概念

 先来搞清楚spring中的一些基本概念。

1.1 Spring是一个IOC容器

为什么说srping是个容器呢?记得刚开始java开发的时候还问过一个多年开发经验的同事这个问题,他也没说得很透彻,至少当时他当时说得我没明白。

实际上,以前不用spring进行开发时,我们需要在代码中设置对象的依赖关系。当我们用了Spring之后,由Spring来管理这种依赖关系,当我们想使用对象时,直接从Spring中获取即可。

这一点上,spring不就和普通JDK里面的List、Map等容器获取其中的元素不就差不多了么,所以说Spring是个容器,只不过里面的元素是bean。

1.2 BeanDefinition

上面说了,Spring是个容器,里面的元素是bean,我们需要的时候直接从spring中获取。

那你会说,bean不就是某个类的对象或者实例么?对,但又不完全对!

这里要说到spring中的bean和普通Java类的实例的区别

那就是spring中的bean,在Java类的基础上增加了很多概念属性,比如scope(作用域),isLazyInit(是否延迟初始化),isSingleton(是否单例)等属性特征。

也就是说,普通的Java类是不能完整描述上面的属性的,那Spring就通过BeanDefinition这个类来描述普通的Java类的属性以及额外的cope(作用域),isLazyInit(是否延迟初始化),isSingleton(是否单例)等属性特征。

spring就是根据BeanDefinition来实例化对应的bean。

这就是BeanDefinition的由来。

1.3 BeanDefinitionReader

上面说了BeanDefinition类是用来描述普通的Java类的属性以及额外的cope(作用域),isLazyInit(是否延迟初始化),isSingleton(是否单例)等属性特征。

那总要有个能从我们配置的bean的地方获取这些属性的类吧,这个类就是BeanDefinitionReader。BeanDefinitionReader会将配置的bean解析成为BeanDefinition。

Spring Bean的配置方式有很多种,如XML,properties,groovy,注解(可能通过properties,groovy的方式你不常用,但Spring确实支持这种方式),所以BeanDefinitionReader的实现类也很多:

2w字搞懂Spring Bean的一生

1.4 BeanDefinitionRegistry

BeanDefinitionReader将配置的bean解析成为BeanDefinition,需要将BeanDefinition保存到BeanDefinitionRegistry。类似工厂把原料保存到仓库中,登记一下,供后续生产产品使用。

1.5 BeanFactory

BeanFactory会根据BeanDefinition将Bean生产出来,并保存下来。

1.6 DefaultListableBeanFactory

DefaultListableBeanFactory在绝大多数的场景都是BeanFactory的实现类,DefaultListableBeanFactory实现了BeanDefinitionRegistry接口和BeanFactory接口,所以能保存Bean定义,同时又能根据Bean定义将Bean生产出来。

1.7 BeanPostProcessor

BeanFactory根据BeanDefinition生成Bean的过程是一个标准化的流程,就像一个流水线一样,当然你可以在这个流水线上做一些自定义的操作。

在Spring中你可以通过实现BeanPostProcessor来干预Bean的生产过程,所以这个BeanPostProcessor很重要,比如AOP等都是利用这个进行实现的。

BeanPostProcessor 可以在bean的初始化前后进行自定义的处理。可以参考:

sprig中怎么指定一个bean的初始化和销毁方法?一下子都搞懂! 第四节

1.8 BeanFactoryPostProcessor

Spring作为一个强大的容器,不仅能让你干预Bean的生产过程,还可以让你干预BeanFactory,例如你可以通过BeanFactoryPostProcessor将Bean的作用域都该成原型,默认是单例。

1.9  父 BeanFactory —— ParentBeanFactory

在 Spring 中可能存在多个 BeanFactory,多个 BeanFactory 可能存在 “父工厂” 与 “子工厂” 的关系。最常见的例子就是:Spring MVC 的 BeanFactory 和 Spring 的 BeanFactory,通常情况下,Spring 的 BeanFactory 是 “父工厂”,Spring MVC 的 BeanFactory 是 “子工厂”。

在 Spring 中,子工厂可以使用父工厂的 BeanDefinition,因而,如果在当前 BeanFactory 中找不到,而又存在父工厂,则会去父工厂中查找。

1.10  spring中的几个重要的缓存

mergedBeanDefinitions 缓存:beanName -> 合并的 bean 定义。
beanDefinitionMap 缓存:beanName -> BeanDefinition。
singletonObjects 缓存:beanName -> 单例 bean 对象。
earlySingletonObjects 缓存:beanName -> 单例 bean 对象,该缓存存放的是早期单例 bean 对象,可以理解成只是实例化有个引用,还未进行属性填充、初始化。
singletonFactories 缓存:beanName -> ObjectFactory。
singletonsCurrentlyInCreation 缓存:当前正在创建单例 bean 对象的 beanName 集合。

二、Spring容器启动流程

Spring容器启动流程包含主要有两个过程:容器初始化、容器刷新。

我们常用的容器有如下2种

  1. 基于xml配置Bean(ClassPathXmlApplicationContext)
  2. 基于注解配置Bean(AnnotationConfigApplicationContext)

以AnnotationConfigApplicationContext的启动流程为例:

@Repository
public class UserDao {
 public String getUser() {
  return "user";
 }
}
@Configuration
@ComponentScan("com.javashitang")
public class AppConfig {
}
public class Main {
 public static void main(String[] args) {
  // 容器启动完毕
  AnnotationConfigApplicationContext context = 
            new AnnotationConfigApplicationContext(AppConfig.class);
  UserDao userDao = context.getBean(UserDao.class);
  String str = userDao.getUser();
  System.out.println(str);
 }
}

当AnnotationConfigApplicationContext被new出来的时候,容器已经启动完毕,后续就可以直接从容器中获取Bean了。

AnnotationConfigApplicationContext的继承与实现关系如下:

图三

构造函数主要执行了如下3个步骤,其中this和register方法主要是容器初始化的过程。refresh是刷新容器,即启动的过程。

2w字搞懂Spring Bean的一生

2.1 容器初始化过程 —— this()

 this()方法里面做了啥?

this() 方法流程

AnnotatedBeanDefinitionReader用于获取一个或多个带有注解的具体类,之后将他们解析为BeanDefintion,之后注册到Registry中;ClassPathBeanDefinitionScanner用获取一个或多个包下的带有注解的类,之后将他们解析为BeanDefintion,注册到Registry中。

第一点:在容器初始化的过程中注册了6个Bean

  1. ConfigurationClassPostProcessor(实现了BeanFactoryPostProcessor,处理@Configuration,@ComponmentScan等注解,这是一个很重要的类)
  2. AutowiredAnnotationBeanPostProcessor(实现了BeanPostProcessor,处理@Autowired,@Value等)
  3. CommonAnnotationBeanPostProcessor(实现了BeanPostProcessor,用来处理JSR-250规范的注解,如@Resource,@PostConstruct等)
  4. PersistenceAnnotationBeanPostProcessor(实现了BeanFactoryPostProcessor,用来支持JPA,在我们这个Demo中不会注册,因为路径中没有JPA相关的类)
  5. EventListenerMethodProcessor(实现了BeanFactoryPostProcessor)
  6. DefaultEventListenerFactory

第二点:

初始化的过程可以看到初始化beanFactory为DefaultListableBeanFactory。

2.2.注册 —— register()

this()调用本类的无参构造后,接着开始执行 register(annotatedClasses) 方法。

public void register(Class<?>... annotatedClasses) {
		Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
		this.reader.register(annotatedClasses);
}

入参 annotatedClasses是进行初始化的时候传入的类。

最终调用的是doRegisterBean方法: 

下面解析下上面的doRegisterBean方法的逻辑: 

(1)AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);

上面是将传进来的annotatedClass转化为AnnotatedGenericBeanDefinition。

BeanDefinition描述了一个bean的实例,AnnotatedGenericBeanDefinition实现了接口AnnotatedBeanDefinition,而AnnotatedBeanDefinition继承了BeanDefinition。AnnotatedBeanDefinition比BeanDefinition多出getMetadata()方法,用于获得类上的注解信息。spring4.1.1之后还多出了getFactoryMethodMetadata()方法,也是用于获得类上的注解信息。
AnnotationMetadata类是AnnotatedGenericBeanDefinition的成员变量,记录注解信息传入的annotatedClass上面的注解信息,StandardAnnotationMetadata是它的标准实现类,用标准的反射来获取制定类的内部注解信息,打个断点看下:

正好就是我们的测试配置类 AopOneConfig 上面的两个注解。

(2)if (this.conditionEvaluator.shouldSkip(abd.getMetadata()))

 doRegisterBean()方法是AnnotatedBeanDefinitionReader中的一个方法,这里的 this.conditionEvaluator 表明conditionEvaluator 是 AnnotatedBeanDefinitionReader的一个成员变量,随着上面一步this()方法AnnotatedBeanDefinitionReader初始化而初始化。

ConditionEvaluator这个类主要用于完成条件注解@Conditional的解析和判断。@Conditional 是Spring 4框架的新特性。此注解使得只有在特定条件满足时才启用一些配置。ConditionEvaluator的shouldSkip就是用于判断@Conditional下的而配置是否被启用。

再打个断点看下:

上面的前两句代码表示如果这个类没有被@Conditional注解所修饰,返回false,不会skip。这里我们的测试配置类 AopOneConfig没有使用@Conditional注解,因此返回false继续执行后面的逻辑。

(3)ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);

ScopeMetadata 从命名就可以知道是和bean的作用域有关的,就两个属性:

上面这句代码点进去:

ScopeMetadata 的scope默认是singleton。我们打个断点看下attributes的值:

AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType)。this.scopeAnnotationType是AnnotationScopeMetadataResolver成员变量,值为Scope.class。该方法就是从元数据中获得注解scope的值,并将其返回。如果没有配置@scope,所以attributes=null, 那么它的默认值就是singleton,即单例模式。

(4)String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

这句代码就是说生成一个bean的name,若name有值,那就取这个值;看前面的代码:

name传的null,那就会走this.beanNameGenerator.generateBeanName()

这里beanNameGenerator是AnnotatedBeanDefinitionReader的一个成员变量,是类AnnotationBeanNameGenerator的一个实例。

老规矩打个断点看下,先在 determineBeanNameFromAnnotation 方法里面打个断点:

getAnnotationTypes()方法获得所有的注解,遍历这些注解,AnnotationConfigUtils.attributesFor()方法读取注解对应的所有属性。

这时type = org.springframework.context.annotation.EnableAspectJAutoProxy,看到attributes的两个值正好是@EnableAspectJAutoProxy的两个属性值。

isStereotypeWithNameValue()方法用于判断 这些注解是否是@component注解,是否继承了@component注解,是否是@ManageBean注解,是否是@Named注解,如果满足以上条件中的任何一个并且包含value属性,则返回true。

@Configuration注解显然是满足的,因此isStereotypeWithNameValue()方法返回true,那就把value值作为beanName。

而@EnableAspectJAutoProxy注解不满足,因此isStereotypeWithNameValue()方法返回false,beanName = null返回,到了外层会调用 buildDefaultBeanName()方法。

我们在buildDefaultBeanName()方法中打上断点,看看怎么生成默认的beanName:

可以看到如果是AnnotationBeanDefinition的话,执determineBeanNameFromAnnotation(),从注解上获得bean name。

如果不是AnnotationBeanDefinition,buildDefaultBeanName()方法直接将类名(不含包名)作为bean name。

(5)String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

这句代码使用AnnotationConfigUtils的processCommonDefinitionAnnotations方法处理注解Bean定义类中通用的注解。 


通用的注解有哪些呢?源码已经给出了答案,processCommonDefinitionAnnotations方法处理了5个注解,分别是:

  • @lazy注解:用于指定该Bean是否懒加载,如果该注解的value为true的话,则这个bean在spring容器初始化之后,第一次使用时才初始化。AbstractBeanDefinition中定义该值的默认值是false。即默认立即加载。
  • @primary注解:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常。
  • @DependsOn注解:定义Bean初始化顺序。
  • 如果这个bean是AbstractBeanDefinition的子类的话,还会处理以下两个注解:
  • @Role注解:用于用户自定义的bean,value值是int类型,表明该bean在应用中的角色,默认值是0,极少用到。
  • @Description注解:用于描述bean,提高代码可读性,极少用到。

(6)if (qualifiers != null)

这一段代码是针对 @Qualifier注解的,一般情况下,@Autowired是根据类型进行自动装配的。如果当Spring上下文中存在不止一个该类型的bean时,就会抛出BeanCreationException异常。@Qualifier可以配置自动依赖注入装配的限定条件,@Qualifier 可以直接指定注入 Bean 的名称,简单来说, @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。

(7)BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);

BeanDefinitionHolder就是一个BeanDefinition的持有者:

这行代码就是把BeanDefination简单的封装为BeanDefinitionHolder。

(8)definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

在applyScopedProxyMode()方法中打个断点看下:

ScopedProxyMode值实在@scope注解中使用proxyMode属性设置的,默认为NO,就是没有代理。

它还可被设置为ScopedProxyMode. INTERFACES或者是ScopedProxyMode. TARGET_CLASS。

@scope注解的value可以设置为以下几种:  单例(singleton)、 原型(prototype)、会话(session)、请求(request),

 当一个singleton作用域的bean中需要注入一个session作用域的bean的时候,会报错,应为此时应用没有人访问,session作用域bean没有创建,所以出现了问题。spring提供给我们的解决方案就是通过设置proxyMode属性的值来解决,当他设置为ScopedProxyMode. INTERFACES或者是ScopedProxyMode. TARGET_CLASS时,spring会为session作用域bean创建代理对象,而真正调用的bean则在运行时懒加载,两者的区别是一个使用JDK提供的动态代理实现,一个使用CGLIB实现。
这段代码就是通过判断proxyMode的值为注册的Bean创建相应模式的代理对象。默认不创建。

(9)BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); 

就是把BeanDefinition注册到spring中,其实就是找个Map容器存储起来,后面若要使用则直接从这个Map中获取。

这里的Map就是this.beanDefinitionMap,它是DefaultListableBeanFactory一个成员变量。

这个很好理解,DefaultListableBeanFactory是要创建bean的,那自己总要先保存这些bean的定义。

registerBeanDefinition()方法有多个实现,因为 this.beanFactory是在初始化GenericApplicationContext类时初始化的,是一个DefaultListableBeanFactory。DefaultListableBeanFactory也实现了BeanDefinitionRegistry接口的registerBeanDefinition方法,所以最终调用的是DefaultListableBeanFactory的registerBeanDefinition方法。
,GenericApplicationContext和DefaultListableBeanFactory都是下面的逻辑:

    @Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

参数 this.registry 其实就是AnnotationConfigApplicationContext实例对象,spring的上下文。

总体来说,首先对BeanDefiniton  的校验,具体来说,是对AbstractBeanDefinition属性中的methodOverrides 效验; 效验methodOverrides 是否与工厂方法并存或者methodOverrides对应的方法根本不存在。

然后对容器中已经存在了一个同名bean的处理方法。如果对应beanName已经注册 并且beanName不能被覆盖,则抛出异常,否则后注册的覆盖先注册的。

正常情况会将beanName和beanDefinition放到beanDefinitionMap中,此时的beanDefinitionMap中已经存在了5个beanDefinition,前面一节调用无参构造 this()中放进去的5个处理器。

 registerBeanDefinition方法之后,还有registry.registerAlias(beanName, alias)方法,这是给bean注册别名用的。其实就是spring上线文对bean名称和别名之间维护了映射关系。

打个断点更直观:

当然这段逻辑还有一些日志打印的代码。

2.3 容器刷新过程 —— refresh()

容器刷新的过程可以细分为如下几个步骤:

  1. Spring应用上下文启动准备阶段
  2. BeanFactory创建阶段
  3. BeanFactory准备阶段
  4. BeanFactory后置处理阶段
  5. BeanFactory注册BeanPostProcessor阶段
  6. 初始化内建Bean:MessageSource
  7. 初始化内建Bean:Spring事件广播器
  8. Spring应用上下文刷新阶段
  9. Spring事件监听器注册阶段
  10. BeanFactory初始化完成阶段
  11. Spring应用上下文启动完成阶段

2w字搞懂Spring Bean的一生

2.1.1 Spring应用上下文启动准备阶段 —— prepareRefresh

  1. 记录启动时间 startupDate
  2. 设置标志为closed(false),active(true)
  3. 初始化PropertySources
  4. 校验Environment中必须属性
  5. 初始化事件监听器集合
  6. 初始化早期Spring事件集合

startupShutdownMonitor是一个object,是refresh方法和destory方法公用的一个监视器,避免两个方法同时执行。 

 prepareRefresh方法首先设置容器启动时间和启动标志字段。

initPropertySources是个空方法,不执行任何操作。

getEnvironment().validateRequiredProperties主要是验证this.requiredProperties中的key是否有对应的value值。如果找不到,就会抛出异常。

最后初始化监听、事件等。

2.1.2  BeanFactory创建阶段 —— obtainFreshBeanFactory

刷新Spring应用上下文底层BeanFactory(refreshBeanFactory)

  1. 通过CAS判断当前上下文是否已经刷新,重复刷新会报错
  2. 为序列化目的指定一个 id,如果需要,允许将此 BeanFactory 从此 id 反序列化回 BeanFactory 对象
  3. 返回beanFactory

返回Spring应用上下文底层BeanFactory(getBeanFactory)。

(1)先看里面的 refreshBeanFactory() 

compareAndSet方法是说:如果当前值是预期值,则原子地将值设置为给定的更新值。 底层调用的是Unsafe.compareAndSwapInt() 方法:

Unsafe.compareAndSwapInt() 方法是Java的native方法,并不由Java语言实现。方法的作用是,读取传入对象o在内存中偏移量为offset位置的值与期望值expected作比较。

  • 相等就把x值赋值给offset位置的值。方法返回true。
  • 不相等,就取消赋值,方法返回false。

这也是CAS的思想,及比较并交换。用于保证并发时的无锁并发的安全性。

 这里的getId()方法,直接返回的是这个BeanFactory的Id,是直接获取,那你可定会想这个ID啥时候有的?

图三说明了AnnotationConfigApplicationContext的继承关系,它继承至AbstractApplicationContext,这个ID就是AbstractApplicationContext的属性:

前面也说了,AnnotationConfigApplicationContext启动时的this()方法会把beanFactory初始化为DefaultListableBeanFactory,这个ID就是在这时生成的,可以在这里打个断点看下。

(2)先看里面的 getBeanFactory() 

这里看到  this.beanFactory 取的是 GenericApplicationContext 的属性。和上面的ID一样,AnnotationConfigApplicationContext启动时的this()方法会把beanFactory初始化为DefaultListableBeanFactory。

我们知道子类在实例化的时候会调用父类的无参构造方法,而图三的继承关系中AnnotationConfigApplicationContext继承至GenericApplicationContext,GenericApplicationContext的无参构造如下:

可以看到这个this.beanFactory是在这里被赋值。

2.1.3 BeanFactory准备阶段 —— prepareBeanFactory

BeanFactory 已经创建了,接下来就是给它预处理一下,配置工厂的标准上下文特性,例如上下文的类加载器和后处理器等:

  1. 关联ClassLoader
  2. 设置Bean表达式处理器
  3. 添加PropertyEditorRegistrar 的实现 ResourceEditorRegistrar
  4. 注册BeanPostProcessor(ApplicationContextAwareProcessor),用来处理Aware回调接口
  5. 忽略Aware回调接口作为依赖注入接口
  6. 注册ResolvableDependency对象-BeanFactory,ResourceLoader,ApplicationEventPublisher,ApplicationContext
  7. 注册BeanPostProcessor(ApplicationListenerDetector),用来处理ApplicationListener接口
  8. 注册BeanPostProcessor(LoadTimeWeaverAwareProcessor),用来处理aop
  9. 注册单例对象(Environment,Java System Properties以及OS环境变量)

(1)beanFactory.setBeanClassLoader(getClassLoader()) 为BeanFactory设置了一个类加载器,BeanFactory 需要加载类,也就需要类加载器,是一个AppClassLoader。

(2)beanFactory.setBeanExpressionResolver 为BeanFactory设置了一个BeanExpressionResolver。StandardBeanExpressionResolver是用来解析EL表达式的,比如配置文件或者@Value("#{...}")等使用。

(3)beanFactory.addPropertyEditorRegistrar 注册属性编辑器ResourceEditorRegistrar,将输入的字符串转换成我们期望的数据类型。例如InputStreamEditor这个属性编辑器,可以将spring配置文件中,用字符串表示的文件路径,转成Resource资源类,注入到bean的对应属性中。

(4)beanFactory.addBeanPostProcessor是为这个beanFactory添加bean的后置处理,用于在Bean的初始化前后做一些事情。比如这里添加了ApplicationContextAwareProcessor,ApplicationListenerDetector。

(5)beanFactory.ignoreDependencyInterface 设置忽略给定接口的自动装配功能。为什么要配置这个?举例来说,当类A中有属性B时,在从spring容器中获取A对象时会查看属性是否初始化,没有的话会自动初始化B。然而有些情况下是不希望初始化属性B的,例如B实现了BeanNameAware、BeanFactoryAware、BeanClassLoaderAware接口,作用分别是获取其在容器中的名称、容器、类加载器,这些接口都有各自的set方法,想装配B这个对象,可以实现这些接口,通过它们的set方法进行装配。

这个有些抽象,本文后面的补充里会详细说明这个的ignoreDependencyInterface 和 ignoreDependencyType 的含义。

(6)beanFactory.registerResolvableDependency使用相应的自动装配值注册一个特殊的依赖类型。resolvableDependencies中保存了类名和实例之间的映射,注入的时候可以直接拿来用。

(7)beanFactory.registerSingleton  在给定的 bean 名称下,在 bean 注册表中将给定的现有对象注册为单例。

(8)prepareBeanFactory(),这里面注入了ApplicationContextAwareProcessor和ApplicationListenerDetector,下面分别来看看这两个BeanPostProcessor。

ApplicationContextAwareProcessor

class ApplicationContextAwareProcessor implements BeanPostProcessor {

	private final ConfigurableApplicationContext applicationContext;

	private final StringValueResolver embeddedValueResolver;

	/**
	 * Create a new ApplicationContextAwareProcessor for the given context.
	 */
	public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
	}

	@Override
	@Nullable
	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		AccessControlContext acc = null;

		if (System.getSecurityManager() != null &&
				(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
						bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
						bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}
		return bean;
	}

	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof EnvironmentAware) {
				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
			}
			if (bean instanceof EmbeddedValueResolverAware) {
				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
			}
			if (bean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
			}
			if (bean instanceof ApplicationEventPublisherAware) {
				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
			}
			if (bean instanceof MessageSourceAware) {
				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
			}
			if (bean instanceof ApplicationContextAware) {
				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
			}
		}
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		return bean;
	}
}

ApplicationContextAwareProcessor干啥的?它是一种BeanPostProcessor,那就意味着在bean实例化前后执行。其中org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization 是这样的:

  • (1)判断当前的bean是否实现了某个指定的Aware接口
  • (2)如果当前bean实现了某个Aware接口。那就调用该接口对应的方法

postProcessBeforeInitialization 中调用了invokeAwareInterfaces。

org.springframework.context.support.ApplicationContextAwareProcessor#postProcessAfterInitialization,则是直接返回这个bean,即不做任何处理。

ApplicationListenerDetector

    @Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (bean instanceof ApplicationListener) {
			// potentially not detected as a listener by getBeanNamesForType retrieval
			Boolean flag = this.singletonNames.get(beanName);
			if (Boolean.TRUE.equals(flag)) {
				// singleton bean (top-level or inner): register on the fly
				this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
			}
			else if (Boolean.FALSE.equals(flag)) {
				if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
					// inner bean with other scope - can't reliably process events
					logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
							"but is not reachable for event multicasting by its containing ApplicationContext " +
							"because it does not have singleton scope. Only top-level listener beans are allowed " +
							"to be of non-singleton scope.");
				}
				this.singletonNames.remove(beanName);
			}
		}
		return bean;
	}

Aware接口是干啥的?

我们看一下ApplicationContextAwareProcessor类中出现的各个Aware接口的源码:

  • EnvironmentAware

  • EmbeddedValueResolverAware

  • ResourceLoaderAware

  • ApplicationEventPublisherAware

  • MessageSourceAware

  • ApplicationContextAware

这几个接口都继承至Aware,Aware类的接口都有以下特点:

  • (1)该接口是一个标记接口
  • (2)如果某个bean实现了该接口,一般会有一个BeanPostProcessor类对其进行处理
  • (3)具体方法的定义由实现了该接口的子接口进行定义,但是通常该子接口应该只包含一个方法,且该方法的返回值为void,参数只有一个。

2.1.4 BeanFactory后置处理阶段 —— postProcessBeanFactory

这里没有做任何处理。

但如果想对BeanFactory进行扩展,可以通过如下2种方式

  1. 子类重写AbstractApplicationContext#postProcessBeanFactory方法
  2. 实现BeanFactoryPostProcessor接口

2.1.5 调用所有 BeanFactoryPostProcessor —— invokeBeanFactoryPostProcessors

本方法会实例化和调用所有 BeanFactoryPostProcessor(包括其子类 BeanDefinitionRegistryPostProcessor)。

BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。

BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,主要用来在常规的 BeanFactoryPostProcessor 检测开始之前注册其他 bean 定义。特别是,你可以通过 BeanDefinitionRegistryPostProcessor 来注册一些常规的 BeanFactoryPostProcessor,因为此时所有常规的 BeanFactoryPostProcessor 都还没开始被处理。 (这边的 “常规 BeanFactoryPostProcessor” 主要用来跟 BeanDefinitionRegistryPostProcessor 区分。)

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

         //1.判断beanFactory是否为BeanDefinitionRegistry,beanFactory为DefaultListableBeanFactory,
    // 而DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,因此这边为true 
		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					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.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			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.
			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.
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			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!
		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();
	}

前面说过在容器初始化的过程中,往容器中注入了一个BeanFactoryPostProcessor接口的实现类即ConfigurationClassPostProcessor。

ConfigurationClassPostProcessor是一个非常重要的BeanFactoryPostProcessor,通过@Bean、@Component、@ComponentScan、@Import、@ImportResource注入Bean的方式都由这个类来处理。

回调BeanFactoryPostProcessor接口的相关方法的排序规则,一方面是提高可扩展性,另外一方面是有些实现类的调用优先级必须要高一点,不然会有问题。

(1)getBeanFactoryPostProcessors

public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
    return this.beanFactoryPostProcessors;
}

拿到当前应用上下文中已经注册的 BeanFactoryPostProcessor,在默认情况下,this.beanFactoryPostProcessors 是返回空的。

(2)invokeBeanDefinitionRegistryPostProcessors

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();

		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// Return immediately if no @Configuration classes were found
		if (configCandidates.isEmpty()) {
			return;
		}

		// Sort by previously determined @Order value, if applicable
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		// Detect any custom bean name generation strategy supplied through the enclosing application context
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry) {
			sbr = (SingletonBeanRegistry) registry;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		// Parse each @Configuration class
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			parser.parse(candidates);
			parser.validate();

			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			configClasses.removeAll(alreadyParsed);

			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			candidates.clear();
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
				Set<String> alreadyParsedClasses = new HashSet<>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				for (String candidateName : newCandidateNames) {
					if (!oldCandidateNames.contains(candidateName)) {
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());

		// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}

		if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
			// Clear cache in externally provided MetadataReaderFactory; this is a no-op
			// for a shared cache since it'll be cleared by the ApplicationContext.
			((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
		}
	}

processConfigBeanDefinitions(registry);这个方法很长,但实际主要就是干了下面几件事:

  1. 找到开发人员传入主配置类
  2. 创建一个配置类解析器对象
  3. 解析我们的配置类 parser.parse(candidates);
  4. 把解析出来的配置类注册到容器中 this.reader.loadBeanDefinitions(configClasses);

打个断点你就知道了:

我们测试的时候只有在AopOneConfig上加了@Configuration注解,因此这里的configCandidates里面只有AopOneConfig的bean定义。

 checkConfigurationClassCandidate用来判断bean是否为@Configuration注解修饰的配置类:

public static boolean checkConfigurationClassCandidate(
			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

		String className = beanDef.getBeanClassName();
		if (className == null || beanDef.getFactoryMethodName() != null) {
			return false;
		}

		AnnotationMetadata metadata;
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
			// Can reuse the pre-parsed metadata from the given BeanDefinition...
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			// Check already loaded Class if present...
			// since we possibly can't even load the class file for this Class.
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			metadata = new StandardAnnotationMetadata(beanClass, true);
		}
		else {
			try {
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				metadata = metadataReader.getAnnotationMetadata();
			}
			catch (IOException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Could not find class file for introspecting configuration annotations: " +
							className, ex);
				}
				return false;
			}
		}

		if (isFullConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		else if (isLiteConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			return false;
		}

		// It's a full or lite configuration candidate... Let's determine the order value, if any.
		Integer order = getOrder(metadata);
		if (order != null) {
			beanDef.setAttribute(ORDER_ATTRIBUTE, order);
		}

		return true;
	}

1.获取类名,如果类名不存在则返回false
2.获得AnnotationMetadata

  • 如果BeanDefinition 是 AnnotatedBeanDefinition的实例,并且className 和 BeanDefinition中的元数据的类名相同,则直接从BeanDefinition 获得Metadata
  • 如果BeanDefinition 是 AnnotatedBeanDefinition的实例,并且beanDef 有 beanClass属性存在,则实例化StandardAnnotationMetadata
  • 否则 通过MetadataReaderFactory 中的MetadataReader 进行读取

3.进行判断

  • 如果存在Configuration 注解,则为BeanDefinition 设置configurationClass属性为full.
  • 如果AnnotationMetadata 中有Component,ComponentScan,Import,ImportResource 注解中的任意一个,或者存在 被@bean 注解的方法,则返回true.
  • 否则,返回false

4.如果该类被@Order所注解,则设置order属性为@Order的值
5.返回true.

(3)invokeBeanFactoryPostProcessors

@Configuration注解修饰的类Spring会为其生成代理类,比如我们例子的 AopOneConfig 类,

上面的代码中Spring为其创建了CGLIB代理对象,目的是为了解决@Bean单例问题。为什么这么说呢?看下面的例子:

如果方法P在调用方法A,若不生成代理对象,此时会创建两次P对象。创建两次对象,即在spring里非单例对象,这样的话无法保证spring中配置类的属性单例原则。

通过代理方法来管理p对象的创建,如果调用方法p()会交由代理去判断person对象是否已经被创建成功,如果是那么则交由代理对象的proxy.invokeSuper的方法调用父类去创建;如果没有则通过代理类$BeanFactory.getBean的方法创建对象p,从而保证对象只被创建一次,即为单例。

需要了解上面的spring创建代理对象的过程。 

2.1.6 BeanFactory注册BeanPostProcessor阶段 —— registerBeanPostProcessors

invokeBeanFactoryPostProcessors 方法主要用于处理 BeanFactoryPostProcessor 接口,而 registerBeanPostProcessors 方法主要用于处理 BeanPostProcessor 接口。BeanFactoryPostProcessor 和 BeanPostProcessor,相信大家很容易从命名看出来这两个接口“长得很像”。BeanFactoryPostProcessor 是针对 BeanFactory 的扩展,主要用在 bean 实例化之前,读取 bean 的定义,并可以修改它。BeanPostProcessor 是针对 bean 的扩展,主要用在 bean 实例化之后,执行初始化方法前后,允许开发者对 bean 实例进行修改。

本方法会注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。

BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。在 registerBeanPostProcessors 方法只是注册到 BeanFactory 中,具体调用是在 bean 初始化的时候。

public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, register the BeanPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// Finally, re-register all internal BeanPostProcessors.
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}
  1. 找出所有实现BeanPostProcessor接口的类
  2. 添加BeanPostProcessorChecker(主要用于记录信息)到beanFactory中
  3. 定义不同的变量用于区分: 实现PriorityOrdered接口的BeanPostProcessor、实现Ordered接口的BeanPostProcessor、普通BeanPostProcessor

以上将 PostProcessor 添加到 BeanFactory 中的 beanPostProcessors 缓存。而 hasInstantiationAwareBeanPostProcessors 和 hasDestructionAwareBeanPostProcessors 变量用于指示 beanFactory 是否已注册过 InstantiationAwareBeanPostProcessors 和 DestructionAwareBeanPostProcessor,在之后的 IoC 创建过程会用到这两个变量

2.1.6 初始化内建Bean —— MessageSource

 国际化相关的内容,不用太关注。

2.1.7 初始化内建Bean:Spring事件广播器 —— initApplicationEventMulticaster

先判断有没有自定义的ApplicationEventMulticaster,没有的话就注册一个,即new 一个SimpleApplicationEventMulticaster,用来发布事件。

spring里面的事件、监听详细参考:https://blog.csdn.net/weixin_41231928

2.1.8 Spring应用上下文刷新阶段 —— onRefresh

模板方法,留给子类扩展用的。

2.1.9 Spring事件监听器注册阶段 —— registerListeners

  1. 添加当前应用上下文所关联的ApplicationListener对象
  2. 添加BeanFactory所注册的ApplicationListener
  3. 广播早期Spring事件

2.1.10 BeanFactory初始化完成阶段 —— finishBeanFactoryInitialization

  1. conversionService如果存在的话,设置到beanFactory
  2. 如果beanFactory之前没有注册嵌入值解析器,则注册默认的嵌入值解析器:主要用于注解属性值的解析。
  3. 依赖查找LoadTimeWeaverAware Bean
  4. beanFactory将ClassLoader临时设置为null
  5. beanFactory冻结配置
  6. beanFactory初始化非延迟单例Beans

1、beanFactory.addEmbeddedValueResolver

主要是添加 StringValueResolver。

2、beanFactory.freezeConfiguration()

冻结所有bean定义,注册的bean定义不会被修改或进一步后处理,因为马上要创建 Bean 实例对象了。

3、beanFactory.preInstantiateSingletons()

实例化所有剩余(非懒加载)单例对象 

    @Override
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

1、getMergedLocalBeanDefinition(beanName)

MergedBeanDefinition用来表示 “合并的 bean 定义”。之所以称之为 “合并的”,是因为存在 “子定义” 和 “父定义” 的情况。对于一个 bean 定义来说,可能存在以下几种情况:

  1. 该 BeanDefinition 存在 “父定义”:首先使用 “父定义” 的参数构建一个 RootBeanDefinition,然后再使用该 BeanDefinition 的参数来进行覆盖。
  2. 该 BeanDefinition 不存在 “父定义”,并且该 BeanDefinition 的类型是 RootBeanDefinition:直接返回该 RootBeanDefinition 的一个克隆。
  3. 该 BeanDefinition 不存在 “父定义”,但是该 BeanDefinition 的类型不是 RootBeanDefinition:使用该 BeanDefinition 的参数构建一个 RootBeanDefinition。

因为通常 BeanDefinition 在之前加载到 BeanFactory 中的时候,通常是被封装成 GenericBeanDefinition 或 ScannedGenericBeanDefinition,但是从这边之后 bean 的后续流程处理都是针对 RootBeanDefinition,因此在这边会统一将 BeanDefinition 转换成 RootBeanDefinition。 

通常会是上面的第3种情况。

如果使用 XML 配置来注册 bean,则该 bean 定义会被封装成:GenericBeanDefinition;

如果我们使用注解的方式来注册 bean,也就是@Compoment,则该 bean 定义会被封装成 ScannedGenericBeanDefinition。

protected RootBeanDefinition getMergedBeanDefinition(
			String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
			throws BeanDefinitionStoreException {

		synchronized (this.mergedBeanDefinitions) {
			RootBeanDefinition mbd = null;

			// Check with full lock now in order to enforce the same merged instance.
			if (containingBd == null) {
				mbd = this.mergedBeanDefinitions.get(beanName);
			}

			if (mbd == null) {
				if (bd.getParentName() == null) {
					// Use copy of given root bean definition.
					if (bd instanceof RootBeanDefinition) {
						mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
					}
					else {
						mbd = new RootBeanDefinition(bd);
					}
				}
				else {
					// Child bean definition: needs to be merged with parent.
					BeanDefinition pbd;
					try {
						String parentBeanName = transformedBeanName(bd.getParentName());
						if (!beanName.equals(parentBeanName)) {
							pbd = getMergedBeanDefinition(parentBeanName);
						}
						else {
							BeanFactory parent = getParentBeanFactory();
							if (parent instanceof ConfigurableBeanFactory) {
								pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
							}
							else {
								throw new NoSuchBeanDefinitionException(parentBeanName,
										"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
										"': cannot be resolved without an AbstractBeanFactory parent");
							}
						}
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
								"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
					}
					// Deep copy with overridden values.
					mbd = new RootBeanDefinition(pbd);
					mbd.overrideFrom(bd);
				}

				// Set default singleton scope, if not configured before.
				if (!StringUtils.hasLength(mbd.getScope())) {
					mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
				}

				// A bean contained in a non-singleton bean cannot be a singleton itself.
				// Let's correct this on the fly here, since this might be the result of
				// parent-child merging for the outer bean, in which case the original inner bean
				// definition will not have inherited the merged outer bean's singleton status.
				if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
					mbd.setScope(containingBd.getScope());
				}

				// Cache the merged bean definition for the time being
				// (it might still get re-merged later on in order to pick up metadata changes)
				if (containingBd == null && isCacheBeanMetadata()) {
					this.mergedBeanDefinitions.put(beanName, mbd);
				}
			}
			return mbd;
		}
	}

String parentBeanName = transformedBeanName(bd.getParentName()); 获取父定义的beanName

pbd = getMergedBeanDefinition(parentBeanName);获取父定义的 MergedBeanDefinition

mbd = new RootBeanDefinition(pbd);和mbd.overrideFrom(bd);就是合并操作,也就是我们之前一直说的 MergedBeanDefinition 的由来。

2、transformedBeanName

将 name 真正解析成真正的 beanName,主要是去掉 FactoryBean 里的 “&” 前缀,和解析别名。
什么是FactoryBean会在本文后面的补充里来详细说明。

3、isFactoryBean

判断这个bean是否实现了FactoryBean接口,即是否是FactoryBean。

  • 1.拿到真正的beanName(去掉&前缀、解析别名)
  • 2.尝试从缓存获取Bean实例对象
  • 3.beanInstance存在,则直接判断类型是否为FactoryBean
  • 4.如果beanInstance为null,并且beanName在单例对象缓存中,则代表beanName对应的单例对象为空对象,返回false
  • 5.如果缓存中不存在此beanName && 父beanFactory是ConfigurableBeanFactory,则调用父BeanFactory判断是否为FactoryBean
  • 6.通过MergedBeanDefinition来检查beanName对应的Bean是否为FactoryBean

4、getSingleton

  • 1.从单例对象缓存中获取beanName对应的单例对象
  • 2.如果单例对象缓存中没有,并且该beanName对应的单例bean正在创建中
  • 3.从早期单例对象缓存中获取单例对象(早期单例对象,是因为earlySingletonObjects里的对象都是通过提前曝光的ObjectFactory创建出来的,还未进行属性填充等操作)
  • 4.如果在早期单例对象缓存中也没有,并且允许创建早期单例对象引用
  • 5.从单例工厂缓存中获取beanName的单例工厂
  • 6.如果存在单例对象工厂,则通过工厂创建一个单例对象
  • 7.将通过单例对象工厂创建的单例对象,放到早期单例对象缓存中
  • 8.移除该beanName对应的单例对象工厂,因为该单例工厂已经创建了一个实例对象,并且放到earlySingletonObjects缓存了, // 因此,后续获取beanName的单例对象,可以通过earlySingletonObjects缓存拿到,不需要在用到该单例工厂

这段代码之所以重要,是因为该段代码是 Spring 解决循环引用的一部分代码(还有一部分是实例化bean的时候)。

解决循环引用逻辑:使用构造函数创建一个 “不完整” 的 bean 实例(之所以说不完整,是因为此时该 bean 实例还未初始化),并且提前曝光该 bean 实例的 ObjectFactory(提前曝光就是将 ObjectFactory 放到 singletonFactories 缓存),通过 ObjectFactory 我们可以拿到该 bean 实例的引用,如果出现循环引用,我们可以通过缓存中的 ObjectFactory 来拿到 bean 实例,从而避免出现循环引用导致的死循环。这边通过缓存中的 ObjectFactory 拿到的 bean 实例虽然拿到的是 “不完整” 的 bean 实例,但是由于是单例,所以后续初始化完成后,该 bean 实例的引用地址并不会变,所以最终我们看到的还是完整 bean 实例。会有一篇文章专门介绍spring是如何解决循环依赖的。

2.1.11 Spring应用上下文启动完成阶段 —— finishRefresh

  1. 清除ResoureLoader缓存
  2. 初始化lifecycleProcessor对象
  3. 调用lifecycleProcessor#onRefresh方法
  4. 发布应用上下文刷新事件 ContextRefreshedEvent
  5. 向MBeanServer托管Live Beans

1.清除ResoureLoader缓存 

比如context 级别的资源缓存,比如 ASM 的元数据。

2.initLifecycleProcessor()

初始化所有的 LifecycleProcessor。

在 Spring 中还提供了 Lifecycle 接口, Lifecycle 中包含 start/stop 方法,实现此接口后 Spring 会保证在启动的时候调用其 start 方法开始生命周期, 并在 Spring 关闭的时候调用 stop 方法来结束生命周期,通常用来配置后台程序,在启动后一直运行(如对 MQ 进行轮询等)。ApplicationContext 的初始化最后正是保证了这一功能的实现。

protected void initLifecycleProcessor() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        // 判断BeanFactory是否已经存在生命周期处理器
		if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
        // 存在则直接赋值
			this.lifecycleProcessor =
					beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
			}
		}
        // 不存在,新建DefaultLifecycleProcessor
		else {
			DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
			defaultProcessor.setBeanFactory(beanFactory);
			this.lifecycleProcessor = defaultProcessor;
			beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
						"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
			}
		}
	}

看下Lifecycle接口:

public interface Lifecycle {
 
	void start();
 
	void stop();
	
	boolean isRunning();
}

 LifecycleProcessor:负责管理ApplicationContext生命周期。是ApplicationContext很重要的一环。onRefresh与onClose是比较重要的方法,onRefresh作用是容器启动成功,onClose是只应用要关闭的时候。

 

3. getLifecycleProcessor().onRefresh();

private void startBeans(boolean autoStartupOnly) {
        // 获取所有实现了Lifecycle接口的Bean,如果采用了factroyBean的方式配置了一个LifecycleBean,那么factroyBean本身也要实现Lifecycle接口
        // 配置为懒加载的LifecycleBean必须实现SmartLifeCycle才能被调用start方法
		Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
        // key:如果实现了SmartLifeCycle,则为其getPhase方法返回的值,如果只是实现了Lifecycle,则返回0
        // value:相同phase的Lifecycle的集合,并将其封装到了一个LifecycleGroup中
		Map<Integer, LifecycleGroup> phases = new HashMap<>();
		lifecycleBeans.forEach((beanName, bean) -> {
             // 我们可以看到autoStartupOnly这个变量在上层传递过来的
             // 这个参数意味着是否只启动“自动”的Bean,这是什么意思呢?就是说,不需要手动调用容器的start方法
             // 从这里可以看出,实现了SmartLifecycle接口的类并且其isAutoStartup如果返回true的话,会在容器启动过程中自动调用,而仅仅实现了Lifecycle接口的类并不会被调用。
             // 如果我们去阅读容器的start方法的会发现,当调用链到达这个方法时,autoStartupOnly这个变量写死的为false
			if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
                // 获取这个Bean执行的阶段,实际上就是调用SmartLifecycle中的getPhase方法
                // 如果没有实现SmartLifecycle,而是单纯的实现了Lifecycle,那么直接返回0
				int phase = getPhase(bean);
                // 下面就是一个填充Map的操作,有的话add,没有的话直接new一个
				LifecycleGroup group = phases.get(phase);
				if (group == null) {
                    // LifecycleGroup构造函数需要四个参数
                    // phase:代表这一组lifecycleBeans的执行阶段
                    // timeoutPerShutdownPhase:因为lifecycleBean中的stop方法可以在另一个线程中运行,所以为了确保当前阶段的所有lifecycleBean都执行完,Spring使用了CountDownLatch,而为了防止无休止的等待下去,所有这里设置了一个等待的最大时间,默认为30秒
                    // lifecycleBeans:所有的实现了Lifecycle的Bean
                    // autoStartupOnly: 手动调用容器的start方法时,为false。容器启动阶段自动调用时为true,详细的含义在上面解释过了    
					group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
					phases.put(phase, group);
				}
				group.add(beanName, bean);
			}
		});
		if (!phases.isEmpty()) {
			List<Integer> keys = new ArrayList<>(phases.keySet());
			Collections.sort(keys);
			for (Integer key : keys) {
                // 获取每个阶段下所有的lifecycleBean,然后调用其start方法
				phases.get(key).start();
			}
		}
	}

跟踪代码可以发现,start方法最终调用到了doStart方法,其代码如下:

private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
    Lifecycle bean = lifecycleBeans.remove(beanName);
    if (bean != null && bean != this) {
        // 获取这个Bean依赖的其它Bean,在启动时先启动其依赖的Bean
        String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
        for (String dependency : dependenciesForBean) {
            doStart(lifecycleBeans, dependency, autoStartupOnly);
        }
        if (!bean.isRunning() &&
            (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {
            try {
                bean.start();
            }
            catch (Throwable ex) {
                throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);
            }
        }
    }
}

获取这个Bean依赖的其它Bean,在启动时先启动其依赖的Bean。

上面是启动容器阶段,那停止阶段呢?本文下面的补充会有说明。

4. publishEvent(new ContextRefreshedEvent(this));

广播ContextRefreshedEvent事件,通过事件广播器ApplicationEventMulticaster向所有监听了ContextRefreshedEvent事件的监听器进行通知。 

5. LiveBeansView.registerApplicationContext(this)

如果设置了JMX相关的属性,向MBeanServer注册LiveBeansView,可以通过JMX来监控此ApplicationContext。

ok,至此容器就已经全部加载启动完毕,进入工作状态!

补充一、ApplicationContext和BeanFactory有哪些区别?

  1. BeanFactory是一个最基础的IOC容器,提供了依赖查找,依赖注入等基础的功能
  2. ApplicationContext继承了BeanFactory,在BeanFactory的基础上增加了企业级的功能,如AOP,资源管理(Resources)事件(Event),国际化(i18n),Environment抽象等

因此当我们启动的容器是BeanFactory时,只能注入BeanNameAware,BeanClassLoaderAware,BeanFactoryAware接口的实现,其他接口的实现它并没有。当我们启动的容器是ApplicationContext时,对这些接口进行了实现,此时才能注入进来。这也是上面属性赋值的 Bean Aware接口回调阶段 Aware接口的回调是分开一次调用的原因。

补充二、Spring什么时候实例化bean?

首先要分2种情况:

 第一:如果使用BeanFactory作为Spring Bean的工厂类,则所有的bean都是在第一次使用该Bean的时候实例化

 第二:如果使用ApplicationContext作为Spring Bean的工厂类,则又分为以下几种情况:
       (1):如果bean的scope是singleton的,并且lazy-init为false(默认是false,所以可以不用设置),则ApplicationContext启动的时候就实例化该Bean,并且将实例化的Bean放在一个map结构的缓存中,下次再使用该Bean的时候,直接从这个缓存中取
       (2):如果bean的scope是singleton的,并且lazy-init为true,则该Bean的实例化是在第一次使用该Bean的时候进行实例化
       (3):如果bean的scope是prototype的,则该Bean的实例化是在第一次使用该Bean的时候进行实例化

补充三、BeanNameAware接口有啥用?

作用:让Bean获取或设置自己在BeanFactory配置中的名字(根据情况是id或者name)。

实现:通过实现BeanNameAware接口,接口中就一个方法setBeanName()

public class LogginBean implements BeanNameAware {
   private String beanName = null;
   public void setBeanName(String beanName) {
     this.beanName = beanName;
   }
}

在程序中使用 BeanFactory.getBean(String beanName) 或者 applicationContext.getBean(beanName)之前,Bean的名字就已经设定好了。所以,程序中可以尽情的使用BeanName而不用担心它没有被初始化。

举个例子:

(1)定义两个User类,一个实现BeanNameAware,一个不实现。

public class User implements BeanNameAware{
    private String id;
    private String name;
    private String address;

    public void setBeanName(String beanName) {
        //ID保存BeanName的值
        id=beanName;
    }
}
public class User implements BeanNameAware{
    private String id;
    private String name;
    private String address;
}

(2)在Spring配置文件中初始化两个对象。

    <bean id="zhangsan"  class="com.github.jettyrun.springinterface.demo.aware.beannameaware.User">
        <property name="name" value="zhangsan"></property>
        <property name="address" value="火星"></property>
    </bean>
    <bean id="lisi"  class="com.github.jettyrun.springinterface.demo.aware.beannameaware.User2">
        <property name="name" value="lisi"></property>
        <property name="address" value="木星"></property>
    </bean>

(3)main方法测试

 public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application-beanaware.xml");
        User user=context.getBean(User.class);
        System.out.println(String.format("实现了BeanNameAware接口的信息BeanId=%s,所有信息=%s",user.getId(),user.toString()));
        User2 user2=context.getBean(User2.class);
        System.out.println(String.format("未实现BeanNameAware接口的信息BeanId=%s,所有信息=%s",user2.getId(),user2.toString()));
    }
实现了BeanNameAware接口的信息BeanId=zhangsan,所有信息=User{id='zhangsan', name='zhangsan', address='火星'}
未实现BeanNameAware接口的信息BeanId=null,所有信息=User{id='null', name='lisi', address='木星'}

能够看到,我们在实现了BeanNameAware的User中,获取到了Spring容器中的BeanId(对应Spring配置文件中的Id属性),而没有实现BeanNameAware的User2,则不能获取到Spring容器中的Id属性。

所以BeanNameAware接口是为了让自身Bean能够感知到,获取到自身在Spring容器中的id属性。

同理,其他的Aware接口也是为了能够感知到自身的一些属性。比如实现了ApplicationContextAware 接口的类,能够获取到ApplicationContext,实现了BeanFactoryAware接口的类,能够获取到BeanFactory对象。

补充四、BeanFactoryAware接口有啥用?

作用:让Bean获取配置他们的BeanFactory的引用,即让bean知道自己是在哪个工厂(BeanFactory的引用)中。让Bean获取配置他们的BeanFactory的引用。

实现:实现BeanFactoryAware接口,其中只有一个方法即setFactory(BeanFactory factory)。使用上与BeanNameAware接口无异,只不过BeanFactoryAware注入的是个工厂,BeanNameAware注入的是个Bean的名字。

public class ZhangSan implements BeanFactoryAware {
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanFactoryAware的setBeanFactory");
    }
}

 让bean获取配置自己的工厂之后,当然可以在Bean中使用这个工厂的getBean()方法,但是,实际上非常不推荐这样做,因为结果是进一步加大Bean与Spring的耦合,而且,能通过DI注入进来的尽量通过DI来注入。当然,除了查找bean,BeanFactory可以提供大量其他的功能,例如销毁singleton模式的Bean。

通过这个方法的参数创建它的BeanFactory实例,实现了BeanFactoryAware接口,就可以让Bean拥有访问Spring容器的能力。缺点:导致代码与spring的api耦合在一起。

补充五、为什么要去获取这个ApplicationContext对象?

获取到了我们能干什么呢?答:能手动从Spring获取所需要的bean。

// 获取bean 方法1
public static <T>T getBean(String beanName){
	return (T) applicationContext.getBean(beanName);
}
 
// 获取bean 方法2
public static <T> T getBean(Class<T> c){
	return (T) applicationContext.getBean(c);
}
 

我们一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文(本身也是个BeanFactory)。如果说BeanFactory是Sping的心脏,那么ApplicationContext就是完整的身躯了。Spring的核心是容器,而容器并不唯一,框架本身就提供了很多个容器的实现,大概分为两种类型:

  1. 一种是不常用的BeanFactory,这是最简单的容器,只能提供基本的DI功能;
  2. 一种就是继承了BeanFactory后派生而来的ApplicationContext(应用上下文),它能提供更多企业级的服务,例如解析配置文本信息等等,这也是ApplicationContext实例对象最常见的应用场景。

ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。在BeanFactory中,很多功能需要以编程的方式实现,而在ApplicationContext中则可以通过配置的方式实现。ApplicationContext 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,比如,从属性文件从解析文本信息和将事件传递给所指定的监听器。

补充六、ignoreDependencyInterface 和 ignoreDependencyType 的含义? 

ignoreDependencyInterface 和 ignoreDependencyType 这两个到底该怎么理解?

/**
* Ignore the given dependency interface for autowiring.
* 忽略给定依赖接口的自动装配 
* @see org.springframework.context.ApplicationContextAware
*/
void ignoreDependencyInterface(Class<?> ifc);
​
/**
* Ignore the given dependency type for autowiring:
* 忽略给定依赖类型的自动装配
* @param type the dependency type to ignore
*/
void ignoreDependencyType(Class<?> type);

来操作下就好理解了,准备五个model,作为实验注入Spring容器中的实例对象,如下:

    public class User {
    }
    //这个接口类用来测试ignoreDependencyInterface方法,看能否注入User
    public interface UserAware {
        void setUser(User user);
    }
    //这个用来测试ignoreDependencyType方法
    public class Admin {
    }
    //这个就是和上面的做对比,不对它做任何处理
    public class Role {
    }
    //这个就是和上面的做对比,不对它做任何处理
    public class Role {
    }
 //实现了上面的UserAware接口并实现setUser方法,
 //并且将User、Admin、Role属性注入
 public class Person implements UserAware{
    private User user;
    private Admin admin;
    private Role role;
​
    public User getUser() {
        return user;
    }

    //实现了UserAwre接口的setUser方法
    @Override
    public void setUser(User user) {
        this.user = user;
    }
​
    public Admin getAdmin() {
        return admin;
    }
    public void setAdmin(Admin admin) {
        this.admin = admin;
    }
​
    public Role getRole() {
        return role;
    }
    public void setRole(Role role) {
        this.role = role;
    }
}

​​其中User、Admin、Role都是空的实例对象,UserAware是个接口,里面有一个setUser(User user)方法,Person类中有User、Admin、Role三个对象属性,并且实现了UserAwre接口和它的方法,然后对所有的属性添加get、set方法。其中注意,Person中的setUser是复写了UserAware接口中的setUser方法。

配置spring注入属性的xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd"
       default-autowire="byType">
    <!--这个default-autowire作者测试的时候并不会影响到测试结果,我们后面分析-->
​
    <bean id = "user" class="ignore.model.User"></bean>
    <bean id = "role" class="ignore.model.Role"></bean>
    <bean id = "admin" class="ignore.model.Admin"></bean>
    <bean id="person" class="ignore.model.Person"></bean>
</beans>
    @Test
    public void testSimpleLoad(){
​
        XmlBeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("ignore/beanFactoryTest.xml"));
        //beanFactory.ignoreDependencyInterface(UserAware.class);//测试ignoreDependencyInterface方法作用
        //beanFactory.ignoreDependencyType(Admin.class);//测试ignoreDependencyType方法作用
        Person person = beanFactory.getBean("person", Person.class);
        System.out.println("person"+person);
    }

测试步骤: 

  1. 先测试不开启ignoreDependencyInterface方法和ignoreDependency方法的时候,获取person中的属性值有些哪些?
  2. 测试开启上面代码第五行,启动ignoreDependencyInterface(UserAware.class)方法后,获取person中的属性值有哪些?
  3. 测试关闭上面第五行,开启上面代码第六行,启动ignoreDependency(Admin.class)方法后,获取person中的属性值有哪些?
  4. 测试同时启用ignoreDependencyInterface方法和ignoreDependency方法后,获取的person中的属性值有哪些?
  5. 上面4的测试是依赖xml配置中default-autowire="byType"测试的,我们把它改成default-autowire="byName"后在测试一次第4条,结果又如何?

【1】先测试不开启ignoreDependencyInterface方法和ignoreDependency方法的时候,获取person中的属性值有些哪些?运行结果截图如下:

person中的三个属性值都能获取到。 

【2】 测试只开启ignoreDependencyInterface(UserAware.class)方法后,运行结果如下图:

person对象中的user属性值为空,说明user属性值在开启了ignoreDependencyInterface(UserAware.class)方法后并不能自动装配到person中(注意,user只是不能自动注入到person对象中,Spring容器中依然有user实例),到这里我们可以得到一个小结论:ignoreDependencyInterface方法是忽略指定接口(UserAwre)的set方法的自动装配!

【3】只开启ignoreDependency(Admin.class)方法,运行结果如下图:

【4】同时开启ignoreDependency和ignoreDependencyInterface方法,运行截图如下:​

【5】修改xml配置文件中的default-autowire="byType",修改为default-autowire="byName",然后在开启ignoreDependency和ignoreDependencyInterface方法的同时运行的结果截图如下:​​​

通过运行结果我们可以分析出:ignoreDependency和ignoreDependencyInterface方法的忽略自动装配和自动绑定方式无关!

可以得出一下结论:

  1. ignoreDependencyInterface方法忽略指定依赖接口的自动装配指的是忽略接口中的set方法这样的自动装配方式
  2. ignoreDependency忽略指定依赖类型的自动装配指的是忽
  3. 以上两种忽略方式都和自动装配(自动绑定)的方式无关.

补充七、FactoryBean是什么?和普通bean的区别?和beanfactory区别?

FactoryBean 是一种特殊的 bean,它是个工厂 bean,可以自己创建 bean 实例,如果一个类实现了 FactoryBean 接口,则该类可以自己定义创建实例对象的方法,只需要实现它的 getObject() 方法。很多中间件都利用 FactoryBean 来进行扩展。

1. FactoryBean和普通bean的区别:

一般情况下,Spring 通过反射机制利用 bean 的 class 属性指定实现类来实例化 bean。不像FactoryBean,通过实现它的 getObject() 方法来创建bean。

“FactoryBean” 和 “FactoryBean 创建的 bean 实例”是两个概念。为了区别,Spring 使用了“&” 前缀来表示FactoryBean。

例如:beanName 为 apple,则 getBean(“apple”) 获得的是 AppleFactoryBean 通过 getObject() 方法创建的 bean 实例;而 getBean("&apple") 获得的是 AppleFactoryBean 本身。

2. Factorybean和Beanfactory区别:

Beanfactory是一个接口,它是Spring中工厂的顶层规范,是SpringIoc容器的核心接口,它定义了getBean()containsBean()等管理Bean的通用方法。

Spring的容器都是它的具体实现如:

  • DefaultListableBeanFactory

  • XmlBeanFactory

  • ApplicationContext

这些实现类又从不同的维度分别有不同的扩展。

FactoryBean首先它是一个Bean,但又不仅仅是一个Bean。它是一个能生产对象生成的工厂Bean,类似于设计模式中的工厂模式和装饰器。

public interface FactoryBean<T> {

	//从工厂中获取bean
	@Nullable
	T getObject() throws Exception;

	//获取Bean工厂创建的对象的类型
	@Nullable
	Class<?> getObjectType();

	//Bean工厂创建的对象是否是单例模式
	default boolean isSingleton() {
		return true;
	}
}

从它定义的接口可以看出,FactoryBean表现的是一个工厂的职责。 即一个Bean A如果实现了FactoryBean接口,那么A就变成了一个工厂,根据A的名称获取到的实际上是工厂调用getObject()返回的对象,而不是A本身,如果要获取工厂A自身的实例,那么需要在名称前面加上'&'符号。

  • getObject('name')返回工厂中的实例
  • getObject('&name')返回工厂本身的实例

通常情况下,bean 无须自己实现工厂模式,Spring 容器担任了工厂的 角色;但少数情况下,容器中的 bean 本身就是工厂,作用是产生其他 bean 实例。由工厂 bean 产生的其他 bean 实例,不再由 Spring 容器产生,因此与普通 bean 的配置不同,不再需要提供 class 元素。

示例:

定义一个Bean实现FactoryBean接口。

@Component
public class MyBean implements FactoryBean {
    private String message;
    public MyBean() {
        this.message = "通过构造方法初始化实例,即我是一个FactoryBean实例,不是普通的bean";
    }
    @Override
    public Object getObject() throws Exception {
        // 这里并不一定要返回MyBean自身的实例,可以是其他任何对象的实例。
        //如return new Student()...
        return new MyBean("通过FactoryBean.getObject()创建实例");
    }
    @Override
    public Class<?> getObjectType() {
        return MyBean.class;
    }
    public String getMessage() {
        return message;
    }
}

MyBean实现了FactoryBean接口的两个方法,getObject()是可以返回任何对象的实例的,这里测试就返回MyBean自身实例,且返回前给message字段赋值。同时在构造方法中也为message赋值。然后测试代码中先通过名称获取Bean实例,打印message的内容,再通过&+名称获取实例并打印message内容。

    @Test
    public void test() {
        MyBean myBean1 = (MyBean) context.getBean("myBean");
        System.out.println("myBean1 = " + myBean1.getMessage());
        MyBean myBean2 = (MyBean) context.getBean("&myBean");
        System.out.println("myBean2 = " + myBean2.getMessage());
        System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));
    }
myBean1 = 通过FactoryBean.getObject()初始化实例
myBean2 = 通过构造方法初始化实例,即我是一个FactoryBean实例,不是普通的bean
myBean1.equals(myBean2) = false

使用场景:

FactoryBean在Spring中最为典型的一个应用就是用来创建AOP的代理对象

这个对象,是我们在运行时创建的,而不是一开始就定义好的,这很符合工厂方法模式。更形象地说,AOP代理对象通过Java的反射机制,在运行时创建了一个代理对象,在代理对象的目标方法中根据业务要求织入了相应的方法。这个对象在Spring中就是——ProxyFactoryBean

所以,FactoryBean为我们实例化Bean提供了一个更为灵活的方式,我们可以通过FactoryBean创建出更为复杂的Bean实例。

综上:

  • 两个都是个工厂,但FactoryBean本质上还是一个Bean,也归BeanFactory管理
  • BeanFactory是Spring容器的顶层接口,FactoryBean更类似于用户自定义的工厂接口。

补充八、容器的生命周期中,停止容器如何进行的?

 停止容器有两种办法,一种时显式的调用容器的stop或者close方法,如下:

public static void main(String[] args) {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
    ac.register(LifeCycleConfig.class);
    ac.refresh();
    ac.stop();
    //		ac.close();
}

另外一个中是注册一个JVM退出时的钩子,如下:

public static void main(String[] args) {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
    ac.register(LifeCycleConfig.class);
    // 当main函数运行完成后,会调用容器doClose方法
    ac.registerShutdownHook();
    ac.refresh();
}

不论是上面哪一种方法,最终都会调用到DefaultLifecycleProcessoronClose方法,代码如下:

public void onClose() {
    // 传递所有的停止信号到Bean
    stopBeans();
    // 跟启动阶段一样,因为它本身是一个实现了Lifecycle接口的Bean,所有需要更改它的运行标志
    this.running = false;
}
private void stopBeans() {
    // 获取容器中所有的实现了Lifecycle接口的Bean
    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
    Map<Integer, LifecycleGroup> phases = new HashMap<>();
    lifecycleBeans.forEach((beanName, bean) -> {
        int shutdownPhase = getPhase(bean);
        LifecycleGroup group = phases.get(shutdownPhase);
        if (group == null) {
            group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false);
            phases.put(shutdownPhase, group);
        }
        // 同一阶段的Bean放到一起
        group.add(beanName, bean);
    });
    if (!phases.isEmpty()) {
        List<Integer> keys = new ArrayList<>(phases.keySet());
        // 跟start阶段不同的是,这里采用的是降序
        // 也就是阶段越后的Bean,越先stop
        keys.sort(Collections.reverseOrder());
        for (Integer key : keys) {
            phases.get(key).stop();
        }
    }
}
public void stop() {
    if (this.members.isEmpty()) {
        return;
    }
    this.members.sort(Collections.reverseOrder());
    
    // 创建了一个CountDownLatch,需要等待的线程数量为当前阶段的所有ifecycleBean的数量
    CountDownLatch latch = new CountDownLatch(this.smartMemberCount);
    
    // stop方法可以异步执行,这里保存的是还没有执行完的lifecycleBean的名称
    Set<String> countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet<>());
    
    // 所有lifecycleBeans的名字集合
    Set<String> lifecycleBeanNames = new HashSet<>(this.lifecycleBeans.keySet());
    for (LifecycleGroupMember member : this.members) {
        if (lifecycleBeanNames.contains(member.name)) {
            doStop(this.lifecycleBeans, member.name, latch, countDownBeanNames);
        }
        else if (member.bean instanceof SmartLifecycle) {
            // 按理说,这段代码永远不会执行,可能是版本遗留的代码没有进行删除
            // 大家可以自行对比4.x的代码跟5.x的代码
            latch.countDown();
        }
    }
    try {
        // 最大等待时间30s,超时进行日志打印
        latch.await(this.timeout, TimeUnit.MILLISECONDS);
        if (latch.getCount() > 0 && !countDownBeanNames.isEmpty() && logger.isInfoEnabled()) {
            logger.info("Failed to shut down " + countDownBeanNames.size() + " bean" +
                        (countDownBeanNames.size() > 1 ? "s" : "") + " with phase value " +
                        this.phase + " within timeout of " + this.timeout + ": " + countDownBeanNames);
        }
    }
    catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
    }
}
}
private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,
                    final CountDownLatch latch, final Set<String> countDownBeanNames) {
	
    Lifecycle bean = lifecycleBeans.remove(beanName);
    if (bean != null) {
        // 获取这个Bean所被依赖的Bean,先对这些Bean进行stop操作
        String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);
        for (String dependentBean : dependentBeans) {
            doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames);
        }
        try {
            if (bean.isRunning()) {
                if (bean instanceof SmartLifecycle) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Asking bean '" + beanName + "' of type [" +
                                     bean.getClass().getName() + "] to stop");
                    }
                    countDownBeanNames.add(beanName);
                    
                    // 还记得到SmartLifecycle中的stop方法吗?里面接受了一个Runnable参数
                    // 就是在这里地方传进去的。主要就是进行一个操作latch.countDown(),标记当前的lifeCycleBean的stop方法执行完成
                    ((SmartLifecycle) bean).stop(() -> {
                        latch.countDown();
                        countDownBeanNames.remove(beanName);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Bean '" + beanName + "' completed its stop procedure");
                        }
                    });
                }
                else {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Stopping bean '" + beanName + "' of type [" +
                                     bean.getClass().getName() + "]");
                    }
                    bean.stop();
                    if (logger.isDebugEnabled()) {
                        logger.debug("Successfully stopped bean '" + beanName + "'");
                    }
                }
            }
            else if (bean instanceof SmartLifecycle) {
                // Don't wait for beans that aren't running...
                latch.countDown();
            }
        }
        catch (Throwable ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Failed to stop bean '" + beanName + "'", ex);
            }
        }
    }
}

整个stop方法跟start方法相比,逻辑上并没有很大的区别,除了执行时顺序相反外。

  • start方法,先找出这个Bean的所有依赖,然后先启动这个Bean的依赖
  • stop方法,先找出哪些Bean依赖了当前的Bean,然后停止这些被依赖的Bean,之后再停止当前的Bean

补充九、Spring中单例Bean是线程安全的吗?

对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。

对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。

如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。

有状态对象(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。

无状态对象(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean 的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean 并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。

对于有状态的bean,Spring官方提供的bean,一般提供了通过ThreadLocal去解决线程安全的方法,比如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等。

Spring框架并没有对单例Bean进行任何多线程的封装处理。关于单例Bean的线程安全和并发问题需要开发者自行搞定。但实际上,大部分Spring Bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说,Spring的单例Bean是线程安全的。如果你的Bean有多种状态(比如View Model对象),就需要自行保证线程安全。

最浅显的解决办法就是将多态Bean的作用域由“singleton”变更为“prototype”。

posted @ 2022-06-25 14:02  沙滩de流沙  阅读(2869)  评论(0编辑  收藏  举报

关注「Java视界」公众号,获取更多技术干货