ToB企服应用市场:ToB评测及商务社交产业平台

标题: Spring Bean生命周期 [打印本页]

作者: 铁佛    时间: 2022-9-1 22:11
标题: Spring Bean生命周期
Spring Bean生命周期

本文基于图灵课堂周瑜老师的讲解整理,包括spring bean加载的过程,主要是扫描BeanDefinition以及初始化非懒加载单例Bean两部分,源码取自SpringFramework 5.3.22
1. Bean扫描

本小节介绍的是Spring从给定的扫描位置扫描到待加载的Bean,生成BeanDefinitionMap的过程
SpringBoot启动过程中使用的ApplicationContext是AnnotationConfigApplicationContext,而它初始化的时候会顺带初始化两个BeanDefinitionReader:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner,前者是可以直接通过给定的class注册Bean,后者则可以扫描给定目录下所有的目标Bean,下面着重介绍后者扫描Bean组件的过程。
ClassPathBeanDefinitionScanner扫描的入口是public int scan(String... basePackages),而真正做事情的是protected Set doScan(String... basePackages)方法,代码如下:
  1. /**<br>     * Perform a scan within the specified base packages,<br>     * returning the registered bean definitions.<br>     * <p>This method does <i>not</i> register an annotation config processor<br>     * but rather leaves this up to the caller.<br>     * @param basePackages the packages to check for annotated classes<br>     * @return set of beans registered if any for tooling registration purposes (never {@code null})<br>     */<br>protected Set<BeanDefinitionHolder> doScan(String... basePackages) {<br>        Assert.notEmpty(basePackages, "At least one base package must be specified");<br>        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();<br>        for (String basePackage : basePackages) {<br>            // 找到basePackage下的所有候选组件,这里只是把classname赋值给了BeanDefinition<br>            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);<br>            for (BeanDefinition candidate : candidates) {<br>                // 获取组件的scope,默认是单例的<br>                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);<br>                candidate.setScope(scopeMetadata.getScopeName());<br>                // 获取beanname<br>                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);<br>                if (candidate instanceof AbstractBeanDefinition) {<br>                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);<br>                }<br>                // 处理通用的注解<br>                if (candidate instanceof AnnotatedBeanDefinition) {<br>                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);<br>                }<br>                // 最后再对BeanDefinition做检查,看下是否有重名的<br>                if (checkCandidate(beanName, candidate)) {<br>                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);<br>                    definitionHolder =<br>                            AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);<br>                    beanDefinitions.add(definitionHolder);<br>                    registerBeanDefinition(definitionHolder, this.registry);<br>                }<br>            }<br>        }<br>        return beanDefinitions;<br>    }
复制代码
下面将以上部分代码展开去讲
1.1 扫描包下面的所有组件

即对应findCandidateComponents方法的操作,该方法如下:
  1.     /**<br>     * Scan the class path for candidate components.<br>     * @param basePackage the package to check for annotated classes<br>     * @return a corresponding Set of autodetected bean definitions<br>     */<br>    public Set<BeanDefinition> findCandidateComponents(String basePackage) {<br>        if (this.componentsIndex != null && indexSupportsIncludeFilters()) {<br>            return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);<br>        }<br>        else {<br>            return scanCandidateComponents(basePackage);<br>        }<br>    }
复制代码
1.2 依次处理扫描到的组件


2. 非懒加载单例Bean的创建

本小节介绍在扫描完BeanDefinition之后的,在初始化的时候做的事情,对于每一个扫描到的BeanDefinition,合并成RootBeanDefinition,之后调用getSingleton,如果是单例非懒加载Bean,就实例化、初始化Bean,加载到单例池中。
这里是在ApplicitionContext的refresh()方法中调用的,其中有beanFactory.preInstantiateSingletons();这么一步,即初始化所有的非懒加载的单例Bean,具体实现如下:
  1.     public void preInstantiateSingletons() throws BeansException {<br>        if (logger.isTraceEnabled()) {<br>            logger.trace("Pre-instantiating singletons in " + this);<br>        }<br>​<br>        // Iterate over a copy to allow for init methods which in turn register new bean definitions.<br>        // While this may not be part of the regular factory bootstrap, it does otherwise work fine.<br>        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);<br>​<br>        // Trigger initialization of all non-lazy singleton beans...<br>        for (String beanName : beanNames) {<br>            // 因为之前BeanDefinition存在继承的概念,这里是合并子BeanDefinition和父BeanDefinition<br>            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);<br>            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {<br>                // 非懒加载单例bean<br>                if (isFactoryBean(beanName)) {<br>                    // 处理工厂Bean<br>                    Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);<br>                    if (bean instanceof FactoryBean) {<br>                        FactoryBean<?> factory = (FactoryBean<?>) bean;<br>                        boolean isEagerInit;<br>                        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {<br>                            isEagerInit = AccessController.doPrivileged(<br>                                    (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,<br>                                    getAccessControlContext());<br>                        }<br>                        else {<br>                            isEagerInit = (factory instanceof SmartFactoryBean &&<br>                                    ((SmartFactoryBean<?>) factory).isEagerInit());<br>                        }<br>                        if (isEagerInit) {<br>                            getBean(beanName);<br>                        }<br>                    }<br>                }<br>                else {<br>                    // 初始化Bean<br>                    getBean(beanName);<br>                }<br>            }<br>        }<br>​<br>        // Trigger post-initialization callback for all applicable beans...<br>        for (String beanName : beanNames) {<br>            Object singletonInstance = getSingleton(beanName);<br>            if (singletonInstance instanceof SmartInitializingSingleton) {<br>                StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")<br>                        .tag("beanName", beanName);<br>                SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;<br>                if (System.getSecurityManager() != null) {<br>                    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {<br>                        smartSingleton.afterSingletonsInstantiated();<br>                        return null;<br>                    }, getAccessControlContext());<br>                }<br>                else {<br>                    smartSingleton.afterSingletonsInstantiated();<br>                }<br>                smartInitialize.end();<br>            }<br>        }<br>    }
复制代码
之后的核心实现在getBean(beanName)的doGetBean();方法中,如下:
  1. /**<br> * Return an instance, which may be shared or independent, of the specified bean.<br> * @param name the name of the bean to retrieve<br> * @param requiredType the required type of the bean to retrieve<br> * @param args arguments to use when creating a bean instance using explicit arguments<br> * (only applied when creating a new instance as opposed to retrieving an existing one)<br> * @param typeCheckOnly whether the instance is obtained for a type check,<br> * not for actual use<br> * @return an instance of the bean<br> * @throws BeansException if the bean could not be created<br> */<br>@SuppressWarnings("unchecked")<br>protected <T> T doGetBean(<br>      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)<br>      throws BeansException {<br>    // 处理BeanName,如果是前面加了&符号,去除之,如果是别名,得到其正式的名称<br>   String beanName = transformedBeanName(name);<br>   Object beanInstance;<br>​<br>    // 这里先试着获取下单例池中有没有对应的单例对象,如果有的话,就直接返回<br>   // Eagerly check singleton cache for manually registered singletons.<br>   Object sharedInstance = getSingleton(beanName);<br>   if (sharedInstance != null && args == null) {<br>      if (logger.isTraceEnabled()) {<br>         if (isSingletonCurrentlyInCreation(beanName)) {<br>            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +<br>                  "' that is not fully initialized yet - a consequence of a circular reference");<br>         }<br>         else {<br>            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");<br>         }<br>      }<br>      beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);<br>   }<br>​<br>   else {<br>      // Fail if we're already creating this bean instance:<br>      // We're assumably within a circular reference.<br>      if (isPrototypeCurrentlyInCreation(beanName)) {<br>         throw new BeanCurrentlyInCreationException(beanName);<br>      }<br>​<br>       // 如果本bean工厂不存在传进来的BeanName,并且存在父工厂,则到父工厂中寻找<br>      // Check if bean definition exists in this factory.<br>      BeanFactory parentBeanFactory = getParentBeanFactory();<br>      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {<br>         // Not found -> check parent.<br>         String nameToLookup = originalBeanName(name);<br>         if (parentBeanFactory instanceof AbstractBeanFactory) {<br>            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(<br>                  nameToLookup, requiredType, args, typeCheckOnly);<br>         }<br>         else if (args != null) {<br>            // Delegation to parent with explicit args.<br>            return (T) parentBeanFactory.getBean(nameToLookup, args);<br>         }<br>         else if (requiredType != null) {<br>            // No args -> delegate to standard getBean method.<br>            return parentBeanFactory.getBean(nameToLookup, requiredType);<br>         }<br>         else {<br>            return (T) parentBeanFactory.getBean(nameToLookup);<br>         }<br>      }<br>​<br>      if (!typeCheckOnly) {<br>         markBeanAsCreated(beanName);<br>      }<br>​<br>      StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")<br>            .tag("beanName", name);<br>      try {<br>         if (requiredType != null) {<br>            beanCreation.tag("beanType", requiredType::toString);<br>         }<br>          // 取合并之后的rootBeanDefinition<br>         RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);<br>         checkMergedBeanDefinition(mbd, beanName, args);<br>​<br>          // 如果有被dependsOn注解修饰,优先初始化dependsOn中的bean<br>         // Guarantee initialization of beans that the current bean depends on.<br>         String[] dependsOn = mbd.getDependsOn();<br>         if (dependsOn != null) {<br>            for (String dep : dependsOn) {<br>               if (isDependent(beanName, dep)) {<br>                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,<br>                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");<br>               }<br>               registerDependentBean(dep, beanName);<br>               try {<br>                  getBean(dep);<br>               }<br>               catch (NoSuchBeanDefinitionException ex) {<br>                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,<br>                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);<br>               }<br>            }<br>         }<br>​<br>          // 之后基于不同的scope来创建bean<br>         // Create bean instance.<br>         if (mbd.isSingleton()) {<br>            sharedInstance = getSingleton(beanName, () -> {<br>               try {<br>                  return createBean(beanName, mbd, args);<br>               }<br>               catch (BeansException ex) {<br>                  // Explicitly remove instance from singleton cache: It might have been put there<br>                  // eagerly by the creation process, to allow for circular reference resolution.<br>                  // Also remove any beans that received a temporary reference to the bean.<br>                  destroySingleton(beanName);<br>                  throw ex;<br>               }<br>            });<br>            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);<br>         }<br>​<br>         else if (mbd.isPrototype()) {<br>            // It's a prototype -> create a new instance.<br>            Object prototypeInstance = null;<br>            try {<br>               beforePrototypeCreation(beanName);<br>               prototypeInstance = createBean(beanName, mbd, args);<br>            }<br>            finally {<br>               afterPrototypeCreation(beanName);<br>            }<br>            beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);<br>         }<br>​<br>         else {<br>            String scopeName = mbd.getScope();<br>            if (!StringUtils.hasLength(scopeName)) {<br>               throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");<br>            }<br>            Scope scope = this.scopes.get(scopeName);<br>            if (scope == null) {<br>               throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");<br>            }<br>            try {<br>               Object scopedInstance = scope.get(beanName, () -> {<br>                  beforePrototypeCreation(beanName);<br>                  try {<br>                     return createBean(beanName, mbd, args);<br>                  }<br>                  finally {<br>                     afterPrototypeCreation(beanName);<br>                  }<br>               });<br>               beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);<br>            }<br>            catch (IllegalStateException ex) {<br>               throw new ScopeNotActiveException(beanName, scopeName, ex);<br>            }<br>         }<br>      }<br>      catch (BeansException ex) {<br>         beanCreation.tag("exception", ex.getClass().toString());<br>         beanCreation.tag("message", String.valueOf(ex.getMessage()));<br>         cleanupAfterBeanCreationFailure(beanName);<br>         throw ex;<br>      }<br>      finally {<br>         beanCreation.end();<br>      }<br>   }<br>​<br>   return adaptBeanInstance(name, beanInstance, requiredType);<br>}
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4