Spring IOC 源码解析(持续)

Spring框架外文文献、论文参考与Java源码深度解析 优势说明消除版本冲突所有starter共享同一版本基线简化依赖声明开发者只需关注“要什么”,而非“哪个版本”易于升级升级Spring Boot版本即同步更新所有子组件社区标准化形成统一的技术选型规范此外,Spring Boot还提供了与自动配置配合,实现“按需激活”。例如,仅当引入时才会触发,保证无冗余Bean加载。构建自定义Starter是高级开发者常见的需求,适用于封装公司内部中间件、通用工具包或特定业务模板。 阅读详情

Spring IOC 源码解析(持续)

如何查看源码

Spring源码下载https://github.com/spring-projects/spring-framework/tags?after=v3.1.0.RC1

eclipse关联源码 自己百度吧

源代码结构组织

Build-spring-framework是整个Spring源代码的构建目录,里面是项目的构建脚本,如果要自己动手构建Spring,可以进入这个目录使用ANT进行构建。

l  org.springframework.context是IoC容器的源代码目录

l  org.springframework.aop是AOP实现的源代码目录

l  org.springframework.jdbc是JDBC的源代码部分

l  org.springframework.orm是O/R Mapping对应的源代码实现部分

 

 

SpringIOC源码分析

IOC初始化

1、 XmlBeanFactory(屌丝IOC)的整个流程

2、 FileSystemXmlApplicationContext 的IOC容器流程

1、高富帅IOC解剖

2、 设置资源加载器和资源定位

3、AbstractApplicationContext的refresh函数载入Bean定义过程:

4、AbstractApplicationContext子类的refreshBeanFactory()方法:

5、AbstractRefreshableApplicationContext子类的loadBeanDefinitions方法:

6、AbstractBeanDefinitionReader读取Bean定义资源:

7、资源加载器获取要读入的资源:

8、XmlBeanDefinitionReader加载Bean定义资源:

9、DocumentLoader将Bean定义资源转换为Document对象:

10、XmlBeanDefinitionReader解析载入的Bean定义资源文件:

11、DefaultBeanDefinitionDocumentReader对Bean定义的Document对象解析:

12、BeanDefinitionParserDelegate解析Bean定义资源文件中的<Bean>元素:

13、BeanDefinitionParserDelegate解析<property>元素:

14、解析<property>元素的子元素:

15、解析<list>子元素:

16、解析过后的BeanDefinition在IoC容器中的注册:

17、DefaultListableBeanFactory向IoC容器注册解析后的BeanDefinition:

IOC体系

BeanFactory

         Spring Bean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用,其相互关系如下:

 

 

 

 

BeanFactory 

 BeanFactory定义了 IOC 容器的最基本形式,并提供了 IOC 容器应遵守的的最基本的接口,也就是Spring IOC 所遵守的最底层和最基本的编程规范。在  Spring 代码中, BeanFactory 只是个接口,并不是 IOC容器的具体实现,但是 Spring 容器给出了很多种实现,如 DefaultListableBeanFactory 、 XmlBeanFactory 、ApplicationContext 等,都是附加了某种功能的实现。

 

 大体思路是 反射+DOM4J, 解析配置文件,通过beanId查找bean是否存在

 存在的话,获取该节点class地址,使用反射机制初始化。

 Spring 使用了很多抽象类

 Spring核心jar包:

 SpringCore -- Spring 核心jar

 SpringContext--上下文IOC具体实现

 Spring-Bean --  Spring实例

 Spring-jdbc

 SpringAOP

 

BeanFactory接口: ctrl+T

 核心方法查看:Bean的工厂

定义接口去进行规范

public interface BeanFactory {
    //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,  
  //如果需要得到工厂本身,需要转义    
    //转义符“&”用来获取FactoryBean本身
    String FACTORY_BEAN_PREFIX = "&";
//根据bean的名字进行获取bean的实例,这是IOC最大的抽象方法
    Object getBean(String name) throws BeansException;
//根据bean的名字和Class类型进行获取Bean的实例,和上面方法不同的是,bean名字和Bean 的class类型不同时候会爆出异常
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
//检测这个IOC容器中是否含有这个Bean
boolean containsBean(String name);
//判断这个Bean是不是单利

    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//判断这个Bean是不是原型
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//查询指定的bean的名字和Class类型是不是指定的Class类型
    boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;
//这里对得到bean实例的Class类型
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来 
    String[] getAliases(String name);
}

 

 

