前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring bean解析 - refresh

Spring bean解析 - refresh

作者头像
MickyInvQ
发布2021-10-09 16:52:06
1.4K0
发布2021-10-09 16:52:06
举报
文章被收录于专栏:InvQ的专栏InvQ的专栏

文章目录

refresh

Spring bean解析就在此方法,所以单独提出来。

AbstractApplicationContext.refresh:

代码语言:javascript
复制
@Override
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();
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);
            // Last step: publish corresponding event.
            finishRefresh();
        } catch (BeansException 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();
        }
    }
}

prepareRefresh

代码语言:javascript
复制
protected void prepareRefresh() {
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);
    // Initialize any placeholder property sources in the context environment
    //空实现
    initPropertySources();
    // Validate that all properties marked as required are resolvable
    // see ConfigurablePropertyResolver#setRequiredProperties
    getEnvironment().validateRequiredProperties();
    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
属性校验

AbstractEnvironment.validateRequiredProperties:

代码语言:javascript
复制
@Override
public void validateRequiredProperties() throws MissingRequiredPropertiesException {
    this.propertyResolver.validateRequiredProperties();
}

AbstractPropertyResolver.validateRequiredProperties:

代码语言:javascript
复制
@Override
public void validateRequiredProperties() {
    MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
    for (String key : this.requiredProperties) {
        if (this.getProperty(key) == null) {
            ex.addMissingRequiredProperty(key);
        }
    }
    if (!ex.getMissingRequiredProperties().isEmpty()) {
        throw ex;
    }
}

requiredProperties是通过setRequiredProperties方法设置的,保存在一个list里面,默认是空的,也就是不需要校验任何属性。

BeanFactory创建

由obtainFreshBeanFactory调用AbstractRefreshableApplicationContext.refreshBeanFactory:

代码语言:javascript
复制
@Override
protected final void refreshBeanFactory() throws BeansException {
    //如果已经存在,那么销毁之前的
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    //创建了一个DefaultListableBeanFactory对象
    DefaultListableBeanFactory beanFactory = createBeanFactory();
    beanFactory.setSerializationId(getId());
    customizeBeanFactory(beanFactory);
    loadBeanDefinitions(beanFactory);
    synchronized (this.beanFactoryMonitor) {
        this.beanFactory = beanFactory;
    }
}
BeanFactory接口

此接口实际上就是Bean容器,

BeanFactory定制

AbstractRefreshableApplicationContext.customizeBeanFactory方法用于给子类提供一个自由配置的机会,默认实现:

代码语言:javascript
复制
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    if (this.allowBeanDefinitionOverriding != null) {
        //默认false,不允许覆盖
        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    if (this.allowCircularReferences != null) {
        //默认false,不允许循环引用
        beanFactory.setAllowCircularReferences(this.allowCircularReferences);
    }
}
Bean加载

AbstractXmlApplicationContext.loadBeanDefinitions,这个便是核心的bean加载了:

代码语言:javascript
复制
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
    // 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.
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    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);
}
EntityResolver

EntityResolver接口在org.xml.sax中定义。DelegatingEntityResolver用于schema和dtd的解析。

BeanDefinitionReader
路径解析(Ant)
代码语言:javascript
复制
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) {
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }
    String[] configLocations = getConfigLocations();
    //here
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }
}

AbstractBeanDefinitionReader.loadBeanDefinitions:

代码语言:javascript
复制
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
    Assert.notNull(locations, "Location array must not be null");
    int counter = 0;
    for (String location : locations) {
        counter += loadBeanDefinitions(location);
    }
    return counter;
}

之后调用:

代码语言:javascript
复制
//第二个参数为空
public int loadBeanDefinitions(String location, Set<Resource> actualResources) {
    ResourceLoader resourceLoader = getResourceLoader();
    //参见ResourceLoader类图,ClassPathXmlApplicationContext实现了此接口
    if (resourceLoader instanceof ResourcePatternResolver) {
        // Resource pattern matching available.
        try {
            Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            int loadCount = loadBeanDefinitions(resources);
            if (actualResources != null) {
                for (Resource resource : resources) {
                    actualResources.add(resource);
                }
            }
            return loadCount;
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "Could not resolve bean definition resource pattern [" + location + "]", ex);
        }
    }
    else {
        // Can only load single resources by absolute URL.
        Resource resource = resourceLoader.getResource(location);
        int loadCount = loadBeanDefinitions(resource);
        if (actualResources != null) {
            actualResources.add(resource);
        }
        return loadCount;
    }
}

getResource的实现在AbstractApplicationContext:

代码语言:javascript
复制
@Override
public Resource[] getResources(String locationPattern) throws IOException {
    //构造器中初始化,PathMatchingResourcePatternResolver对象
    return this.resourcePatternResolver.getResources(locationPattern);
}

