当前位置 博文首页 > yangkewei616的专栏:Spring容器初始化、bean解析、getbean流程

    yangkewei616的专栏:Spring容器初始化、bean解析、getbean流程

    作者:[db:作者] 时间:2021-08-12 15:09

    Context介绍:

    Context类图如下:
    这里写图片描述

    主要类功能

    • ApplicationContext:Context的核心接口,主要功能都是继承其他接口而来,ListableBeanFactory(获取和访问bean功能),MessageSource(解析消息,支持国际化),ApplicationEventPublisher(发布event到注册的lisnter),ResourcePatternResolver(load文件资源),…完了在补充
    • ConfigurableApplicationContext:继承 Lifecycle, Closeable有生命周期功能,添加Id,Environment,BeanFactoryPostProcessor,ApplicationListener的set或get方法,还有重要的refresh(把持久层的数据load到内存中,并clear掉所有的之前创建的bean,包括singletons)方法
    • AbstractApplicationContext:继承DefaultResourceLoader,具有load资源功能(包涵classloader和持久层资源),在这个类内主要作用:refresh的模板方法和ApplicationEvent发布功能
    • AbstractRefreshableApplicationContext:对父类refresh里面部分方法,二级方法的实现
    • AbstractRefreshableConfigApplicationContext对Context继承BeanNameAware, InitializingBean,使其有bean的特性,增加setConfigLocations方法
    • AbstractXmlApplicationContext:增加生成XmlBeanDefinitionReader并用reader load到持久化的bean的配置文件功能
    • ClassPathXmlApplicationContext:构造方法传入持久化配置文件路径

    BeanFactory介绍:

    BeanFactory接口类图如下:
    这里写图片描述

    主要类功能

    • BeanFactory:持有一些bean definitions,依赖bean definitions,根据name、type获取scope为Prototype,Singleton的bean
    • ListableBeanFactory:扩展BeanFactory接口,根据type,name返回bean集合,不需要每次一个一个获取
    • HierarchicalBeanFactory:用warp的方式实现了Bean工厂的分层,setParentBeanFactory方法在ConfigurableBeanFactory接口钟
    • ConfigurableBeanFactory:实现BeanClassLoader,SpEL表达式解释器,属性转化器,Scope,权限控制的setget方法;bean的依赖,是否创建销毁等方法
    • AutowireCapableBeanFactory:提供外部生成的bean注入根据name,class注入到容器中
    • ConfigurableListableBeanFactory:实现上面所有接口,有所有功能,对一下beandefinition 进行分析和修改
    • ConfigurableListableBeanFactory:实现上面所有接口,有所有功能,对一下beandefinition进行分析和修改
    • SingletonBeanRegistry:singletonBean接口,主要方法registerSingleton、getSingleton和一些其他辅助方法
    • AliasRegistry:Alias的注册删除等方法
    • SimpleAliasRegistry:用一个ConcurrentHashMap实现的AliasRegistry
    • DefaultSingletonBeanRegistry:实现singletonBean的注册,继承SimpleAliasRegistry,所以有别名功能
    • FactoryBeanRegistrySupport:扩展DefaultSingletonBeanRegistry功能,具体作用后面分析
    • AbstractBeanFactory 实现singleton和普通bean的get方法
    • AbstractAutowireCapableBeanFactory bean的创建, 属性, 绑定和初始化.处理运行时bean引用, 解析管理的集合, 调用初始化方法。
    • BeanDefinitionRegistry:bd注册功能
    • DefaultListableBeanFactory:实现了所有接口的功能,可以作为一个标准的beanfactory,也可以自定义BeanFactory的父类

    Resource介绍:

    Resource接口类图如下:
    这里写图片描述

    BeanDefinitionReader介绍:

    BeanDefinitionReader接口类图如下:
    这里写图片描述

    BeanDefinition介绍:

    BeanDefinition接口类图如下:
    这里写图片描述

    ResourceLoader介绍:

    ResourceLoader接口类图如下:
    这里写图片描述

    解析BeanDefinition流程:

    ApplicationContext做为容器中心(内部wrap一个beanfactory),
    1. 把持久化文件转化resource
    2. 读入以流的形势读到内存,BeanDefinitionReader以流形式解析resource成BeanDefinition
    3. BeanDefinitionHolder对BeanDefinition进行wrap,注册到context wrap的beanfactory中

    Bean解析流程:

    下面开始从代码流程上分析Bean的解析过程:

    使用代码如下:

            String file = "bean.xml";
            ClassPathXmlApplicationContext context1 = new ClassPathXmlApplicationContext(file);
            ModelA modelA = (ModelA) context1.getBean("modelA");
            System.out.println(modelA);

    ClassPathXmlApplicationContext

    
        public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
            this(new String[] {configLocation}, true, null);
        }
        public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
                throws BeansException {
    
            super(parent);
    
            setConfigLocations(configLocations);
            if (refresh) {
                refresh();
            }
        }

    两个主要方法:setConfigLocations,refresh,先跟setConfigLocations,功能主要两个:1.把占位符替换为真正的值 2.把值path设置到context中
    AbstractRefreshableConfigApplicationContext

            public void setConfigLocations(String... locations) {
            if (locations != null) {
                Assert.noNullElements(locations, "Config locations must not be null");
                this.configLocations = new String[locations.length];
                for (int i = 0; i < locations.length; i++) {
                    //把占位符号用环境变量或System.getProperties().get("key")替换
                    this.configLocations[i] = resolvePath(locations[i]).trim();
                }
            }
            else {
                this.configLocations = null;
            }
        }
        protected String resolvePath(String path) {
           //getEnvironment(),可以返回一个StandardEnvironment,继续跟到AbstractPropertyResolver类
            return getEnvironment().resolveRequiredPlaceholders(path);//
        }
    
    

    AbstractPropertyResolver

        public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
            if (this.strictHelper == null) {
                this.strictHelper = createPlaceholderHelper(false);
            }
            return doResolvePlaceholders(text, this.strictHelper);
        }
    
        private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
            //最终处理在PropertyPlaceholderHelper
            return helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() {
                @Override
                public String resolvePlaceholder(String placeholderName) {
                    return getPropertyAsRawString(placeholderName);
                }
            });
        }
    public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
            Assert.notNull(value, "'value' must not be null");
            return parseStringValue(value, placeholderResolver, new HashSet<String>());
        }
        //核心方法
        //strVal = "${key:bean$}.xml" 带默认值
        //strVal = "${key${keyiner}}.xml" 带嵌套子占位符
        protected String parseStringValue(
                String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
    
            StringBuilder result = new StringBuilder(strVal);
            //this.placeholderPrefix='${',这个值可以修改
            int startIndex = strVal.indexOf(this.placeholderPrefix);
            while (startIndex != -1) {
                //找到对应${的}
                //找的逻辑很简单,用index变量,从前往后找,匹配到前缀index++,匹配到后缀且index>0,index--,否则命中,如果什么都匹配继续找
                int endIndex = findPlaceholderEndIndex(result, startIndex);
                if (endIndex != -1) {
                    String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
                    String originalPlaceholder = placeholder;
                    if (!visitedPlaceholders.add(originalPlaceholder)) {
                        throw new IllegalArgumentException(
                                "Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
                    }
                    //这个递归的作用先替换子占位符,及先找出嵌套子占位符的${keyiner},用值替换
                    // Recursive invocation, parsing placeholders contained in the placeholder key.
                    //
                    placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
                    // Now obtain the value for the fully resolved key...
                    //到StandardEnvironment注册的Propertie和evn找替换占位符的value
                    String propVal = placeholderResolver.resolvePlaceholder(placeholder);
                    //没有找到,获取默认值,"${key:bean$}.xml"中的bean
                    if (propVal == null && this.valueSeparator != null) {
                        int separatorIndex = placeholder.indexOf(this.valueSeparator);
                        if (separatorIndex != -1) {
                            String actualPlaceholder = placeholder.substring(0, separatorIndex);
                            String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
                            propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
                            if (propVal == null) {
                                propVal = defaultValue;
                            }
                        }
                    }
                    if (propVal != null) {
                        // Recursive invocation, parsing placeholders contained in the
                        // previously resolved placeholder value.
                        //和上面递归类似,这个是evn或prop中有占位符
                        propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
                        result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
                        if (logger.isTraceEnabled()) {
                            logger.trace("Resolved placeholder '" + placeholder + "'");
                        }
                        startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
                    }
                    else if (this.ignoreUnresolvablePlaceholders) {
                        // Proceed with unprocessed value.
                        startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
                    }
                    else {
                        throw new IllegalArgumentException("Could not resolve placeholder '" +
                                placeholder + "'" + " in string value \"" + strVal + "\"");
                    }
                    visitedPlaceholders.remove(originalPlaceholder);
                }
                else {
                    startIndex = -1;
                }
            }
    
            return result.toString();
        }
    

    下面跟refresh方法,refresh主要模版在父类AbstractApplicationContext中,

    AbstractApplicationContext.refresh

        @Override
        public void refresh() throws BeansException, IllegalStateException {
            //枷锁,refresh逻辑同时只有一个线程,close方法也用的这个锁,保证只能同时执行一个方法
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing.
                //设置启动时间、一些标志位、初始化一些全局变量等
                prepareRefresh();
    
                // Tell the subclass to refresh the internal bean factory.
                //真正BeanFactory创建方法,上面主要分析这个方法
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                //对beanfactory
                prepareBeanFactory(beanFactory);
    
                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    //子类prepare,如果子类类似webcontext,evnbean,特殊bean,在这里实现。它的作用同前一个方法
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    //BeanFactoryPostProcessor的实现方法被调用
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // Register bean processors that intercept bean creation.
                    //把BeanPostProcessor注册到beanFactory的一个list中
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    //国际化相关,
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    //context是实现了ApplicationEventPublisher,
                    //如果没有配置applicationEventMulticaster,则注册单例new SimpleApplicationEventMulticaster();
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    //默认空实现,为子类在实例singletonsBean之前,可以实例先特殊bean
                    onRefresh();
    
                    // Check for listener beans and register them.
                    //把listener注册到到applicationEventMulticaster中
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    //初始化所有非懒加载的单例bean
                    //重要方法,跟进分析
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    //发个context event,get生命周期的相关bean,注册一些全局变量
                    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.
                    //如果挂了,清除单例bean,避免浪费资源
                    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();
                }
            }
        }

    先看下prepareRefresh方法
    AbstractApplicationContext

    protected void prepareRefresh() {
            //纪录启动时间,设置标志位
            this.startupDate = System.currentTimeMillis();
            this.closed.set(false);
            this.active.set(true);
    
            if (logger.isInfoEnabled()) {
                logger.info("Refreshing " + this);
            }
    
            // Initialize any placeholder property sources in the context environment
    
            //env等初始化一些全局的property
            initPropertySources();
    
            // Validate that all properties marked as required are resolvable
            // see ConfigurablePropertyResolver#setRequiredProperties
            //validate必要prop全部有,如果没有throws异常
            getEnvironment().validateRequiredProperties();
    
            // Allow for the collection of early ApplicationEvents,
            // to be published once the multicaster is available...
            this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
        }

    obtainFreshBeanFactory这个时重点方法,配置文件的加载、解析、注册
    AbstractApplicationContext

        protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
            //主要的初始化功能在这个方法
            refreshBeanFactory();
            ConfigurableListableBeanFactory beanFactory = getBeanFactory();
            if (logger.isDebugEnabled()) {
                logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
            }
            return beanFactory;
        }

    AbstractRefreshableApplicationContext

        @Override
        protected final void refreshBeanFactory() throws BeansException {
            //如果之前存在BeanFactory
            if (hasBeanFactory()) {
                //destory此BeanFactory注册的单例bean
                destroyBeans();
                //置为当前wrap引用指向null
                closeBeanFactory();
            }
            try {
                //new BeanFactory
                DefaultListableBeanFactory beanFactory = createBeanFactory();
                //把beanFactory和当前Context用id关联
                beanFactory.setSerializationId(getId());
                //设置把Contxt的一些标志设置给BeanFactory,这里主要有两个
                //allowBeanDefinitionOverriding(bean同名 覆盖or exception),allowCircularReferences(bean可以循环引用)
                customizeBeanFactory(beanFactory);
                //主要方法,继续跟
                loadBeanDefinitions(beanFactory);
                synchronized (this.beanFactoryMonitor) {
                    this.beanFactory = beanFactory;
                }
            }
            catch (IOException ex) {
                throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
            }
        }

    真正创建的factory是DefaultListableBeanFactory
    AbstractRefreshableApplicationContext

    protected DefaultListableBeanFactory createBeanFactory() {
            return new DefaultListableBeanFactory(getInternalParentBeanFactory());
        }

    loadBeanDefinitions实现在子类中,因为不同的配置文件需要是不同的resource,也需要不同的reader
    AbstractXmlApplicationContext.loadBeanDefinitions

    @Override
        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            // Create a new XmlBeanDefinitionReader for the given BeanFactory.
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
            // Configure the bean definition reader with this context's
            // resource loading environment.
            //把context的env设置Reader中
            beanDefinitionReader.setEnvironment(this.getEnvironment());
            //把context的ResouceLoader设置Reader中,Context继承DefaultResourceLoader
            beanDefinitionReader.setResourceLoader(this);
            //xml中spring相关的dtd和schema的entiryResolver
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    
            // Allow a subclass to provide custom initialization of the reader,
            // then proceed with actually loading the bean definitions.
            //英文注释是用来子类自定义的
            initBeanDefinitionReader(beanDefinitionReader);
            //这个跟进
            loadBeanDefinitions(beanDefinitionReader);
        }

    查看XmlBeanDefinitionReader父类AbstractBeanDefinitionReader中构造方法
    AbstractBeanDefinitionReader.AbstractBeanDefinitionReader

    protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
            Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
            //把DefaultListableBeanFactory实现了BeanDefinitionRegistry接
            this.registry = registry;
    
            // Determine ResourceLoader to use.
            //DefaultListableBeanFactory没有实现ResourceLoader,所以走else
            if (this.registry instanceof ResourceLoader) {
                this.resourceLoader = (ResourceLoader) this.registry;
            }
            else {
                this.resourceLoader = new PathMatchingResourcePatternResolver();
            }
            //DefaultListableBeanFactory没有实现EnvironmentCapable,所以走else