BeanDefinition 

这个接口,可以理解为xml bean元素的数据载体。通过对比xml bean标签的属性列表和BeanDefinition的属性列表一看便知。
我的理解,是解析XML的过程,就是 xml <bean>元素内容 转换为BeanDefinition对象的过程。而且这个接口,支持层级,对应对象的继承。
有一个类BeanDefinitionHolder,BeanDefinitionHolder,根据名称或者别名持有beanDefinition,它承载了name和BeanDefinition的映射信息。
BeanWarpper:
提供对标准javabean的分析和操作方法:单个或者批量获取和设置属性值,获取属性描述符,查询属性的可读性和可写性等。支持属性的嵌套设置,深度没有限制。
AbstractRefreshableApplicationContext的refreshBeanFactory()这个方法

核心类:

 

 

 

 核心方法:

 

 这个接口主要做xml解析的

   封装xml解析Spring Bean文件的解析封装 (可以get出来个Bean属性哈哈)

   方法: 

一:

/**
     * Return the current bean class name of this bean definition.
     * <p>Note that this does not have to be the actual class name used at runtime, in
     * case of a child definition overriding/inheriting the class name from its parent.
     * Also, this may just be the class that a factory method is called on, or it may
     * even be empty in case of a factory bean reference that a method is called on.
     * Hence, do <i>not</i> consider this to be the definitive bean type at runtime but
     * rather only use it for parsing purposes at the individual bean definition level.
     * @see #getParentName()
     * @see #getFactoryBeanName()
     * @see #getFactoryMethodName()
     */
    @Nullable
    String getBeanClassName();

 

获取bean的class文件地址  id = xx  class=“”com.tooc5.car“

 

二:

/**
* Override the target scope of this bean, specifying a new scope name.
* @see #SCOPE_SINGLETON
* @see #SCOPE_PROTOTYPE
*/
void setScope(@Nullable String scope);

 xml的配置的范围属性

 

 

分析看一个类: 分析要分析父类 一直追踪。核心的都封装在父类

点击进入这个抽象类 AbstractRefreshableApplicationContext

 

看它的方法:refreshBeanFactory()

protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();//创建IOC容器(Bean工厂)!!!!!!
            beanFactory.setSerializationId(getId()); 
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);    //载入loadBeanDefinitions  直接把工厂传入进去了
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

 点进入看:

 loadBeanDefinitions(beanFactory); 

实现类:
@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.
        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);   
    }

继续点进去看:

loadBeanDefinitions(beanDefinitionReader);    加载配置文件
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        String[] configLocations = getConfigLocations();  //数组形式 可以加载多个配置文件
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

持续点击: 

 reader.loadBeanDefinitions(configLocations);   
    @Override
    public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {  //可以传递多个路径进入
        Assert.notNull(locations, "Location array must not be null");
        int count = 0;
        for (String location : locations) {
            count += loadBeanDefinitions(location);
        }
        return count;
    }

 

持续点击:

loadBeanDefinitions(location);
循环读取配置文件
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}

持续点击:

loadBeanDefinitions(location, null);
 
/**
     * Load bean definitions from the specified resource location.
     * <p>The location can also be a location pattern, provided that the
     * ResourceLoader of this bean definition reader is a ResourcePatternResolver.
     * @param location the resource location, to be loaded with the ResourceLoader
     * (or ResourcePatternResolver) of this bean definition reader
     * @param actualResources a Set to be filled with the actual Resource objects
     * that have been resolved during the loading process. May be {@code null}
     * to indicate that the caller is not interested in those Resource objects.
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of loading or parsing errors
     * @see #getResourceLoader()
     * @see #loadBeanDefinitions(org.springframework.core.io.Resource)
     * @see #loadBeanDefinitions(org.springframework.core.io.Resource[])
     */
    public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();   //获取到当配置路径
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        }

        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            try {
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                int count = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    Collections.addAll(actualResources, resources);
                }
                if (logger.isTraceEnabled()) {
                    logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
                }
                return count;
            }
            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 count = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
            }
            return count;
        }
    }