PathMatchingResourcePatternResolver是ResourceLoader继承体系的一部分。

代码语言:javascript
复制
@Override
public Resource[] getResources(String locationPattern) throws IOException {
    Assert.notNull(locationPattern, "Location pattern must not be null");
    //classpath:
    if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
        // a class path resource (multiple resources for same name possible)
        //matcher是一个AntPathMatcher对象
        if (getPathMatcher().isPattern(locationPattern
            .substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
            // a class path resource pattern
            return findPathMatchingResources(locationPattern);
        } else {
            // all class path resources with the given name
            return findAllClassPathResources(locationPattern
                .substring(CLASSPATH_ALL_URL_PREFIX.length()));
        }
    } else {
        // Only look for a pattern after a prefix here
        // (to not get fooled by a pattern symbol in a strange prefix).
        int prefixEnd = locationPattern.indexOf(":") + 1;
        if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
            // a file pattern
            return findPathMatchingResources(locationPattern);
        }
        else {
            // a single resource with the given name
            return new Resource[] {getResourceLoader().getResource(locationPattern)};
        }
    }
}

isPattern:

代码语言:javascript
复制
@Override
public boolean isPattern(String path) {
    return (path.indexOf('*') != -1 || path.indexOf('?') != -1);
}

可以看出配置文件路径是支持ant风格的,也就是可以这么写:

代码语言:javascript
复制
new ClassPathXmlApplicationContext("con*.xml");

具体怎么解析ant风格的就不写了。

配置文件加载

入口方法在AbstractBeanDefinitionReader的217行:

代码语言:javascript
复制
//加载
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//解析
int loadCount = loadBeanDefinitions(resources);

最终逐个调用XmlBeanDefinitionReader的loadBeanDefinitions方法:

代码语言:javascript
复制
@Override
public int loadBeanDefinitions(Resource resource) {
    return loadBeanDefinitions(new EncodedResource(resource));
}

Resource是代表一种资源的接口,

EncodedResource扮演的其实是一个装饰器的模式,为InputStreamSource添加了字符编码(虽然默认为null)。这样为我们自定义xml配置文件的编码方式提供了机会。

之后关键的源码只有两行:

代码语言:javascript
复制
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    InputStream inputStream = encodedResource.getResource().getInputStream();
    InputSource inputSource = new InputSource(inputStream);
    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}

InputSource是org.xml.sax的类。

doLoadBeanDefinitions:

代码语言:javascript
复制
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {
    Document doc = doLoadDocument(inputSource, resource);
    return registerBeanDefinitions(doc, resource);
}

doLoadDocument:

代码语言:javascript
复制
protected Document doLoadDocument(InputSource inputSource, Resource resource) {
    return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
        getValidationModeForResource(resource), isNamespaceAware());
}

documentLoader是一个DefaultDocumentLoader对象,此类是DocumentLoader接口的唯一实现。getEntityResolver方法返回ResourceEntityResolver,上面说过了。errorHandler是一个SimpleSaxErrorHandler对象。

校验模型其实就是确定xml文件使用xsd方式还是dtd方式来校验,忘了的话左转度娘。Spring会通过读取xml文件的方式判断应该采用哪种。

NamespaceAware默认false,因为默认配置了校验为true。

DefaultDocumentLoader.loadDocument:

代码语言:javascript
复制
@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
    ErrorHandler errorHandler, int validationMode, boolean namespaceAware) {
    //这里就是老套路了,可以看出,Spring还是使用了dom的方式解析,即一次全部load到内存
    DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
    DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
    return builder.parse(inputSource);
}

createDocumentBuilderFactory比较有意思:

代码语言:javascript
复制
protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware{
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(namespaceAware);
    if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
        //此方法设为true仅对dtd有效,xsd(schema)无效
        factory.setValidating(true);
        if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
            // Enforce namespace aware for XSD...
             //开启xsd(schema)支持
            factory.setNamespaceAware(true);
             //这个也是Java支持Schema的套路,可以问度娘
            factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
        }
    }
    return factory;
}
Bean解析

XmlBeanDefinitionReader.registerBeanDefinitions:

代码语言:javascript
复制
public int registerBeanDefinitions(Document doc, Resource resource) {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

createBeanDefinitionDocumentReader:

代码语言:javascript
复制
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
    return BeanDefinitionDocumentReader.class.cast
      //反射
      (BeanUtils.instantiateClass(this.documentReaderClass));
}

documentReaderClass默认是DefaultBeanDefinitionDocumentReader,这其实也是策略模式,通过setter方法可以更换其实现。

注意cast方法,代替了强转。

createReaderContext:

