跳至主要內容

Spring Boot bean解析

向往大约 10 分钟Spring BootSpring Boot

Bean配置

配置bean可以通过Xml和注解进行配置,在本文暂不介绍Xml方式,只介绍注解方式,注解有以下几种方式配置Bean。

  • @Component声明,其他还有@Service 、@Repository

    @Component
    public class Teacher extends Person {
        
        @Override
        public String getProfessional() {
            return "teacher";
        }
    }
    
  • 配置类中使用@Bean

    @Configuration
    public class StudentConfig {
    
        @Bean
        public Person student() {
            return new Student();
        }
    }
    
    
  • 实现FactoryBean

    @Component
    public class MyWorker implements FactoryBean<Person> {
    
        @Override
        public Person getObject() throws Exception {
            return new Worker("worker");
        }
    
        @Override
        public Class<?> getObjectType() {
            return Person.class;
        }
    }
    
  • 实现BeanDefinitionRegistryPostProcessor

    @Component
    public class BeanRegister implements BeanDefinitionRegistryPostProcessor {
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
            rootBeanDefinition.setBeanClass(Salesman.class);
            beanDefinitionRegistry.registerBeanDefinition("salesMan", rootBeanDefinition);
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    
        }
    }
    
  • 实现ImpoprtBeanDefinitionRegister

    public class BeanImport implements ImportBeanDefinitionRegistrar {
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
            rootBeanDefinition.setBeanClass(Coder.class);
            registry.registerBeanDefinition("coder", rootBeanDefinition);
        }
    }
    

    在启动类加上:@Import(BeanImport.class)

Bean解析

Bean解析核心逻辑在org.springframework.context.support.AbstractApplicationContext#refresh方法中,该方法的核心流程如下图所示:

image-20230103225108995

prepareRefresh方法

prepareRefresh主要做了以下几个事情:

  • 容器状态设置,表明容器为active状态
  • 初始化属性设置
  • 检查必备属性是否存在

属性检查支持自定义,示例如下:

public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        environment.setRequiredProperties("xw.age");

    }
}

在初始化器中添加属性检查的逻辑,上述示例将在启动时检查xw.age属性是否存在,如果不存在,将抛出如下异常:

image-20230104111931193

prepareBeanFactory

prepareBeanFactory方法主要做了以下几个事情:

  • 设置beanFactory的一些属性
  • 添加后置处理器
  • 设置忽略的自动装配接口
  • 注册一些组件

postProcessBeanFactory

postProcessBeanFactory中主要用于子类重写在BeanFactory完成创建后做进一步设置l

invokeBeanFactoryPostProcessors

invokeBeanFactoryPostProcessors方法主要逻辑:

  • 调用BeanDefinitionRegistryPostProcessor实现向容器中添加Bean的定义,具体实现请参考上面

  • 调用BeanFactoryPostProcessor实现向容器内bean的定义添加属性,实现如下所示:

    @Component
    public class FirstBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
            Salesman salesman = configurableListableBeanFactory.getBean(Salesman.class);
            salesman.setAge(100);
        }
    }
    

    上述代码向salesman bean中设置了age属性,赋值为100。

initMessageSource

该方法主要逻辑是初始化国际化相关属性。

initApplicationEventMulticaster

改方法主要逻辑是初始事件广播器。

onRefresh

创建web容器。

registerListeners

将监听器事件监听器添加到广播器中。

finishBeanFactoryInitialization

初始化未初始化的单例bean实例,实例化的流程如下:

image-20230104170035854

doGetBean方法如下:

	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
    // 获取bean名称,如果是beanFactory对象在前面加上&标记
		String beanName = transformedBeanName(name);
		Object beanInstance;

		// Eagerly check singleton cache for manually registered singletons.
    // 从缓存获取单例bean
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
      //判断bean对象标记是否正在创建中,如果正在创建中则不应该继续下去,出现依赖循环就会出现这个错误
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			BeanFactory parentBeanFactory = getParentBeanFactory();
      // 检查父容器是否存在,尝试从父容器中获取	
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
					.tag("beanName", name);
			try {
				if (requiredType != null) {
					beanCreation.tag("beanType", requiredType::toString);
				}
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
          //bean 中@DependsOn信息,用于标记bean之间初始化顺序,优先创建@DependsOn中的bean
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						registerDependentBean(dep, beanName);
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.
        // 创建单例对象,并加入一级缓存
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
          //如果生成bean 是FactoryBean ,再获取真正的对象
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
        //作用域 = prototype,因为不会放入缓存中,每次获取都要重新创建
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
        // session request 这些作用域,由作用域容器去管理这些对象
				else {
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
					}
					Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new ScopeNotActiveException(beanName, scopeName, ex);
					}
				}
			}
			catch (BeansException ex) {
				beanCreation.tag("exception", ex.getClass().toString());
				beanCreation.tag("message", String.valueOf(ex.getMessage()));
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
			finally {
				beanCreation.end();
			}
		}
    // 返回初始化成功的对象
		return adaptBeanInstance(name, beanInstance, requiredType);
	}