拿到resource后继续读取,点击

int count = loadBeanDefinitions(resource);

点击xml的 不是配置 文件的

    /**
     * Load bean definitions from the specified XML file.
     * @param resource the resource descriptor for the XML file
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of loading or parsing errors
     */
    @Override
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(new EncodedResource(resource));
    }

持续点击:

 return loadBeanDefinitions(new EncodedResource(resource));
    /**
     * Load bean definitions from the specified XML file.
     * @param encodedResource the resource descriptor for the XML file,
     * allowing to specify an encoding to use for parsing the file
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of loading or parsing errors
     */
    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isTraceEnabled()) {
            logger.trace("Loading XML bean definitions from " + encodedResource);
        }

        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
            InputStream inputStream = encodedResource.getResource().getInputStream();  //拿到input流
            try {
                InputSource inputSource = new InputSource(inputStream);  //读取input流
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());  //进行转码
                }
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

 

拿到文件流之后? 持续点击
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {

        try {  //XML的DOM4J解析
            Document doc = doLoadDocument(inputSource, resource);
            int count = registerBeanDefinitions(doc, resource);
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }
如何解析的?持续点击:
/**
     * Actually load bean definitions from the specified XML file.
     * @param inputSource the SAX InputSource to read from
     * @param resource the resource descriptor for the XML file
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of loading or parsing errors
     * @see #doLoadDocument
     * @see #registerBeanDefinitions
     */
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {

        try {
            Document doc = doLoadDocument(inputSource, resource);  //解析出doc
            int count = registerBeanDefinitions(doc, resource);    //注册bean
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }

拿到:doc 和 resource后,注册bean:持续点击

 int count = registerBeanDefinitions(doc, resource); 
 
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // 作bean的注册
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

 

持续点击:
documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 
    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        doRegisterBeanDefinitions(doc.getDocumentElement());
    }

继续点击进入: 从根目录获取到配置文件document。拿到根路径后正式做解析。

    /**
     * Register each bean definition within the given root {@code <beans/>} element.
     */
    @SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
    protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }

        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);  //做documet解析
        postProcessXml(root);

        this.delegate = parent;
    }

 

持续点击:
  parseBeanDefinitions(root, this.delegate);  //做documet解析  从根路径开始解析 遍历节点 
/**
     * Parse the elements at the root level in the document:
     * "import", "alias", "bean".
     * @param root the DOM root element of the document
     */
    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);
        }
    }

持续点击进入默认解析:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {    // input解析
            importBeanDefinitionResource(ele);
        }
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {  //别名解析
            processAliasRegistration(ele);
        }
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {    //解析beans
            processBeanDefinition(ele, delegate);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {  
            // recurse
            doRegisterBeanDefinitions(ele);
        }
    }

持续查看解析bean: 

 processAliasRegistration(ele);
    /**
     * Process the given bean element, parsing the bean definition
     * and registering it with the registry.
     */
    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));
        }
    }

 

可以持续点击查看这里
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 
/**
     * Register the given bean definition with the given bean factory.
     * @param definitionHolder the bean definition including name and aliases
     * @param registry the bean factory to register with
     * @throws BeanDefinitionStoreException if registration failed
     */
    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());  //beanName beanId的名称 
 
        // Register aliases for bean name, if any.
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }
beanName beanId的名称 是通过
   String beanName = definitionHolder.getBeanName();
获取的:点击查看 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

@Nullable
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        String id = ele.getAttribute(ID_ATTRIBUTE);   //解析 id
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);  // 解析 name

        List<String> aliases = new ArrayList<>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;    //通过beanId 找
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            beanName = aliases.remove(0);
            if (logger.isTraceEnabled()) {
                logger.trace("No XML 'id' specified - using '" + beanName +
                        "' as bean name and " + aliases + " as aliases");
            }
        }

        if (containingBean == null) {
            checkNameUniqueness(beanName, aliases, ele);
        }

        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        // Register an alias for the plain bean class name, if still possible,
                        // if the generator returned the class name plus a suffix.
                        // This is expected for Spring 1.2/2.0 backwards compatibility.
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }
                    if (logger.isTraceEnabled()) {
                        logger.trace("Neither XML 'id' nor 'name' specified - " +
                                "using generated bean name [" + beanName + "]");
                    }
                }
                catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }

 