代码语言:javascript
复制
public XmlReaderContext createReaderContext(Resource resource) {
    return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
        this.sourceExtractor, this, getNamespaceHandlerResolver());
}

problemReporter是一个FailFastProblemReporter对象。

eventListener是EmptyReaderEventListener对象,此类里的方法都是空实现。

sourceExtractor是NullSourceExtractor对象,直接返回空,也是空实现。

getNamespaceHandlerResolver默认返回DefaultNamespaceHandlerResolver对象,用来获取xsd对应的处理器。

XmlReaderContext的作用感觉就是这一堆参数的容器,糅合到一起传给DocumentReader,并美其名为Context。可以看出,Spring中到处都是策略模式,大量操作被抽象成接口。

DefaultBeanDefinitionDocumentReader.registerBeanDefinitions:

代码语言:javascript
复制
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    Element root = doc.getDocumentElement();
    doRegisterBeanDefinitions(root);
}

doRegisterBeanDefinitions:

代码语言:javascript
复制
protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);
    //默认的命名空间即
    //http://www.springframework.org/schema/beans
    if (this.delegate.isDefaultNamespace(root)) {
        //检查profile属性
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            //profile属性可以以,分割
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                return;
            }
        }
    }
    preProcessXml(root);
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);
    this.delegate = parent;
}

delegate的作用在于处理beans标签的嵌套,其实Spring配置文件是可以写成这样的:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>    
<beans>    
    <bean class="base.SimpleBean"></bean>
    <beans>
        <bean class="java.lang.Object"></bean>
    </beans>
</beans>

xml(schema)的命名空间其实类似于java的报名,命名空间采用URL,比如Spring的是这样:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>    
<beans xmlns="http://www.springframework.org/schema/beans"></beans>

xmlns属性就是xml规范定义的用来设置命名空间的。这样设置了之后其实里面的bean元素全名就相当于http://www.springframework.org/schema/beans:bean,可以有效的防止命名冲突。命名空间可以通过规范定义的org.w3c.dom.Node.getNamespaceURI方法获得。

注意一下profile的检查, AbstractEnvironment.acceptsProfiles:

代码语言:javascript
复制
@Override
public boolean acceptsProfiles(String... profiles) {
    Assert.notEmpty(profiles, "Must specify at least one profile");
    for (String profile : profiles) {
        if (StringUtils.hasLength(profile) && profile.charAt(0) == '!') {
            if (!isProfileActive(profile.substring(1))) {
                return true;
            }
        } else if (isProfileActive(profile)) {
            return true;
        }
    }
    return false;
}

原理很简单,注意从源码可以看出,profile属性支持!取反

preProcessXml方法是个空实现,供子类去覆盖,目的在于给子类一个把我们自定义的标签转为Spring标准标签的机会, 想的真周到。

DefaultBeanDefinitionDocumentReader.parseBeanDefinitions:

代码语言:javascript
复制
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    parseDefaultElement(ele, delegate);
                } else {
                    delegate.parseCustomElement(ele);
                }
            }
        }
    } else {
        delegate.parseCustomElement(root);
    }
}

可见,对于非默认命名空间的元素交由delegate处理。

默认命名空间解析

即import, alias, bean, 嵌套的beans四种元素。parseDefaultElement:

代码语言:javascript
复制
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    //"import"
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}
import

写法示例:

代码语言:javascript
复制
<import resource="CTIContext.xml" />
<import resource="customerContext.xml" />

importBeanDefinitionResource套路和之前的配置文件加载完全一样,不过注意被import进来的文件是先于当前文件 被解析的。

alias

加入有一个bean名为componentA-dataSource,但是另一个组件想以componentB-dataSource的名字使用,就可以这样定义:

代码语言:javascript
复制
<alias name="componentA-dataSource" alias="componentB-dataSource"/>

processAliasRegistration核心源码:

代码语言:javascript
复制
protected void processAliasRegistration(Element ele) {
    String name = ele.getAttribute(NAME_ATTRIBUTE);
    String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
    getReaderContext().getRegistry().registerAlias(name, alias);
    getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
}

从前面的源码可以发现,registry其实就是DefaultListableBeanFactory,它实现了BeanDefinitionRegistry接口。registerAlias方法的实现在SimpleAliasRegistry:

代码语言:javascript
复制
@Override
public void registerAlias(String name, String alias) {
    Assert.hasText(name, "'name' must not be empty");
    Assert.hasText(alias, "'alias' must not be empty");
    //名字和别名一样
    if (alias.equals(name)) {
        //ConcurrentHashMap
        this.aliasMap.remove(alias);
    } else {
        String registeredName = this.aliasMap.get(alias);
        if (registeredName != null) {
            if (registeredName.equals(name)) {
                // An existing alias - no need to re-register
                return;
            }
            if (!allowAliasOverriding()) {
                throw new IllegalStateException
                    ("Cannot register alias '" + alias + "' for name '" +
                    name + "': It is already registered for name '" + registeredName + "'.");
            }
        }
        checkForAliasCircle(name, alias);
        this.aliasMap.put(alias, name);
    }
}