上述方法整体流程如下:

  • 从三级缓存获取bean实例
  • 如果缓存中不存在,尝试从父容器中获取
  • 如果父容器中不存在,开始进入实例化阶段,获取RootBeanDefinition,优先加载@DependsOn上的bean
  • 调用 AbstractBeanFactory#createBean进行实例化,完成后加入一级缓存,并从二级缓存和三级缓存移除。

查看createBean方法:

	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      //通过BeanPostProcessors 增强返回一个代理对象,这个生成AOP的代理对象,使用多个BeanPostProcessors来处理
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
      // 对象实例化
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}	
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

进一步查看doCreateBean方法,主要流程为:

  • 初始化实例,创建对象完成,并且添加到3级缓存。第3级缓存常常用于存储代理对象,因为有些类需要动态代理方法,需要生成代理对象,会委派给第三级缓存方法ObjectFactroy去实现的,普通对象如果不需要会直接返回。
  • 对实例化bean进行属性注入
  • 执行初始化方法,DisposableBean接口加入到disposableBeans容器中

查看属性注入方法逻辑:

	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		if (bw == null) {
			if (mbd.hasPropertyValues()) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
			}
			else {
				// Skip property population phase for null instance.
				return;
			}
		}

		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
		// state of the bean before properties are set. This can be used, for example,
		// to support styles of field injection.
    // 判断是否支持注入
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					return;
				}
			}
		}

		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    //获取注入方式 根据名称注入、根据类型注入、构造器注入
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
        // 设置属性
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

bean的注入都是InstantiationAwareBeanPostProcessor 类进行处理的,该是BeanPostProcessor的子接口,该接口添加了实例化前回调,以及实例化后设置显式属性或自动装配之前的回调。方法如下:

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

  //在目标bean初始化前被调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,
  //所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,
  //后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走
	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

  // 在bean实例化之后(通过构造函数或工厂方法),但在Spring属性填充(从显式属性或自动装配)发生之前执行操作。
	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

  //对属性进行赋值
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}

  //对bean属性值赋值后调用,对属性值的修改。如果postProcessAfterInstantiation方法返回false,
  //该方法可能不会被调用。可以在该方法内对属性值进行修改
	@Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

		return pvs;
	}

}

InstantiationAwareBeanPostProcessor 接口实现类主要分3个

  1. ConfigurationClassPostProcessor:看类名就知道处理@Configuration实例化。
  2. CommonAnnotationBeanPostProcessor:实现JSR-250 注解、@Resource,@EJB、@WebServiceRef,@WebServiceContext,@PostConstrusct、@PreDestory这些注解实现。
  3. AutowiredAnnotationBeanPostProcessor:实现 @Autowired、@Value注入,并且支持JSR-330's @Inject注解注入的。

@Autowired和@Resource注解使用

bean的注入常用的有@Autowired注解和@Resource注解,区别如下:

@Autowired是根据类型进行注入,当有多个一样的类型时,可通过使用名称装配结合@Qualifier注解进行使用

@Resource有name和type两个属性,如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常,如果指定了name,则从上下文中查找名称匹配的bean进行装配,找不到则抛出异常,如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常。

finishRefresh

核心逻辑:

  • 初始化生命周期处理器
  • 调用生命周期处理器的onRfresh方法
  • 发布ContextRefreshedEvent事件
  • JMX相关处理

三级缓存

	/** Cache of singleton objects: bean name to bean instance. */
	//	一级缓存 用于存放完全可以使用单例bean,也就是初始化完成并且注入所有依赖
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name to ObjectFactory. */
	//二级缓存 过早暴露单例对象,此时bean刚刚完成初始化,未完成属性注入和执行 init 方法
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name to bean instance. */
	// 三级缓存  装载创建bean的工厂对象
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

三级缓存主要作用: 创建对象ObjectFactory首先放入三级换缓存中,当调用getObject 创建实例时,会将创建好对象加入二级缓存中,并且删除三级中缓存,当对象已经完成初始化方法和属性注入,再将缓存添加到一级缓存中,并且删除二级缓存。主要用来解决单例bean的循环依赖问题。