回退 查看注册的代码,持续点击进入:
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
/**
     * Register the given bean definition with the given bean factory.
     * @param definitionHolder the bean definition including name and aliases
     * @param registry the bean factory to register with
     * @throws BeanDefinitionStoreException if registration failed
     */
    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // 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);
            }
        }
    }

重点点击:

好几种注册方式:

选择一种:

@Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "'beanName' must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

 

下面插入一段反射代码:

从这里点击进入:

 

 点击:

 

 持续点击进入:

持续点击:

 

 

@Nullable
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        String id = ele.getAttribute(ID_ATTRIBUTE);
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        List<String> aliases = new ArrayList<>();
        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()) {
            beanName = aliases.remove(0);
            if (logger.isTraceEnabled()) {
                logger.trace("No XML 'id' specified - using '" + beanName +
                        "' as bean name and " + aliases + " as aliases");
            }
        }

        if (containingBean == null) {
            checkNameUniqueness(beanName, aliases, ele);
        }

        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  //正式开始注册!!!!!!
        if (beanDefinition != null) {
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        // Register an alias for the plain bean class name, if still possible,
                        // if the generator returned the class name plus a suffix.
                        // This is expected for Spring 1.2/2.0 backwards compatibility.
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }
                    if (logger.isTraceEnabled()) {
                        logger.trace("Neither XML 'id' nor 'name' specified - " +
                                "using generated bean name [" + beanName + "]");
                    }
                }
                catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }

 

持续点击关键代码 注册bean:
核心代码:

持续点击:

持续点击:

public static AbstractBeanDefinition createBeanDefinition(
            @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setParentName(parentName);
        if (className != null) {
            if (classLoader != null) {
                bd.setBeanClass(ClassUtils.forName(className, classLoader));   //反射机制初始化bean!
            }
            else {
                bd.setBeanClassName(className);
            }
        }
        return bd;
    }

 

注意啊 不要点击classPatxXmlApplicationContext  里面没有! 核心 在父类!


  很多方法写成了一个类 ,一层一个类。看起类是挺不爽的,下伙伴耐心看昂。

 

 

 

 

 

 

 

  可以参考:

https://www.cnblogs.com/ITtangtang/p/3978349.html

 

posted @ 2019-04-14 21:39 toov5 阅读(...) 评论(...) 编辑 收藏

Spring Framework 3.2源码深度解析与Gradle编译实战 Spring Framework 3.2奠定了现代Java企业级开发的基石,其核心特性围绕控制反转(IoC)面向切面编程(AOP)声明式事务管理和Web MVC架构四大支柱展开。该版本采用模块化设计,分为spring-aopspring-web等子模块,各模块职责清晰且高度内聚。// 典型IoC配置示例(XML)</bean>上述配置体现了Spring 3.2对XML与注解双模式的支持:既可通过<bean>定义组件,也可使用@Component。 阅读详情

相关推荐

aistudio高效解压zip文件的实用技巧

本文详细介绍了在百度AI Studio平台上高效解压ZIP文件的实用技巧。针对深度学习项目数据准备中的常见痛点,重点讲解了使用Python zipfile库和Linux unzip命令两种核心方法,并提供了路径设置、大文件处理、中文乱码等关键问题的解决方案,帮助用户提升数据处理效率。

salt的博客 784

聊聊最近撸Spring源码感悟

聊聊最近撸Spring源码感悟 一、前言 最近一段时间撸了Spring IOC、AOP、Transactional源码,这篇文章聊聊我写了哪些小玩意,这可能就是阅读源码以后最大收获。希望大家在里面能学习一些什么东西吧; 二、Spring IOC简单实现 第一步首先看一下配置文件,配置文件模拟Spring Bean注入时候的样子,少了XML验证头的一些东西; View Code 第二步是实体类; View Code 第三步也是最重要的一步,实现从配置中解析文件,然后通过反射创建Student对象,解析配置

m0_58478980的博客 240