所以别名关系的保存使用Map完成,key为别名,value为本来的名字。

bean

bean节点是Spring最最常见的节点了。

DefaultBeanDefinitionDocumentReader.processBeanDefinition:

代码语言:javascript
复制
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            BeanDefinitionReaderUtils.registerBeanDefinition
                (bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}
id & name处理

最终调用BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, BeanDefinition containingBean),源码较长,分部分说明。

首先获取到id和name属性,name属性支持配置多个,以逗号分隔,如果没有指定id,那么将以第一个name属性值代替。id必须是唯一的,name属性其实是alias的角色,可以和其它的bean重复,如果name也没有配置,那么其实什么也没做

代码语言:javascript
复制
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
    //按,分隔
    String[] nameArr = StringUtils.tokenizeToStringArray
        (nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
    //name的第一个值作为id
    beanName = aliases.remove(0);
}
//默认null
if (containingBean == null) {
    //校验id是否已重复,如果重复直接抛异常
    //校验是通过内部一个HashSet完成的,出现过的id都会保存进此Set
    checkNameUniqueness(beanName, aliases, ele);
}
beanName生成

如果name和id属性都没有指定,那么Spring会自己生成一个, BeanDefinitionParserDelegate.parseBeanDefinitionElement:

代码语言:javascript
复制
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
aliases.add(beanClassName);

可见,Spring同时会把类名作为其别名。

最终调用的是BeanDefinitionReaderUtils.generateBeanName:

代码语言:javascript
复制
public static String generateBeanName(
        BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) {
    String generatedBeanName = definition.getBeanClassName();
    if (generatedBeanName == null) {
        if (definition.getParentName() != null) {
            generatedBeanName = definition.getParentName() + "$child";
             //工厂方法产生的bean
        } else if (definition.getFactoryBeanName() != null) {
            generatedBeanName = definition.getFactoryBeanName() + "$created";
        }
    }
    String id = generatedBeanName;
    if (isInnerBean) {
        // Inner bean: generate identity hashcode suffix.
        id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + 
            ObjectUtils.getIdentityHexString(definition);
    } else {
        // Top-level bean: use plain class name.
        // Increase counter until the id is unique.
        int counter = -1;
         //用类名#自增的数字命名
        while (counter == -1 || registry.containsBeanDefinition(id)) {
            counter++;
            id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
        }
    }
    return id;
}
bean解析

还是分部分说明(parseBeanDefinitionElement)。

首先获取到bean的class属性和parent属性,配置了parent之后,当前bean会继承父bean的属性。之后根据class和parent创建BeanDefinition对象。

代码语言:javascript
复制
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
    className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
    parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
AbstractBeanDefinition bd = createBeanDefinition(className, parent);

BeanDefinition的创建在BeanDefinitionReaderUtils.createBeanDefinition:

代码语言:javascript
复制
public static AbstractBeanDefinition createBeanDefinition(
        String parentName, String className, ClassLoader classLoader) {
    GenericBeanDefinition bd = new GenericBeanDefinition();
    bd.setParentName(parentName);
    if (className != null) {
        if (classLoader != null) {
            bd.setBeanClass(ClassUtils.forName(className, classLoader));
        }
        else {
            bd.setBeanClassName(className);
        }
    }
    return bd;
}

之后是解析bean的其它属性,其实就是读取其配置,调用相应的setter方法保存在BeanDefinition中:

代码语言:javascript
复制
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

之后解析bean的decription子元素:

代码语言:javascript
复制
<bean id="b" name="one, two" class="base.SimpleBean">
    <description>SimpleBean</description>
</bean>

就仅仅是个描述。

然后是meta子元素的解析,meta元素在xml配置文件里是这样的:

代码语言:javascript
复制
<bean id="b" name="one, two" class="base.SimpleBean">
    <meta key="name" value="skywalker"/>
</bean>

注释上说,这样可以将任意的元数据附到对应的bean definition上。解析过程源码:

代码语言:javascript
复制
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
    NodeList nl = ele.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
            Element metaElement = (Element) node;
            String key = metaElement.getAttribute(KEY_ATTRIBUTE);
            String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
             //就是一个key, value的载体,无他
            BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
             //sourceExtractor默认是NullSourceExtractor,返回的是空
            attribute.setSource(extractSource(metaElement));
            attributeAccessor.addMetadataAttribute(attribute);
        }
    }
}

