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常规处理。

猜你喜欢

转载自blog.csdn.net/adolph09/article/details/121566503