瑞萨芯片串口配置,基于RL78芯片的串口使用配置

在这里隆重给大家介绍瑞萨编辑器CS+ for CA 的自动生成代码功能,只需要配置几个参数,就可以得到你想要的串口配置了,我现在已经忘记怎么手动配置寄存器了,哈哈。选择设置,此时将端口设置成功接下来设置时钟,根据自己的芯片所需设置相应的时钟,自己芯片是什么时钟查看数据手册和原理图可以找到。瑞萨芯片的串口配置其实和ST芯片的串口配置差不多,只是ST芯片的中文数据手册比较多,就更好配置了,找到所需要的串口配置IO口,此时将UART0 配置为引脚P61和P62,瑞萨芯片的串口配置竟然要配置串口。

qq_45315904的博客 4302

美团二面问源码卒!闭门偷学318页Spring深度手册,再战

Spring 框架 作为 Spring 家族的核心,主要就两个核心功能,控制翻转(IOC)和面向切面编程(AOP)。那你知道 Spring 中是怎么实现的吗?想不想一探 Spring 核心奥秘呢?这个模块手把手搭建一个不依赖 Spring 但可以实现和 Spring 一样的 IOC 和 AOP 的核心功能的 Demo。通过这个 Demo 让我们对 Spring 核心源码有清晰的认识,以便大家更轻松的阅读源码。IT 技术发展太快了,就像浪潮一样一波接着一波,朝你迎面扑来,稍不留神就会被巨浪卷至海底而不得翻身。

m0_73311735的博客 70

51单片机——LCD12864驱动函数深度解析与实战优化

本文深入解析了51单片机驱动LCD12864液晶屏的核心驱动函数,从底层时序、关键延时到地址计算进行逐行剖析,并针对常见显示问题提供系统性的调试技巧与实战优化方案。重点探讨了如何将基础代码优化为稳定高效的驱动,涵盖延时精准化、批量写入及显示缓冲区等高级技巧,旨在帮助开发者从“点亮”屏幕进阶到“精通”驱动,确保显示稳定可靠。

weixin_29190169的博客 85

裸眼3D技术发展与应用前景

这项技术利用传感器或摄像头实时监测观众的位置和视角,然后根据观众的位置信息动态调整投射的图像,确保不同位置的观众都能看到一致的3D效果。这种技术不仅可以在电影院和家庭影院中应用,还可以用于虚拟现实设备和大型展览等领域。裸眼3D呈现是一种不需要佩戴任何特殊设备(如3D眼镜或头盔)即可观看到3D效果的技术。这种技术近年来得到了快速发展,为观众带来了更加沉浸式的视觉体验。总之,裸眼3D呈现技术的发展为观众带来了更加真实、沉浸式的视觉体验。随着技术的不断进步和创新,相信未来裸眼3D将会在更多领域得到应用和推广。

学无止境 1999

Spring源码分析:全集整理

本文是Spring源码分析系列文章的目录整理,主要基于《Spring源码深度解析》的学习记录。内容涵盖Spring核心功能源码分析、衍生技术解析及补充知识点,包括IOC容器、AOP实现、事务管理、Spring MVC等核心模块的源码解读。文章持续更新中,目前已包含25篇源码分析、13篇衍生技术探讨以及3篇补充内容,并附有Mybatis源码分析链接。作者在2021年期间持续更新,后期因技术沉淀需要暂停写作。

猫吻鱼的博客 5万+

Simulink仿真模块 - Data Type Conversion

Data Type Conversion将输入信号转换为指定的数据类型 在仿真库中的位置为: Simulink / 常用模块 Simulink / Signal Attributes 模型为: 说明 DataTypeConversion模块可将任何 Simulink®数据类型的输入信号转换为您指定的数据类型。 注意 要通过指定模块参数来控制输出数据类型,或者要从下游模块继承数据类型,使用DataTypeConversion模块。要...

jk_101的博客 2520

手撕Spring底层系列之:IOC、AOP