AbstractBeanDefinition继承自BeanMetadataAttributeAccessor类,底层使用了一个LinkedHashMap保存metadata。这个metadata具体是做什么暂时还不知道。

lookup-method解析:

此标签的作用在于当一个bean的某个方法被设置为lookup-method后,每次调用此方法时,都会返回一个新的指定bean的对象。用法示例:

代码语言:javascript
复制
<bean id="apple" class="cn.com.willchen.test.di.Apple" scope="prototype"/>
<!--水果盘-->
<bean id="fruitPlate" class="cn.com.willchen.test.di.FruitPlate">
    <lookup-method name="getFruit" bean="apple"/>
</bean>

数据保存在Set中,对应的类是MethodOverrides。可以参考:

Spring - lookup-method方式实现依赖注入

replace-mothod解析:

此标签用于替换bean里面的特定的方法实现,替换者必须实现Spring的MethodReplacer接口,有点像aop的意思。

配置文件示例:

代码语言:javascript
复制
<bean name="replacer" class="springroad.deomo.chap4.MethodReplace" />  
<bean name="testBean" class="springroad.deomo.chap4.LookupMethodBean">
    <replaced-method name="test" replacer="replacer">
        <arg-type match="String" />
    </replaced-method>  
</bean> 

arg-type的作用是指定替换方法的参数类型,因为接口的定义参数都是Object的。参考: SPRING.NET 1.3.2 学习20–方法注入之替换方法注入

解析之后将数据放在ReplaceOverride对象中,里面有一个LinkedList专门用于保存arg-type。

构造参数(constructor-arg)解析:

作用一目了然,使用示例:

代码语言:javascript
复制
<bean class="base.SimpleBean">
    <constructor-arg>
        <value type="java.lang.String">Cat</value>
    </constructor-arg>
</bean>

type一般不需要指定,除了泛型集合那种。除此之外,constructor-arg还支持name, index, ref等属性,可以具体的指定参数的位置等。构造参数解析后保存在BeanDefinition内部一个ConstructorArgumentValues对象中。如果设置了index属性,那么以Map<Integer, ValueHolder>的形式保存,反之,以List的形式保存。

property解析:

非常常用的标签,用以为bean的属性赋值,支持value和ref两种形式,示例:

代码语言:javascript
复制
<bean class="base.SimpleBean">
    <property name="name" value="skywalker" />
</bean>

value和ref属性不能同时出现,如果是ref,那么将其值保存在不可变的RuntimeBeanReference对象中,其实现了BeanReference接口,此接口只有一个getBeanName方法。如果是value,那么将其值保存在TypedStringValue对象中。最终将对象保存在BeanDefinition内部一个MutablePropertyValues对象中(内部以ArrayList实现)。

qualifier解析:

配置示例:

代码语言:javascript
复制
<bean class="base.Student">
    <property name="name" value="skywalker"></property>
    <property name="age" value="12"></property>
    <qualifier type="org.springframework.beans.factory.annotation.Qualifier" value="student" />
</bean> 
<bean class="base.Student">
    <property name="name" value="seaswalker"></property>
    <property name="age" value="15"></property>
    <qualifier value="student_2"></qualifier>
</bean>
<bean class="base.SimpleBean" />

SimpleBean部分源码:

代码语言:javascript
复制
@Autowired
@Qualifier("student")
private Student student;

此标签和@Qualifier, @Autowired两个注解一起使用才有作用。@Autowired注解采用按类型查找的方式进行注入,如果找到多个需要类型的bean便会报错,有了@Qualifier标签就可以再按照此注解指定的名称查找。两者结合相当于实现了按类型+名称注入。type属性可以不指定,因为默认就是那个。qualifier标签可以有attribute子元素,比如:

代码语言:javascript
复制
<qualifier type="org.springframework.beans.factory.annotation.Qualifier" value="student">
    <attribute key="id" value="1"/>
</qualifier>

貌似是用来在qualifier也区分不开的时候使用。attribute键值对保存在BeanMetadataAttribute对象中。整个qualifier保存在AutowireCandidateQualifier对象中。

Bean装饰

这部分是针对其它schema的属性以及子节点,比如:

代码语言:javascript
复制
<bean class="base.Student" primary="true">
    <context:property-override />
</bean>
Bean注册

BeanDefinitionReaderUtils.registerBeanDefinition:

代码语言:javascript
复制
public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    // Register aliases for bean name, if any.
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

registry其实就是DefaultListableBeanFactory对象,registerBeanDefinition方法主要就干了这么两件事:

代码语言:javascript
复制
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
    this.beanDefinitionMap.put(beanName, beanDefinition);
    this.beanDefinitionNames.add(beanName);
}

