【Spring】spring启动流程+bean生命周期+spring循环依赖解决
(1)spring初始化流程
【入口流程图:AnnotationConfigApplicationContext】 因为是基于 java-config 技术分析源码,所以这里的入口是 AnnotationConfigApplicationContext ,如果是使用 xml 分析,那么入口即为 ClassPathXmlApplicationContext ,它们俩的共同特征便是都继承了 AbstractApplicationContext 类,而大名鼎鼎的 refresh 方法便是在这个类中定义的。
我们接着分析 AnnotationConfigApplicationContext 类,可以绘制成如下流程图:
【思考问题:如果让你去设计一个IOC容器,会怎么做?】 (1)给用户提供一个入口:AnnotationConfigApplicationContext (2)想要生成bean对象,那就需要一个beanFactory工厂(DefaultListableBeanFactory) (3)如果我想对加了特定注解(如 @Service、@Repository)的类进行读取转化成 BeanDefinition 对象(BeanDefinition 是 Spring 中极其重要的一个概念,它存储了 bean 对象的所有特征信息,如是否单例,是否懒加载,factoryBeanName 等),那么就需要一个注解配置读取器(AnnotatedBeanDefinitionReader); (4)如果我想对用户指定的包目录进行扫描查找 bean 对象,那么还需要一个路径扫描器(ClassPathBeanDefinitionScanner)。
(2)启动流程核心代码分析
(1)org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors
代码运行到这里时候,Spring 容器已经构造完毕,那么就可以为容器添加一些内置组件了,其中最主要的组件便是 ConfigurationClassPostProcessor 和 AutowiredAnnotationBeanPostProcessor ,前者是一个 beanFactory 后置处理器,用来完成 bean 的扫描与注入工作,后者是一个 bean 后置处理器,用来完成 @AutoWired 自动注入。
(2)org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean
这个步骤主要是用来解析用户传入的 Spring 配置类,其实也是解析成一个 BeanDefinition 然后注册到容器中。
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(instanceSupplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
(3)容器刷新流程
(1)分析
我们知道了如何去初始化一个 IOC 容器,那么接下来就是让这个 IOC 容器真正起作用的时候了:即先扫描出要放入容器的 bean,将其包装成 BeanDefinition 对象,然后通过反射创建 bean,并完成赋值操作,这个就是 IOC 容器最简单的功能了。但是看完上图,明显 Spring 的初始化过程比这个多的多,下面我们就详细分析一下这样设计的意图:
如果用户想在扫描完 bean 之后做一些自定义的操作:假设容器中包含了 a 和 b,那么就动态向容器中注入 c,不满足就注入 d,这种骚操作 Spring 也是支持的,得益于它提供的 BeanFactoryPostProcessor 后置处理器,对应的是上图中的 invokeBeanFactoryPostProcessors 操作。
如果用户还想在 bean 的初始化前后做一些操作呢?比如生成代理对象,修改对象属性等,Spring 为我们提供了 BeanPostProcessor 后置处理器,实际上 Spring 容器中的大多数功能都是通过 Bean 后置处理器完成的,Spring 也是给我们提供了添加入口,对应的是上图中的 registerBeanPostProcessors 操作。
整个容器创建过程中,如果用户想监听容器启动、刷新等事件,根据这些事件做一些自定义的操作呢?Spring 也早已为我们考虑到了,提供了添加监听器接口和容器事件通知接口,对应的是上图中的 registerListeners 操作。
(2)org.springframework.context.support.AbstractApplicationContext#refresh
这个方法是对上图中的具体代码实现,可划分为12个步骤,其中比较重要的步骤下面会有详细说明。
在这里,我们需要记住:Spring 中的每一个容器都会调用 refresh 方法进行刷新,无论是 Spring 的父子容器,还是 Spring Cloud Feign 中的 feign 隔离容器,每一个容器都会调用这个方法完成初始化。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
...
}
}
(3)org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory
顾名思义,这个接口是为 beanFactory 工厂添加一些内置组件,预处理过程。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
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.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
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());
}
}
(4)org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
Spring 在扫描完所有的 bean 转成 BeanDefinition 时候,我们是可以做一些自定义操作的,这得益于 Spring 为我们提供的 BeanFactoryPostProcessor 接口。
其中 BeanFactoryPostProcessor 又有一个子接口 BeanDefinitionRegistryPostProcessor ,前者会把 ConfigurableListableBeanFactory 暴露给我们使用,后者会把 BeanDefinitionRegistry 注册器暴露给我们使用,一旦获取到注册器,我们就可以按需注入了,例如搞定这种需求:假设容器中包含了 a 和 b,那么就动态向容器中注入 c,不满足就注入 d。
熟悉 Spring 的同学都知道,Spring 中的同类型组件是允许我们控制顺序的,比如在 AOP 中我们常用的 @Order 注解,这里的 BeanFactoryPostProcessor 接口当然也是提供了顺序,最先被执行的是实现了 PriorityOrdered 接口的实现类,然后再到实现了 Ordered 接口的实现类,最后就是剩下来的常规 BeanFactoryPostProcessor 类。
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet<>();
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);
}
}
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
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();
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();
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();
}
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
}
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);
}
}
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
beanFactory.clearMetadataCache();
}
(5)org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors
这一步是向容器中注入 BeanPostProcessor ,注意这里仅仅是向容器中注入而非使用。参考上面的步骤和下面的代码,读者自行分析即可,应该不是很困难。
关于 BeanPostProcessor ,它的作用在后续 Spring 创建 bean 流程文章里我会详细分析一下,当然不可能分析全部的 BeanPostProcessor 组件,那样可能得写好几篇续文,这里我们只需要简单明白这个组件会干预 Spring 初始化 bean 的流程,从而完成代理、自动注入、循环依赖等各种功能。
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
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);
}
}
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
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);
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);
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
(6)org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster
前文我们说到,在整个容器创建过程中,Spring 会发布很多容器事件,如容器启动、刷新、关闭等,这个功能的实现得益于这里的 ApplicationEventMulticaster 广播器组件,通过它来派发事件通知。
在这里 Spring 也为我们提供了扩展,SimpleApplicationEventMulticaster 默认是同步的,如果我们想改成异步的,只需要在容器里自定义一个 name 为 applicationEventMulticaster 的容器即可,类似的思想在后续的 Spring Boot 中会有更多的体现。
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
(7)org.springframework.context.support.AbstractApplicationContext#registerListeners
如果用户想监听容器事件,那么就必须按照规范实现 ApplicationListener 接口并放入到容器中,在这里会被 Spring 扫描到,添加到 ApplicationEventMulticaster 广播器里,以后就可以发布事件通知,对应的 Listener 就会收到消息进行处理。
protected void registerListeners() {
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
(8)org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
在上面的步骤中,Spring 的大多数组件都已经初始化完毕了,剩下来的这个步骤就是初始化所有剩余的单实例 bean,在 Spring 中初始化一个 bean 对象是非常复杂的,如循环依赖、bean 后置处理器运用、aop 代理等,这里我们只需要明白 Spring 是通过这个方法把容器中的 bean 都初始化完毕即可。
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
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);
}
}
}
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();
}
}
}
}
(9)org.springframework.context.support.AbstractApplicationContext#finishRefresh
整个容器初始化完毕之后,会在这里进行一些扫尾工作,如清理缓存,初始化生命周期处理器,发布容器刷新事件等。
protected void finishRefresh() {
clearResourceCaches();
initLifecycleProcessor();
getLifecycleProcessor().onRefresh();
publishEvent(new ContextRefreshedEvent(this));
LiveBeansView.registerApplicationContext(this);
}
(4)spring启动流程小总结
1、Bean: Spring作为一个IoC容器,最重要的当然是Bean咯
2、BeanFactory: 生产与管理Bean的工厂
3、BeanDefinition: Bean的定义,也就是我们方案中的Class,Spring对它进行了封装
4、BeanDefinitionRegistry: 类似于Bean与BeanFactory的关系,BeanDefinitionRegistry用于管理BeanDefinition
5、BeanDefinitionRegistryPostProcessor: 用于在解析配置类时的处理器,类似于我们方案中的ClassProcessor
6、BeanFactoryPostProcessor: BeanDefinitionRegistryPostProcessor父类,让我们可以再解析配置类之后进行后置处理
7、BeanPostProcessor: Bean的后置处理器,用于在生产Bean的过程中进行一些处理,比如依赖注入,类似我们的AutowiredAnnotationBeanProcessor
8、ApplicationContext: 如果说以上的角色都是在工厂中生产Bean的工人,那么ApplicationContext就是我们Spring的门面,ApplicationContext与BeanFactory是一种组合的关系,所以它完全扩展了BeanFactory的功能,并在其基础上添加了更多特定于企业的功能,比如我们熟知的ApplicationListener(事件监听器)
(5)spring容器bean的生命周期
在IoC容器启动之后,并不会马上就实例化相应的bean,此时容器仅仅拥有所有对象的BeanDefinition(BeanDefinition:是容器依赖某些工具加载的XML配置信息进行解析和分析,并将分析后的信息编组为相应的BeanDefinition)。只有当getBean()调用时才是有可能触发Bean实例化阶段的活动
(1)自定义测试代码
@Component
public class A implements SmartLifecycle {
private boolean running;
@Override
public void start() {
System.out.println("SmartLifecycle start...");
this.running = true;
}
@Override
public void stop() {
System.out.println("SmartLifecycle stop...");
}
@Override
public boolean isRunning() {
System.out.println("SmartLifecycle isRunning...");
return this.running;
}
}
public class B implements InitializingBean {
@PostConstruct
public void postConstruct() {
System.out.println("PostConstruct ...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet ...");
}
public void init() {
System.out.println("init method ...");
}
@PreDestroy
public void preDestroy() {
System.out.println("PreDestroy ...");
}
public void destroy() {
System.out.println("destroy method ...");
}
}
@Component
@EnableAsync
public class C {
@Async
public void print() {
for (int i = 0; i < 10; i++) {
System.out.println("test ...");
}
}
}
@Configuration
@ComponentScan("com.francis.test")
public class JavaConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public B b() {
return new B();
}
@Bean
public TaskExecutor taskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(JavaConfig.class);
applicationContext.getBean(C.class).print();
System.out.println("在调用 com.francis.test.C.print() 之前打印这句话说明异步生效,否则是同步");
applicationContext.close();
}
}
(2)演示流程图
(3)再看测试代码
package ioc;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class CustomerBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("【步骤10】执行BeanPostProcessor中postProcessBeforeInitialization方法,beanName=" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("【步骤14】执行BeanPostProcessor的postProcessAfterInitialization方法,beanName=" + beanName);
return bean;
}
}
package ioc;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.*;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Arrays;
public class IocBeanLifeService implements InitializingBean,DisposableBean,ApplicationContextAware,
ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware,
BeanNameAware, EnvironmentAware, ImportAware, ResourceLoaderAware{
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("【步骤2】执行Bean的set方法,设置name属性值:" + name);
this.name = name;
}
public void setSex(String sex) {
System.out.println("【步骤2】执行Bean的set方法,设置sex属性值:" + sex);
this.sex = sex;
}
@Override
public String toString() {
return "IocBeanLifeService{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
public IocBeanLifeService(){
System.out.println("【步骤1】执行Bean的无参构造函数");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("【步骤12】执行InitializingBean的afterPropertiesSet方法");
}
@Override
public void destroy() throws Exception {
System.out.println("【步骤16】执行DisposableBean接口的destroy方法");
}
public void destroyMethod() throws Exception {
System.out.println("【步骤17】执行配置的destroy-method");
}
public void initMethod() throws Exception {
System.out.println("【步骤13】执行配置的init-method");
}
@PostConstruct
public void initPostConstruct(){
System.out.println("【步骤11】执行PostConstruct注解标注的方法");
}
@PreDestroy
public void preDestroy(){
System.out.println("【步骤15】执行preDestroy注解标注的方法");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("【步骤4】执行BeanClassLoaderAware中setBeanClassLoader,ClassLoader的name = " + classLoader.getClass().getName());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("【步骤5】执行BeanFactoryAware中setBeanFactory,beanFactory中是否包含IocBeanLifeService:" + beanFactory.containsBean("iocBeanLifeService"));
}
@Override
public void setBeanName(String s) {
System.out.println("【步骤3】执行BeanNameAware中setBeanName方法,beanName值:"
+ s);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("【步骤9】执行ApplicationContextAware的setApplicationContext方法,Bean Definition Names="
+ Arrays.toString(applicationContext.getBeanDefinitionNames()));
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
System.out.println("【步骤8】执行ApplicationEventPublisherAware中setApplicationEventPublisher方法");
}
@Override
public void setEnvironment(Environment environment) {
System.out.println("【步骤6】执行EnvironmentAware的setEnvironment方法");
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
Resource resource = resourceLoader.getResource("classpath:applicationContext.xml");
System.out.println("【步骤7】执行ResourceLoaderAware的setResourceLoader方法,Resource File Name="
+ resource.getFilename());
}
@Override
public void setImportMetadata(AnnotationMetadata annotationMetadata) {
System.out.println("执行setImportMetadata");
}
}
package test;
import ioc.IocBeanLifeService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeTest {
@Test
public void test(){
System.out.println("Spring容器初始化===========================");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("Spring容器初始化完毕========================");
System.out.println("从容器中获取Bean");
IocBeanLifeService service = context.getBean("iocBeanLifeService", IocBeanLifeService.class);
System.out.println(service.toString());
System.out.println("Spring容器准备关闭==========================");
context.close();
System.out.println("Spring容器完成关闭===========================");
}
}
(4)测试结果演示
Spring容器初始化===========================
五月 16, 2020 3:18:44 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@13b6d03: startup date [Sat May 16 15:18:44 CST 2020]; root of context hierarchy
五月 16, 2020 3:18:45 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
【步骤1】执行Bean的无参构造函数
【步骤2】执行Bean的set方法,设置name属性值:coolsummermoon
【步骤2】执行Bean的set方法,设置sex属性值:man
【步骤3】执行BeanNameAware中setBeanName方法,beanName值:iocBeanLifeService
【步骤4】执行BeanClassLoaderAware中setBeanClassLoader,ClassLoader的name = sun.misc.Launcher$AppClassLoader
【步骤5】执行BeanFactoryAware中setBeanFactory,beanFactory中是否包含IocBeanLifeService:true
【步骤6】执行EnvironmentAware的setEnvironment方法
【步骤7】执行ResourceLoaderAware的setResourceLoader方法,Resource File Name=applicationContext.xml
【步骤8】执行ApplicationEventPublisherAware中setApplicationEventPublisher方法
【步骤9】执行ApplicationContextAware的setApplicationContext方法,Bean Definition Names=[iocBeanLifeService, org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
【步骤10】执行BeanPostProcessor中postProcessBeforeInitialization方法,beanName=iocBeanLifeService
【步骤11】执行PostConstruct注解标注的方法
【步骤12】执行InitializingBean的afterPropertiesSet方法
【步骤13】执行配置的init-method
【步骤14】执行BeanPostProcessor的postProcessAfterInitialization方法,beanName=iocBeanLifeService
五月 16, 2020 3:18:45 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@13b6d03: startup date [Sat May 16 15:18:44 CST 2020]; root of context hierarchy
Spring容器初始化完毕========================
从容器中获取Bean
IocBeanLifeService{name='coolsummermoon', sex='man'}
Spring容器准备关闭==========================
【步骤15】执行preDestroy注解标注的方法
【步骤16】执行DisposableBean接口的destroy方法
【步骤17】执行配置的destroy-method
Spring容器完成关闭===========================
Process finished with exit code 0
可以简述为以下九步 (1)实例化bean对象(通过构造方法或者工厂方法) (2)设置对象属性(setter等)(依赖注入) (3)如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。(和下面的一条均属于检查Aware接口) (4)如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身 (5)将Bean实例传递给Bean的前置处理器的postProcessBeforeInitialization(Object bean, String beanname)方法 (6)调用Bean的初始化方法 (7)将Bean实例传递给Bean的后置处理器的postProcessAfterInitialization(Object bean, String beanname)方法 (8)使用Bean (9)容器关闭之前,调用Bean的销毁方法
(5)测试结果分析
(1)上面的结果,我们可以初步分四个阶段: 1、Bean的实例化阶段 2、Bean的设置属性阶段 3、Bean的 初始化阶段 4、Bean的销毁阶段
(2)在初始化阶段,有个特别重要的接口BeanPostProcessor,在初始化前、后调用: (3)在设置属性阶段后,postProcessBeforeInitialization方法执行前,会执行很多Aware类型的接口,这种类型接口作用是加载资源到Spring容器中,Aware前面的名字就对应哪种资源,依次加载的是: BeanNameAware BeanClassLoaderAware BeanFactoryAware EnvironmentAware ResourceLoaderAware ApplicationEventPublisherAware ApplicationContextAware
看到这里应该明白BeanFactory和ApplicationContext的区别了: BeanFactoryAware之前加载的资源都是公共的。BeanFactoryAware后面加载的资源都是ApplicationContext独有的。
(4)初始化方式有三个,分别是: InitializingBean的afterPropertiesSet方法 PostConstruct注解标注的方法 配置的init-method
上面的三个方法效果都是一样的,开发中选择其中一种方式就行,一般我们选择2、3方法中的一个。
(5)容器销毁的方式有三个,分别是: preDestroy注解标注的方法 DisposableBean接口的destroy方法 配置的destroy-method 上面的三个方法效果都是一样的,开发中选择其中一种方式就行,一般我们选择1、3方法中的一个。
(6)baen生命周期总结
Bean容器找到Spring配置文件中Bean的定义; Bean容器利用java 反射机制实例化Bean; Bean容器为实例化的Bean设置属性值; 如果Bean实现了BeanNameAware接口,则执行setBeanName方法; 如果Bean实现了BeanClassLoaderAware接口,则执行setBeanClassLoader方法; 如果Bean实现了BeanFactoryAware接口,则执行setBeanFactory方法; 如果 ……真的,到这我经常忘记,但前面三个Aware接口肯定能记住; 如果Bean实现了ApplicationContextAware接口,则执行setApplicationContext方法; 如果加载了BeanPostProcessor相关实现类,则执行postProcessBeforeInitialization方法; 如果Bean定义初始化方法(PostConstruct注解、配置init-method、实现了InitializingBean接口),则执行定义的初始化方法; 如果加载了BeanPostProcessor相关实现类,则执行postProcessAfterInitialization方法; 当要销毁这个Bean时,如果自定义了销毁方法(PreDestroy注解、配置destroy-method、实现了DisposableBean接口),则执行定义的销毁方法。
(7)spring循环依赖问题和解决方案
(1)什么是循环依赖
所谓Spring的循环依赖,指的是这样一种场景:
当我们注入一个对象A时,需要注入对象A中标记了某些注解的属性,这些属性也就是对象A的依赖,把对象A中的依赖都初始化完成,对象A才算是创建成功。那么,如果对象A中有个属性是对象B,而且对象B中有个属性是对象A,那么对象A和对象B就算是循环依赖,如果不加处理,就会出现:创建对象A–>处理A的依赖B–>创建对象B–>处理B的对象A–>创建对象A–>处理A的依赖B–>创建对象B…这样无限的循环下去。
(2)Spring处理循环依赖的基本思路
虽说要初始化一个Bean,必须要注入Bean里的依赖,才算初始化成功,但并不要求此时依赖的依赖也都注入成功,只要依赖对象的构造方法执行完了,这个依赖对象就算存在了,注入就算成功了,至于依赖的依赖,以后再初始化也来得及(参考Java的内存模型)。
因此,我们初始化一个Bean时,先调用Bean的构造方法,这个对象就在内存中存在了(对象里面的依赖还没有被注入),然后把这个对象保存下来,当循环依赖产生时,直接拿到之前保存的对象,于是循环依赖就被终止了,依赖注入也就顺利完成了。
举个例子:
假设对象A中有属性是对象B,对象B中也有属性是对象A,即A和B循环依赖。 创建对象A,调用A的构造,并把A保存下来。 然后准备注入对象A中的依赖,发现对象A依赖对象B,那么开始创建对象B。 调用B的构造,并把B保存下来。 然后准备注入B的构造,发现B依赖对象A,对象A之前已经创建了,直接获取A并把A注入B(注意此时的对象A还没有完全注入成功,对象A中的对象B还没有注入),于是B创建成功。 把创建成功的B注入A,于是A也创建成功了。 于是循环依赖就被解决了。
(3)从源码的角度分析
在注入一个对象的过程中,调用了这样一个方法:
Object sharedInstance = this.getSingleton(beanName);
这段代码在AbstractBeanFactory类的doGetBean()方法中。 这里得到的Object就是试图是要创建的对象,beanName就是要创建的对象的类名,这里getSingleton()方法的代码如下:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
这个方法是Spring解决循环依赖的关键方法,在这个方法中,使用了三层列表来查询的方式,这三层列表分别是:
singletonObjects earlySingletonObjects singletonFactories
这个方法中用到的几个判断逻辑,体现了Spring解决循环依赖的思路,不过实际上对象被放入这三层的顺序是和方法查询的循序相反的,也就是说,在循环依赖出现时,对象往往会先进入singletonFactories,然后earlySingletonObjects,然后singletonObjects。
下面看一下这个方法的代码逻辑: 1-方法首先从singletonObjects中获取对象,当Spring准备新建一个对象时,singletonObjects列表中是没有这个对象的,然后进入下一步。
Object singletonObject = this.singletonObjects.get(beanName);
2-除了判断null之外,有一个isSingletonCurrentlyInCreation的判断,实际上当Spring初始化了一个依赖注入的对象,但还没注入对象属性的时候,Spring会把这个bean加入singletonsCurrentlyInCreation这个set中,也就是把这个对象标记为正在创建的状态,这样,如果Spring发现要创建的bean在singletonObjects中没有,但在singletonsCurrentlyInCreation中有,基本上就可以认定为循环依赖了(在创建bean的过程中发现又要创建这个bean,说明bean的某个依赖又依赖了这个bean,即循环依赖)。
举个例子:对象A和对象B循环依赖,那么初始化对象A之后(执行了构造方法),要把A放入singletonsCurrentlyInCreation,对象A依赖了对象B,那么就要再初始化对象B,如果这个对象B又依赖了对象A,也就是形成了循环依赖,那么当我们注入对象B中的属性A时,进入这个代码逻辑,就会发现,我们要注入的对象A已经在singletonsCurrentlyInCreation中了,后面的逻辑就该处理这种循环依赖了。
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName))
3-这里引入了earlySingletonObjects列表,这是个为了循环依赖而存在的列表,从名字就可以看到,是个预创建的对象列表,刚刚创建的对象在这个列表里一般也没有。
singletonObject = this.earlySingletonObjects.get(beanName);
4-earlySingletonObjects也没有则从singletonFactories中获取,前面说到singletonFactories是对象保存的第一步,实际上对象初始化后,可能还没有注入对象的依赖,就把对象放入了这个列表。
如果是循环依赖,此时的singletonFactories中一般是会存在目标对象的,举个例子:对象A和对象B循环依赖,那么初始化了对象A(执行了构造方法),还没有注入对象A的依赖时,就会把A放入singletonFactories,然后开始注入A的依赖,发现A依赖B,那么需要构对象B,构造过程也是执行了B的构造后就把B放到singletonFactories,然后开始注入B的依赖,发现B依赖A,在第二步中提到,此时A已经在singletonsCurrentlyInCreation列表里了,所以会进入此段代码逻辑,而且此时时对象A在singletonFactories中确实存在,因为这已经是第二次试图创建对象A了。
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
5-代码到这里基本已经确定我们要创建的这个对象已经发生循环依赖了,然后Spring进行了这样的操作,把这个对象加入到earlySingletonObjects中,然后把该对象从singletonFactories中删掉。
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
6-其实上面5步已经执行完了该方法的代码,这里加的第6步是为了解释循环依赖的结果。在这个方法的代码之后,会把bean完整的进行初始化和依赖的注入,在完成了bean的初始化后,后面代码逻辑中会调用一个这样的方法:
getSingleton(String beanName, ObjectFactory<?> singletonFactory)
这个方法中有个小小的子方法addSingleton(),他的代码是这样的:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
这个方法处理的是已经注入完依赖的bean,把bean放入singletonObjects中,并把bean从earlySingletonObjects和singletonFactories中删除,这个方法和上面分析的方法组成了Spring处理循环依赖的逻辑。
(8)spring三级缓存
(1)基本认识 Spring在启动过程中,使用到了三个map,称为三级缓存。 Spring启动过程大致如下: 1.创建beanFactory,加载配置文件 2.解析配置文件转化beanDefination,获取到bean的所有属性、依赖及初始化用到的各类处理器等 3.刷新beanFactory容器,初始化所有单例bean 4.注册所有的单例bean并返回可用的容器,一般为扩展的applicationContext
(2)一级缓存 在第三步中,所有单例的bean初始化完成后会存放在一个Map(singletonObjects)中,beanName为key,单例bean为value。
第三步单例bean的初始化过程大致如下: 0.标记bean为创建中 1.new出bean对象 2.如果支持循环依赖则生成三级缓存,可以提前暴露bean 3.填充bean属性,解决属性依赖 4.初始化bean,处理Aware接口并执行各类bean后处理器,执行初始化方法,如果需要生成aop代理对象 5.如果存在循环依赖,解决之 – 这里有点问题,这一步是如果之前解决了aop循环依赖,则缓存中放置了提前生成的代理对象,然后使用原始bean继续执行初始化,所以需要再返回最终bean前,把原始bean置换为代理对象返回。 6.此时bean已经可以被使用,进行bean注册(标记)并注册销毁方法。 7.将bean放入容器中(一级缓存),移除创建中标记及二三级缓存(后面再具体分析) (3)循环依赖及三级缓存 根据以上步骤可以看出bean初始化是一个相当复杂的过程,假如初始化A bean时,发现A bean依赖B bean,即A初始化执行到了第3步填充属性,需要注入B bean,此时B还没有初始化,则需要暂停A,先去初始化B,那么此时new出来的A对象放哪里,直接放在容器Map里显然不合适,半残品怎么能用,所以需要提供一个可以标记创建中bean(A)的Map,可以提前暴露正在创建的bean供其他bean依赖,而如果初始化A所依赖的bean B时,发现B也需要注入一个A的依赖(即发生循环依赖),则B可以从创建中的beanMap中直接获取A对象(创建中)注入A,然后完成B的初始化,返回给正在注入属性的A,最终A也完成初始化,皆大欢喜。
如果配置不允许循环依赖,则上述缓存就用不到了,A 依赖B,就是创建B,B依赖C就去创建C,创建完了逐级返回就行,所以,一级缓存之后的其他缓存(二三级缓存)就是为了解决循环依赖!而配置支持循环依赖后,就一定要解决循环依赖吗?肯定不是!循环依赖在实际应用中也有,但不会太多,简单的应用场景是: controller注入service,service注入mapper,只有复杂的业务,可能service互相引用,有可能出现循环依赖,所以为了出现循环依赖才去解决,不出现就不解决,虽然支持循环依赖,但是只有在出现循环依赖时才真正暴露早期对象,否则只暴露个获取bean的方法,并没有真正暴露bean,因为这个方法不会被执行到,这块的实现就是三级缓存(singletonFactories),只缓存了一个单例bean工厂。
这个bean工厂不仅可以暴露早期bean还可以暴露代理bean,如果存在aop代理,则依赖的应该是代理对象,而不是原始的bean。而暴露原始bean是在单例bean初始化的第2步,填充属性第3步,生成代理对象第4步,这就矛盾了,A依赖到B并去解决B依赖时,要去初始化B,然后B又回来依赖A,而此时A还没有执行代理的过程,所以,需要在填充属性前就生成A的代理并暴露出去,第2步时机就刚刚好。
三级缓存的bean工厂getObject方式,实际执行的是getEarlyBeanReference,如果对象需要被代理(存在beanPostProcessors -> SmartInstantiationAwareBeanPostProcessor),则提前生成代理对象。
(4)二级缓存 三级缓存已经解决所有问题了,二级缓存用来做什么呢?为什么三级缓存不直接叫做二级缓存?这个应该是在缓存使用时决定的: 三级缓存中提到出现循环依赖才去解决,也就是说出现循环依赖时,才会执行工厂的getObject生成(获取)早期依赖,这个时候就需要给它挪个窝了,因为真正暴露的不是工厂,而是对象,所以需要使用一个新的缓存保存暴露的早期对象(earlySingletonObjects),同时移除提前暴露的工厂,也不需要在多重循环依赖时每次去执行getObject(虽然个人觉得不会出问题,因为代理对象不会重复生成,详细可以了解下代理里面的逻辑,如wrapIfNecessary)。
(9)spring三级缓存总结
1.不支持循环依赖情况下,只有一级缓存生效,二三级缓存用不到 2.二三级缓存就是为了解决循环依赖,且之所以是二三级缓存而不是二级缓存,主要是可以解决循环依赖对象需要提前被aop代理,以及如果没有循环依赖,早期的bean也不会真正暴露,不用提前执行代理过程,也不用重复执行代理过程。
|