优秀的框架设计,往往是把复杂留给自己,把简单留给使用者。Spring的成功正是这一理念的完美实践——通过IoC容器标准化对象生命周期,通过AOP解耦横切关注点,最终实现开发效率的质的飞跃。IoC的本质是管理权转移:将对象的控制权从程序员手中移交至容器,通过三级缓存等精妙设计解决工程难题AOP的根基是代理模式:动态代理技术使非侵入式功能扩展成为可能,JDK与CGLIB的互补成就了Spring的灵活性手写轮子的终极意义。

Rqaqedamancy的博客 1万+

基于深度学习的水质预测:多参数监测与预测

在本篇博客中,我们详细介绍了如何使用深度学习技术处理水质预测问题,包括数据集的准备与预处理、多层感知机模型的构建、模型的训练与评估以及模型优化策略。我们使用 Python 语言基于 TensorFlow 和 Keras 框架实现了模型,并给出了各种模型优化方法及对应代码。通过实践,我们可以发现深度学习技术在水质预测方面具有很好的应用潜力。在实际应用中,我们还可以根据具体问题和数据集进一步调整和优化模型,以获得更好的预测性能。

斌擎科技 1081

Open3D 基于法线的双边滤波

基于法线的双边滤波是一种用于点云平滑的技术,它结合了点与其邻域点之间的几何距离和法线方向的相似性,从而在去除噪声的同时保留几何特征。这种滤波方法广泛应用于点云处理领域,尤其是在需要保留表面细节和边缘的场景中。

纵马踏花向自由 2500

专治你不会看源码的毛病---源码解读Spring IOC原理

点关注,不迷路;持续更新Java相关技术及资讯!!! 你不点个赞吗~~~ 本文本文乃学习\整理参考的 一、什么是IOC/DI? IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等等。 先从我们自己设计这样一个视角来考虑: 所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象...

XingXing_Java的博客 3917

Open3D——平面点云凸多边形轮廓提取【2025最新版】

平面点云凸多边形轮廓提起,博客长期更新,本文最近更新时间为:2025年1月6日。

点云侠的博客 6753

一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程)

前言 1、博客内容均出自于咕泡学院架构师第三期 2、本章内容共分为三部分 第一部分:一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 第二部分:一步一步手绘Spring IOC运行时序图二(基于XML的IOC容器初始化) 第三部分:一步一步手绘Spring IOC运行时序图三(基于Annotation的IOC容器初始化) 1、Spring 核心之 IOC 容器初体验 IOC 与 DI IOC(Inversion of Control )控制反转:所谓控制反转,就是

Jarvis.y的博客 1369

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

spring源码注释_Spring IoC:源码总览

前言Spring 作为现在最优秀的框架之一,被广泛的应用于 Java 项目中,但是大多数人都只知道如何使用,而不知其中的原理。对大多数人来说可能知道如何使用已经足够了,但是对于想提升自己的人来说,学习 Spring 的源码是一个不错的选择。在过去的几个月里,我利用空闲时间将 IoC 的相关源码学习了一下,按照老习惯准备整理成笔记,以博文的形式记录下来,供自己以后使用,也供其他网友参考。由于涉及到的...

weixin_39837352的博客 226

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

spring源码学习-前戏- 如何从源码来看什么是IOC容器

之前一直想要找到一个学习spring源码的主线。看了《spring源码深度解析》这本书,效果不是很好,没有得到我想得到的。最终还是借助《spring技术内幕》这本书,抽丝剥茧,打开了思路。 我换一种方式来学习spring源码,走一个不一样的spring源码学习方式——从“农村包围城市”。 先理解里边的关键点,然后逐一击破,走一个星星之火可以燎原的学习道路。 不一样的spring源码学习方式——从“农村包围城市”。我把IOC作为学习spring源码的切入点。 采用归一的方法,不妨问题化简为繁,先不要.

Angus 366

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Spring源码深度解析,Spring源码核心技术,IOC,Bean, (二)(附代码示例:)

二.Spring的核心技术 目录 二.Spring的核心技术 一,IOC 容器 2.1.1,代码示例:在没有 Spring的管理下 2.1.2,示例代码:在 Spring 的管理下 二,容器概述 三 ,配置元数据 四,实例化容器 2.4.1示例代码 五,Bean 概述 2.5.1,Bean的创建 2.5.2,Bean 的实例化 2.5.3,B...

Crazy_Cw的博客 1309