一个是Map,另一个是List,一目了然。registerAlias方法的实现在其父类SimpleAliasRegistry,就是把键值对放在了一个ConcurrentHashMap里。

ComponentRegistered事件触发:

默认是个空实现,前面说过了。

BeanDefiniton数据结构

BeanDefiniton数据结构如下图:

在这里插入图片描述
在这里插入图片描述
beans

beans元素的嵌套直接递归调用DefaultBeanDefinitionDocumentReader.parseBeanDefinitions。

其它命名空间解析

入口在DefaultBeanDefinitionDocumentReader.parseBeanDefinitions->BeanDefinitionParserDelegate.parseCustomElement(第二个参数为空):

代码语言:javascript
复制
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    String namespaceUri = getNamespaceURI(ele);
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

NamespaceHandlerResolver由XmlBeanDefinitionReader初始化,是一个DefaultNamespaceHandlerResolver对象,也是NamespaceHandlerResolver接口的唯一实现。

其resolve方法:

代码语言:javascript
复制
@Override
public NamespaceHandler resolve(String namespaceUri) {
    Map<String, Object> handlerMappings = getHandlerMappings();
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    if (handlerOrClassName == null) {
        return null;
    } else if (handlerOrClassName instanceof NamespaceHandler) {
        return (NamespaceHandler) handlerOrClassName;
    } else {
        String className = (String) handlerOrClassName;
        Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
        NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
        namespaceHandler.init();
        handlerMappings.put(namespaceUri, namespaceHandler);
        return namespaceHandler;
    }
}

容易看出,Spring其实使用了一个Map了保存其映射关系,key就是命名空间的uri,value是NamespaceHandler对象或是Class完整名,如果发现是类名,那么用反射的方法进行初始化,如果是NamespaceHandler对象,那么直接返回

NamespaceHandler映射关系来自于各个Spring jar包下的META-INF/spring.handlers文件,以spring-context包为例:

代码语言:javascript
复制
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
NamespaceHandler继承体系
在这里插入图片描述
在这里插入图片描述
init

resolve中调用了其init方法,此方法用以向NamespaceHandler对象注册BeanDefinitionParser对象。此接口用以解析顶层(beans下)的非默认命名空间元素,比如<context:annotation-config />

所以这样逻辑就很容易理解了: 每种子标签的解析仍是策略模式的体现,init负责向父类NamespaceHandlerSupport注册不同的策略,由父类的NamespaceHandlerSupport.parse方法根据具体的子标签调用相应的策略完成解析的过程

此部分较为重要,所以重新开始大纲。

BeanFactory数据结构

BeanDefinition在BeanFactory中的主要数据结构如下图:

在这里插入图片描述
在这里插入图片描述

prepareBeanFactory

此方法负责对BeanFactory进行一些特征的设置工作,"特征"包含这么几个方面:

BeanExpressionResolver

此接口只有一个实现: StandardBeanExpressionResolver。接口只含有一个方法:

代码语言:javascript
复制
Object evaluate(String value, BeanExpressionContext evalContext)

prepareBeanFactory将一个此对象放入BeanFactory:

代码语言:javascript
复制
beanFactory.setBeanExpressionResolver(new                                   StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

StandardBeanExpressionResolver对象内部有一个关键的成员: SpelExpressionParser,其整个类图:

在这里插入图片描述
在这里插入图片描述

这便是Spring3.0开始出现的Spel表达式的解释器。

PropertyEditorRegistrar

此接口用于向Spring注册java.beans.PropertyEditor,只有一个方法:

代码语言:javascript
复制
registerCustomEditors(PropertyEditorRegistry registry)

实现也只有一个: ResourceEditorRegistrar。

在编写xml配置时,我们设置的值都是字符串形式,所以在使用时肯定需要转为我们需要的类型,PropertyEditor接口正是定义了这么个东西。

prepareBeanFactory:

代码语言:javascript
复制
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

BeanFactory也暴露了registerCustomEditors方法用以添加自定义的转换器,所以这个地方是组合模式的体现。

我们有两种方式可以添加自定义PropertyEditor:

参考: 深入理解JavaBean(2):属性编辑器PropertyEditor

环境注入

在Spring中我们自己的bean可以通过实现EnvironmentAware等一系列Aware接口获取到Spring内部的一些对象。prepareBeanFactory:

代码语言:javascript
复制
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

ApplicationContextAwareProcessor核心的invokeAwareInterfaces方法:

代码语言:javascript
复制
private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
        }
        if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        }
        //....
    }
}
依赖解析忽略

此部分设置哪些接口在进行依赖注入的时候应该被忽略:

代码语言:javascript
复制
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
bean伪装

有些对象并不在BeanFactory中,但是我们依然想让它们可以被装配,这就需要伪装一下:

代码语言:javascript
复制
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

