spring源码分析(一)lazy-init 在Spring中是怎么控制加载的

 2019-10-17 21:56  阅读(812)
文章分类:Spring boot

lazy-init为false,spring容器启动时进行预实例化
lazy-init为true,spring容器启动时懒加载拥有改属性的bean,不进行预实例化
以下源码可以重点看注释部分

  1. IOC阶段,将bean的配置信息解析成BeanDefinition,并放入map中
    解析BeanDefinition的方法org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionAttributes

    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

            if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
                error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
            }
         //解析scope
            else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
                bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
            }
            else if (containingBean != null) {
                // Take default from containing bean in case of an inner bean definition.
                bd.setScope(containingBean.getScope());
            }
    
            if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
                bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
            }
            //这里就是解析lazy-init, org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#defaults 是全局默认配置
            String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
            if (DEFAULT_VALUE.equals(lazyInit)) {
                lazyInit = this.defaults.getLazyInit();
            }
            //lazy-init的配置值跟true比较
            bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
    
            String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
            bd.setAutowireMode(getAutowireMode(autowire));
    
            if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
                String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
                bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
            }
    
            String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
            if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
                String candidatePattern = this.defaults.getAutowireCandidates();
                if (candidatePattern != null) {
                    String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
                    bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
                }
            }
            else {
                bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
            }
    
            if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
                bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
            }
    
            if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
                String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
                bd.setInitMethodName(initMethodName);
            }
            else if (this.defaults.getInitMethod() != null) {
                bd.setInitMethodName(this.defaults.getInitMethod());
                bd.setEnforceInitMethod(false);
            }
    
            if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
                String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
                bd.setDestroyMethodName(destroyMethodName);
            }
            else if (this.defaults.getDestroyMethod() != null) {
                bd.setDestroyMethodName(this.defaults.getDestroyMethod());
                bd.setEnforceDestroyMethod(false);
            }
    
            if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
                bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
            }
            if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
                bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
            }
    
            return bd;
        }
    
  2. DI依赖注入阶段,spring预实例化bean
    org.springframework.context.support.AbstractApplicationContext#refresh refresh方法是入口,大家都很熟悉了吧

    public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh();

                // Tell the subclass to refresh the internal bean factory.
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                prepareBeanFactory(beanFactory);
    
                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    onRefresh();
    
                    // Check for listener beans and register them.
                    registerListeners();
    
                    //这里是进入实例化bean的第一层入口
                    // Instantiate all remaining (non-lazy-init) singletons.
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    finishRefresh();
                }
    
                catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                    }
    
                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();
    
                    // Reset 'active' flag.
                    cancelRefresh(ex);
    
                    // Propagate exception to caller.
                    throw ex;
                }
    
                finally {
                    // Reset common introspection caches in Spring's core, since we
                    // might not ever need metadata for singleton beans anymore...
                    resetCommonCaches();
                }
            }
        }
    

进入org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization方法看怎么利用懒加载的

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
            // Initialize conversion service for this context.
            if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
                    beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
                beanFactory.setConversionService(
                        beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
            }

            // Register a default embedded value resolver if no bean post-processor
            // (such as a PropertyPlaceholderConfigurer bean) registered any before:
            // at this point, primarily for resolution in annotation attribute values.
            if (!beanFactory.hasEmbeddedValueResolver()) {
                beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
            }

            // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
            String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
            for (String weaverAwareName : weaverAwareNames) {
                getBean(weaverAwareName);
            }

            // Stop using the temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(null);

            // Allow for caching all bean definition metadata, not expecting further changes.
            beanFactory.freezeConfiguration();
            //本方法内还没有直接利用lazy-init属性,这里又是一个入口,
            // Instantiate all remaining (non-lazy-init) singletons.
            beanFactory.preInstantiateSingletons();
        }

再走进org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons方法看

public void preInstantiateSingletons() throws BeansException {
            if (logger.isDebugEnabled()) {
                logger.debug("Pre-instantiating singletons in " + this);
            }

            // Iterate over a copy to allow for init methods which in turn register new bean definitions.
            // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
            List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

            // Trigger initialization of all non-lazy singleton beans...
            for (String beanName : beanNames) {
                RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
                //这里才是真正的使用lazy-init属性的地方,lazy-init为false就可以执行下面真正的预实例化getBean
                //这里可以看出BeanDefinition属性抽象的、非单例的、lazy-init为true的是不会进行预实例化的
                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);
                    }
                }
            }

            // Trigger post-initialization callback for all applicable beans...
            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();
                    }
                }
            }
        }

来源:[]()

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> spring源码分析(一)lazy-init 在Spring中是怎么控制加载的

相关推荐