Java-35 深入浅出 Spring - IoC容器体系 Bean源码 断点分析 IoC容器实例化分析

创建 IoC 容器之后,容器会加载 Bean 定义,这些定义通常是通过配置文件(XML 配置文件或注解)提供的。容器会解析这些配置,加载所有 Bean 的元数据。Spring 支持 XML 配置文件、注解配置以及 Java 配置类的方式。XML 配置:解析 XML 文件中的 标签,获取 Bean 的名称、类型、属性、构造函数参数等信息。注解配置:通过扫描指定的包或类,查找如 @Component、@Service、@Repository、@Configuration 等注解标记的类。

谢谢你的喜欢 我们一起无限进步 5274

了解spring中的ioc

大型分布式系统犹如一个生命,系统中各个服务犹如骨骼,其中的数据犹如血液,而Kafka犹如经络,串联整个系统。这份Kafka源码笔记通过大量的设计图展示、代码分析、示例分享,把Kafka的实现脉络展示在读者面前,帮助读者更好地研读Kafka代码。麻烦帮忙转发一下这篇文章+关注我《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

2401_84010762的博客 986

你要的《Spring系列源码解读》PDF它来了

作者:z小赵★一枚用心坚持写原创的“无趣”程序猿,在自身受益的同时也让朋友们在技术上有所提升。出 PDF 版的初衷一周多没有更新文章了,读者朋友们可能会怀疑我在偷懒;是的,我摊牌了...

ShiLuoHeroKing的博客 515

Spring 之Srping IOC运行时序图

加载XML文件——创建IOC容器时序图 源码理解 首先需要找到入口。IOC容器初始化运行的入口。 回顾 什么是SpringIOC IOC(Inversion Of Control)控制反转,所谓控制反转,就是把我们代码中需要实现的对象的创建、依赖。反转给容器来实现。同时需要一种描述让容器知道需要创建的对象和对象之间的关系。即配置文件。 寻找源码入口 1.关于BeanFactory...

记录成长的过程 2335

源码解析:Spring源码解析笔记 目录

本文由colodoo(纸伞)整理 QQ 425343603 最近心血来潮,有阅读Spirng源码的想法并记录,计划是1个月内完成完整Spring核心逻辑的阅读,对后面自己封装框架或者各位面试的时候可能遇到的一些关于Spring的问题,都可以作为参考。 如果你对本文章后续感兴趣的话,可以加群一起学习和进步! Java学习交流群(717726984) 目录 源码解析:Spring源码解析笔记(一)基本概念 源码解析:Spring源码解析笔记(二)启动过程(上) 源码解析:Spring源码解析笔记(三).

全栈纸伞 366

Spring IOC源码笔记(二)

一、IOC初始化流程图解:(后续会补充) https://www.processon.com/view/link/5ed5c93e6376896c9ad2b614 二、BeanPostProcessor 的注册 入口refresh()的registerBeanPostProcessors(beanFactory);这个方法里面。 拿到BeanFactory中所有注册的BeanDefinition对象的名称beanName。 然后判断是否实现了PriorityOrdered排序接口.

你能找到这里,说明你有经天纬地之才,扭转乾坤只能,鬼神不测之计包藏宇宙之志,真乃乱世之枭雄,治世之能臣也 224

深度解析Spring IoC容器初始化:ApplicationContext的refresh()流程拆解

在Java企业级开发领域,Spring框架始终保持着不可撼动的统治地位。截至2025年,Spring Framework 6.x系列已成为主流版本,其核心设计理念"控制反转"(Inversion of Control,IoC)依然是理解整个框架架构的关键切入点。

zuiyuelong的博客 992

每天一遍、阿里相见,Github爆火的spring高级源码解析免费下载

面试前一定少不了刷题,为了方便大家复习,我分享一波个人整理的面试大全宝典Java核心知识整理Java核心知识Spring全家桶(实战系列)其他电子书资料Step3:刷题既然是要面试,那么就少不了刷题,实际上春节回家后,哪儿也去不了,我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。以下是我私藏的面试题库:《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》

H1767410的博客 669
上一篇: Spring mvc异步处理
下一篇: 责任链设计模式
Art&Code
博客等级 码龄7年 77粉丝 554原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值