伪装关系保存在一个Map<Class<?>, Object>里。

LoadTimeWeaver

如果配置了此bean,那么:

代码语言:javascript
复制
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    // Set a temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

这个东西具体是干什么的在后面context:load-time-weaver中说明。

注册环境

源码:

代码语言:javascript
复制
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
    beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
    beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
    beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().
        getSystemEnvironment());
}

containsLocalBean特殊之处在于不会去父BeanFactory寻找。

postProcessBeanFactory

此方法允许子类在所有的bean尚未初始化之前注册BeanPostProcessor。空实现且没有子类覆盖。

invokeBeanFactoryPostProcessors

BeanFactoryPostProcessor接口允许我们在bean正是初始化之前改变其值。此接口只有一个方法:

代码语言:javascript
复制
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);

有两种方式可以向Spring添加此对象:

注意此时尚未进行bean的初始化工作,初始化是在后面的finishBeanFactoryInitialization进行的,所以在BeanFactoryPostProcessor对象中获取bean会导致提前初始化。

此方法的关键源码:

代码语言:javascript
复制
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,
        getBeanFactoryPostProcessors());
}

getBeanFactoryPostProcessors获取的就是AbstractApplicationContext的成员beanFactoryPostProcessors(ArrayList),但是很有意思,只有通过context.addBeanFactoryPostProcessor这种方式添加的才会出现在这个List里,所以对于xml配置方式,此List其实没有任何元素。玄机就在PostProcessorRegistrationDelegate里

核心思想就是使用BeanFactory的getBeanNamesForType方法获取相应的BeanDefinition的name数组,之后逐一调用getBean方法获取到bean(初始化),getBean方法后面再说。

注意此处有一个优先级的概念,如果你的BeanFactoryPostProcessor同时实现了Ordered或者是PriorityOrdered接口,那么会被首先执行。

BeanPostProcessor注册

此部分实质上是在BeanDefinitions中寻找BeanPostProcessor,之后调用BeanFactory.addBeanPostProcessor方法保存在一个List中,注意添加时仍然有优先级的概念,优先级高的在前面。

MessageSource

此接口用以支持Spring国际化。继承体系如下:

在这里插入图片描述
在这里插入图片描述

AbstractApplicationContext的initMessageSource()方法就是在BeanFactory中查找MessageSource的bean,如果配置了此bean,那么调用getBean方法完成其初始化并将其保存在AbstractApplicationContext内部messageSource成员变量中,用以处理ApplicationContext的getMessage调用,因为从继承体系上来看,ApplicationContext是MessageSource的子类,此处是委托模式的体现。如果没有配置此bean,那么初始化一个DelegatingMessageSource对象,此类是一个空实现,同样用以处理getMessage调用请求。

参考: 学习Spring必学的Java基础知识(8)----国际化信息

事件驱动

此接口代表了Spring的事件驱动(监听器)模式。一个事件驱动包含三部分:

事件

java的所有事件对象一般都是java.util.EventObject的子类,Spring的整个继承体系如下:

在这里插入图片描述
在这里插入图片描述
发布者
ApplicationEventPublisher
在这里插入图片描述
在这里插入图片描述

一目了然。

ApplicationEventMulticaster

ApplicationEventPublisher实际上正是将请求委托给ApplicationEventMulticaster来实现的。其继承体系:

在这里插入图片描述
在这里插入图片描述
监听器

所有的监听器是jdk EventListener的子类,这是一个mark接口。继承体系:

在这里插入图片描述
在这里插入图片描述

可以看出SmartApplicationListener和GenericApplicationListener是高度相似的,都提供了事件类型检测和顺序机制,而后者是从Spring4.2加入的,Spring官方文档推荐使用后者代替前者。

初始化

前面说过ApplicationEventPublisher是通过委托给ApplicationEventMulticaster实现的,所以refresh方法中完成的是对ApplicationEventMulticaster的初始化:

代码语言:javascript
复制
// Initialize event multicaster for this context.
initApplicationEventMulticaster();

initApplicationEventMulticaster则首先在BeanFactory中寻找ApplicationEventMulticaster的bean,如果找到,那么调用getBean方法将其初始化,如果找不到那么使用SimpleApplicationEventMulticaster。

事件发布

AbstractApplicationContext.publishEvent核心代码:

代码语言:javascript
复制
protected void publishEvent(Object event, ResolvableType eventType) {
    getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}

SimpleApplicationEventMulticaster.multicastEvent:

代码语言:javascript
复制
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    invokeListener(listener, event);
                }
            });
        } else {
            invokeListener(listener, event);
        }
    }
}
监听器获取

获取当然还是通过beanFactory的getBean来完成的,值得注意的是Spring在此处使用了缓存(ConcurrentHashMap)来加速查找的过程。

