Spring @Bean实例的初始化
简介
我们都知道Spring有很多种创建bean的方式,包括使用@Component, @Service等注解,包括实现ImportSelector或ImportBeanDefinitionRegistrar接口,也可以调用AnnotationConfigApplicationContext#register手动注册bean,也可以在@Configuration类里定义bean。那么今天我们要说的就是在@Configuration配置类里@Bean实例化的原理。
首先来看下通常情况下在@Configuration类里配置@Bean的一个示例:
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public RedisCacheManager redisCacheManager(RedisTemplate<Object, Object> redisTemplate) {
RedisTemplate<Object, Object> newRedisTemplate = new RedisTemplate<>();
newRedisTemplate.setConnectionFactory(redisTemplate.getConnectionFactory());
RedisCacheManager redisCacheManager = new RedisCacheManager(newRedisTemplate);
redisCacheManager.setUsePrefix(true);
redisCacheManager.setDefaultExpiration(600);
return redisCacheManager;
}
}
在这里@Configuration注解即标记这个类是一个配置类,在Spring启动的时候会读取这个类里面的bean定义并生成实例。
那么它是在哪加载bean,又是在哪去实例化的呢?
SpringBoot启动流程简介
首先我们来梳理下SpringBoot的一个启动流程。
入口在主类的main方法中:
public static void main(String[] args) {
SpringApplication.run(Abc.class, args);
}
创建environment
然后到达SpringApplication#run方法
首先是创建environment实例,在这里会加载一些初始的配置以及该使用哪个profile
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
其次在prepareEnvironment方法中会切入Spring Cloud的context的初始化,并且为SpringApplication实例添加AncestorInitializer初始化器,这样在SpringBoot的context初始化的时候会把SpringCoud的context设置为自己的父容器。
那么具体是在哪衔接起来的呢?
原来在prepareEnvironment方法里会发布ApplicationEnvironmentPreparedEvent事件,而SpringCloud在启动时会加载一个监听器为BootstrapApplicationListener,在这里会进行SpringCloud context的初始化。
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 这里即是重点
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
在Spring-cloud-context的spring.factories文件中有这么一行,因此这个listener会被加载到容器中。
org.springframework.context.ApplicationListener=\
org.springframework.cloud.bootstrap.BootstrapApplicationListener
创建context
其次创建ApplicationContext,然后做一些基本的填充工作
context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
在创建ApplicationContext的时候就会加载一些Spring内置的bean,如及其重要的ConfigurationClassPostProcessor。
创建web application context的时候会创建的context类是org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext。
这个类的构造器如下
public AnnotationConfigEmbeddedWebApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
它会创建一个AnnotatedBeanDefinitionReader实例,这个类的构造器如下:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
最重要的就是最后一行,它会加载一些内置的类,最终调用的方法是registerAnnotationConfigProcessors,方法有点长,只贴出最重要的一行,在这里会注册bean ConfigurationClassPostProcessor,而这就是后面进行bean加载解析的基础。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, Object source) {
// ... 省略
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// ... 省略
}
加载主类
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 应用初始化器,如设置SpringCloud context为当前context父容器
applyInitializers(context);
// 获取主类并加载入registry
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
刷新context
准备完context后就会进行context的刷新
refreshContext(context);
其实刷新context主要分为两个步骤,一个是加载bean定义,一个是bean的实例化(除了懒加载的bean,否则都是提前实例化的)。那么我们这里为了突出重点,就按照@Bean注解标记的方法被加载到registry中这条主要路径来解析。
然后会进入到AbstractApplicationContext#refresh方法,随即进入invokeBeanFactoryPostProcessors方法。
public void refresh() throws BeansException, IllegalStateException {
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
}
最终会调用到方法PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, java.util.List<BeanFactoryPostProcessor> beanFactoryPostProcessors)
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<String>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// 在这里会调用到ConfigurationClassPostProcessor
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// 调用beanFactoryPostProcessor
}
因此,实际调用的是invokeBeanDefinitionRegistryPostProcessors
ConfigurationClassPostProcessor解析主类
这里会进入到方法ConfigurationClassPostProcessor#processConfigBeanDefinitions
首先会拿到配置类,因为之前加载了主类,而主类也是一个配置类,所以这里configCandidates里会有主类。
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));
}
}
然后创建Configuration类解析器,并进行解析,这里会加载所有的类路径下的类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
parser.parse(candidates);
对于每一个类都会创建ConfigurationClass对象,并且如果有@Bean标记的方法,则加入到ConfigurationClass的属性beanMethods中。
final class ConfigurationClass {
private final Set<BeanMethod> beanMethods = new LinkedHashSet<BeanMethod>();
}
然后通过ConfigurationClassBeanDefinitionReader来处理配置类,这里会把所有解析到的类都放到configClasses中并进行读取。
Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(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);
加载配置类的bean定义
下面就进入了Configuration类的bean定义读取
ConfigurationClassBeanDefinitionReader
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// 省略
// 这里是重点,处理配置类的@Bean标记的方法
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 省略
}
loadBeanDefinitionsForBeanMethod定义如下,这里会为每个@Bean注解标记的方法创建一个bean定义容器, 类型为ConfigurationClassBeanDefinition,并加入到注册表registry中。
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
// 对于每一个被@Bean标记的方法,创建ConfigurationClassBeanDefinition对象
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(methodName);
}
else {
// 走这条分支
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
// 省略部分代码
// 注册@Bean方法定义的bean
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
到此@Bean注解标记的类就被放入registry中了。
@Bean标记方法调用
那么调用初始化的流程是什么呢?
首先在我们都知道Bean实例化的时候调用AbstractBeanFactory#getBean方法。
注意,走到这里既可能是因为bean自己的提前实例化,也可能是因为被其他bean依赖从而实例化。
AbstractBeanFactory
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
AbstractBeanFactory
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// 省略..
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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 = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 省略..
}
然后调用createBean方法
AbstractAutowireCapableBeanFactory#createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
// 省略..
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 调用具体方法创建bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// ...
}
这里重点来了,记得上文设置bean的factoryMethod为Configuration类的对应方法吗,这里会反射调用,具体方法即为instantiateUsingFactoryMethod。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 走这里
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// ...
}
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
ConstructorResolver#instantiateUsingFactoryMethod
// 找到具体的方法factoryMethodToUse
Object beanInstance;
if (System.getSecurityManager() != null) {
final Object fb = factoryBean;
final Method factoryMethod = factoryMethodToUse;
final Object[] args = argsToUse;
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, beanFactory, fb, factoryMethod, args);
}
}, beanFactory.getAccessControlContext());
}
else {
// 走这里
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse);
}
if (beanInstance == null) {
return null;
}
bw.setBeanInstance(beanInstance);
return bw;
最终反射调用方法
SimpleInstantiationStrategy
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner,
Object factoryBean, final Method factoryMethod, Object... args) {
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
ReflectionUtils.makeAccessible(factoryMethod);
return null;
}
});
}
else {
ReflectionUtils.makeAccessible(factoryMethod);
}
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
try {
currentlyInvokedFactoryMethod.set(factoryMethod);
// 这里进行方法调用并返回
return factoryMethod.invoke(factoryBean, args);
}
finally {
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(factoryMethod,
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(factoryMethod,
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
}
catch (InvocationTargetException ex) {
String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
"declaring the factory method as static for independence from its containing instance. " + msg;
}
throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
}
}
那么到这里,完整的bean定义加载及实例化就完成了,后面会进行一些其他的Spring常规处理。