同步/异步

可以看出,如果executor不为空,那么监听器的执行实际上是异步的。那么如何配置同步/异步呢?

全局
代码语言:javascript
复制
<task:executor id="multicasterExecutor" pool-size="3"/>
<bean class="org.springframework.context.event.SimpleApplicationEventMulticaster">
    <property name="taskExecutor" ref="multicasterExecutor"></property>
</bean>

task schema是Spring从3.0开始加入的,使我们可以不再依赖于Quartz实现定时任务,源码在org.springframework.core.task包下,使用需要引入schema:

代码语言:javascript
复制
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd"

可以参考: Spring定时任务的几种实现

注解

开启注解支持:

代码语言:javascript
复制
<!-- 开启@AspectJ AOP代理 -->  
<aop:aspectj-autoproxy proxy-target-class="true"/>  
<!-- 任务调度器 -->  
<task:scheduler id="scheduler" pool-size="10"/>  
<!-- 任务执行器 -->  
<task:executor id="executor" pool-size="10"/>  
<!--开启注解调度支持 @Async @Scheduled-->  
<task:annotation-driven executor="executor" scheduler="scheduler" proxy-target-class="true"/>  

在代码中使用示例:

代码语言:javascript
复制
@Component  
public class EmailRegisterListener implements ApplicationListener<RegisterEvent> {  
    @Async  
    @Override  
    public void onApplicationEvent(final RegisterEvent event) {  
        System.out.println("注册成功,发送确认邮件给:" + ((User)event.getSource()).getUsername());  
    }  
}  

参考: 详解Spring事件驱动模型

onRefresh

这又是一个模版方法,允许子类在进行bean初始化之前进行一些定制操作。默认空实现。

ApplicationListener注册

registerListeners方法干的,没什么好说的。

singleton初始化

finishBeanFactoryInitialization:

代码语言:javascript
复制
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    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));
    }
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
            @Override
            public String resolveStringValue(String strVal) {
                return getEnvironment().resolvePlaceholders(strVal);
            }
        });
    }
    String[] weaverAwareNames = beanFactory.getBeanNamesForType
        (LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }
    // Allow for caching all bean definition metadata, not expecting further changes.
    beanFactory.freezeConfiguration();
    // Instantiate all remaining (non-lazy-init) singletons.
    beanFactory.preInstantiateSingletons();
}

分部分说明。

ConversionService

此接口用于类型之间的转换,在Spring里其实就是把配置文件中的String转为其它类型,从3.0开始出现,目的和jdk的PropertyEditor接口是一样的,参考ConfigurableBeanFactory.setConversionService注释:

Specify a Spring 3.0 ConversionService to use for converting property values, as an alternative to JavaBeans PropertyEditors. @since 3.0

StringValueResolver

用于解析注解的值。接口只定义了一个方法:

代码语言:javascript
复制
String resolveStringValue(String strVal);
LoadTimeWeaverAware

实现了此接口的bean可以得到LoadTimeWeaver,此处仅仅初始化。

初始化

DefaultListableBeanFactory.preInstantiateSingletons:

代码语言:javascript
复制
@Override
public void preInstantiateSingletons() throws BeansException {
    List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX 
                    + beanName);
                boolean isEagerInit;
                if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                    isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                        @Override
                        public Boolean run() {
                            return ((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(new PrivilegedAction<Object>() {
                    @Override
                    public Object run() {
                        smartSingleton.afterSingletonsInstantiated();
                        return null;
                    }
                }, getAccessControlContext());
            }
            else {
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

首先进行Singleton的初始化,其中如果bean是FactoryBean类型(注意,只定义了factory-method属性的普通bean并不是FactoryBean),并且还是SmartFactoryBean类型,那么需要判断是否需要eagerInit(isEagerInit是此接口定义的方法)。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-09-30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • refresh
    • prepareRefresh
      • 属性校验
    • BeanFactory创建
      • BeanFactory接口
      • BeanFactory定制
      • Bean加载
      • 默认命名空间解析
      • 其它命名空间解析
    • prepareBeanFactory
      • BeanExpressionResolver
      • PropertyEditorRegistrar
      • 环境注入
      • 依赖解析忽略
      • bean伪装
      • LoadTimeWeaver
      • 注册环境
    • postProcessBeanFactory
      • invokeBeanFactoryPostProcessors
        • BeanPostProcessor注册
          • MessageSource
            • 事件驱动
              • 事件
              • 发布者
              • 监听器
              • 初始化
              • 事件发布
            • onRefresh
              • ApplicationListener注册
                • singleton初始化
                  • ConversionService
                  • StringValueResolver
                  • LoadTimeWeaverAware
                  • 初始化
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档