>  기사  >  Java  >  Spring-IOC 컨테이너 소개(코드 포함)

Spring-IOC 컨테이너 소개(코드 포함)

不言
不言앞으로
2019-03-27 10:42:122232검색

이 기사는 Spring-IOC 컨테이너(코드 포함)에 대한 소개를 제공합니다. 이는 특정 참조 가치가 있으므로 도움이 될 수 있습니다.

Spring IoC 컨테이너에 의한 Bean 정의 리소스 로드는 새로 고침() 함수에서 시작됩니다. 새로 고침() 메서드의 기능은 다음과 같습니다. 컨테이너가 이미 존재하는 경우 , 그런 다음 새로 설정된 IoC 컨테이너가 새로 고침 후에 사용되도록 하려면 기존 컨테이너를 삭제하고 닫아야 합니다. 새로 고침 기능은 IoC 컨테이너를 다시 시작하는 것과 유사합니다. 새로 생성된 컨테이너에서 컨테이너를 초기화하고 Bean 정의 리소스를 로드합니다.

public void refresh() throws BeansException, IllegalStateException {
       Object var1 = this.startupShutdownMonitor;
       synchronized(this.startupShutdownMonitor) {
           //调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
           this.prepareRefresh();
           //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从  
           //子类的refreshBeanFactory()方法启动 
           //这个bean的载入过程 包括对xml的解析和加载为BeanDefinitions 都是从this.obtainFreshBeanFactory()这里进入
           ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
           /*这之后的代码都是注册容器的信息源和生命周期事件*/
           //为BeanFactory配置容器特性,例如类加载器、事件处理器等
           this.prepareBeanFactory(beanFactory);

           try {
               //为容器的某些子类指定特殊的BeanPost事件处理器
               this.postProcessBeanFactory(beanFactory);
               //调用所有注册的BeanFactoryPostProcessor的Bean
               this.invokeBeanFactoryPostProcessors(beanFactory);
               //为BeanFactory注册BeanPost事件处理器.  
               //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件 
               this.registerBeanPostProcessors(beanFactory);
               //初始化信息源,和国际化相关.
               this.initMessageSource();
               //初始化容器事件传播器.
               this.initApplicationEventMulticaster();
               //调用子类的某些特殊Bean初始化方法
               this.onRefresh();
               //为事件传播器注册事件监听器. 
               this.registerListeners();
               //初始化所有剩余的单态Bean.
               this.finishBeanFactoryInitialization(beanFactory);
               //初始化容器的生命周期事件处理器,并发布容器的生命周期事件
               this.finishRefresh();
           } catch (BeansException var9) {
               if (this.logger.isWarnEnabled()) {
                   this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
               }
               //销毁以创建的单态Bean
               this.destroyBeans();
               //取消refresh操作,重置容器的同步标识.
               this.cancelRefresh(var9);
               throw var9;
           } finally {
               this.resetCommonCaches();
           }

       }
   }

AbstractRefreshableApplicationContext 클래스:
AbstractRefreshableApplicationContext는 실제로 컨테이너에서 호출되는 추상 loadBeanDefinitions 메서드만 정의합니다. . 은 하위 클래스 AbstractXmlApplicationContext

protected final void refreshBeanFactory() throws BeansException {
        //如果已经创建了BeanFactory,则销毁并关闭BeanFactory
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
             //创建了一个IOC容器
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            /对IoC容器进行定制化,如设置启动参数,开启注解的自动装配等
            this.customizeBeanFactory(beanFactory);
            //调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
            this.loadBeanDefinitions(beanFactory);
            Object var2 = this.beanFactoryMonitor;
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

AbstractXmlApplicationContext 클래스에 의해 이 메소드를 구현한 것입니다.

 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        //创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源  
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
         //为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的  
        //祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器
        beanDefinitionReader.setResourceLoader(this);
        //为Bean读取器设置SAX xml解析器 
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        //当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制  
        this.initBeanDefinitionReader(beanDefinitionReader);
        //Bean读取器真正实现加载的方法
        this.loadBeanDefinitions(beanDefinitionReader);
    }
    
    protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
        reader.setValidating(this.validating);
    }

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = this.getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }

        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }

    }

    @Nullable
    protected Resource[] getConfigResources() {
        return null;
    }

로드 프로세스는 추상 상위 클래스 AbstractBeanDefinitionReader

 public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        //获取resourceLoader
        ResourceLoader resourceLoader = this.getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
            int loadCount;
            if (!(resourceLoader instanceof ResourcePatternResolver)) {
                //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
                //加载多个指定位置的Bean定义资源文件 完成具体的资源定位的工作               
                Resource resource = resourceLoader.getResource(location);
                //加载资源 开始我们的第二步操作 转换为BeanDefinition对象
                loadCount = this.loadBeanDefinitions((Resource)resource);
                if (actualResources != null) {
                    actualResources.add(resource);
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
                }

                return loadCount;
            } else {
                try {
                   //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
                   //加载单个指定位置的Bean定义资源文件  
                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
                    //加载资源 开始我们的第二步操作 转换为BeanDefinition对象
                    loadCount = this.loadBeanDefinitions(resources);
                    if (actualResources != null) {
                        Resource[] var6 = resources;
                        int var7 = resources.length;

                        for(int var8 = 0; var8 < var7; ++var8) {
                            Resource resource = var6[var8];
                            actualResources.add(resource);
                        }
                    }

                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                    }

                    return loadCount;
                } catch (IOException var10) {
                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
                }
            }
        }
    }

리소스를 로드하는 특정 메소드
먼저 리소스 로더를 호출하여 리소스를 얻습니다. 메소드 resourceLoader.getResource(location), 로드할 리소스를 가져옵니다.
두 번째로, XmlBeanDefinitionReader 하위 클래스의 loadBeanDefinitions 메서드는 실제로 로딩 기능을 수행합니다.
리소스 위치 지정은 여기서 끝납니다. 최종적으로 반환되는 것은 BeanDefinition을 로드하기 위한 Resource 객체입니다. 위치 지정이 완료된 후 BeanDefinition에 대한 Maker I/O 조건이 로드되지만
특정 로드는 아직 시작되지 않았습니다.

public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");
        Iterator var2 = this.protocolResolvers.iterator();

        Resource resource;
        do {
            if (!var2.hasNext()) {
               //处理/开头的定位
                if (location.startsWith("/")) {
                    return this.getResourceByPath(location);
                }
                //带有classpath标识的Resource
                if (location.startsWith("classpath:")) {
                    return new ClassPathResource(location.substring("classpath:".length()), this.getClassLoader());
                }

                try {
                //处理URL标识的Resource定位
                    URL url = new URL(location);
                    return (Resource)(ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
                } catch (MalformedURLException var5) {
                    //如果不存classpath、Url、/标志的 就教给他处理
                    return this.getResourceByPath(location);
                }
            }

            ProtocolResolver protocolResolver = (ProtocolResolver)var2.next();
            resource = protocolResolver.resolve(location, this);
        } while(resource == null);

        return resource;
    }
protected Resource getResourceByPath(String path) {    
   if (path != null && path.startsWith("/")) {    
        path = path.substring(1);    
    }  
    //这里使用文件系统资源对象来定义bean 文件
    return new FileSystemResource(path);  
}

BeanDefinition의 로딩은 두 부분으로 나누어집니다. 먼저 XML 파서를 통해 문서 객체를 얻습니다. 그러나
이 문서 객체는 Spring의 Bean 규칙에 따라 구문 분석되지 않습니다. XML 구문 분석이 완료된 후 Spring의 Bean 규칙에 따라 구문 분석됩니다. 이 구문 분석 프로세스는 documentReader에서 구현됩니다.

 public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        //获取resourceLoader
        ResourceLoader resourceLoader = this.getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
            int loadCount;
            if (!(resourceLoader instanceof ResourcePatternResolver)) {
                //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
                //加载多个指定位置的Bean定义资源文件 完成具体的资源定位的工作               
                Resource resource = resourceLoader.getResource(location);
 
                //加载资源 开始我们的第二步操作 转换为BeanDefinition对象
                loadCount = this.loadBeanDefinitions((Resource)resource);
                if (actualResources != null) {
                    actualResources.add(resource);
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
                }

                return loadCount;
            } else {
                try {
                   //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
                   //加载单个指定位置的Bean定义资源文件  
                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
                    //加载资源 开始我们的第二步操作 转换为BeanDefinition对象
                    loadCount = this.loadBeanDefinitions(resources);
                    if (actualResources != null) {
                        Resource[] var6 = resources;
                        int var7 = resources.length;

                        for(int var8 = 0; var8 < var7; ++var8) {
                            Resource resource = var6[var8];
                            actualResources.add(resource);
                        }
                    }

                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                    }

                    return loadCount;
                } catch (IOException var10) {
                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
                }
            }
        }
    }

xml 파일을 문서 객체로 변환한 후 BeanDefinition을 구문 분석합니다.
Bean 정의 리소스 파일을 XML 형식으로 로드하는 방법은 다음과 같습니다.

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if(this.logger.isInfoEnabled()) {
            this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if(currentResources == null) {
            currentResources = new HashSet(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }

        if(!((Set)currentResources).add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var5;
            try {
                //将资源文件转为InputStream的IO流
                InputStream inputStream = encodedResource.getResource().getInputStream();

                try {
                    //从InputStream中得到XML的解析源
                    InputSource inputSource = new InputSource(inputStream);
                    if(encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                     //这里是具体的读取过程
                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {
                    //IO流的关闭
                    inputStream.close();
                }
            } catch (IOException var15) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
            } finally {
                ((Set)currentResources).remove(encodedResource);
                if(((Set)currentResources).isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }

            }

            return var5;
        }
    }
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
            //@1将XML文件转换为DOM对象,解析过程由documentLoader实现
            Document doc = this.doLoadDocument(inputSource, resource);
            //@2这里是启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean配置规则
            return this.registerBeanDefinitions(doc, resource);
        } catch (BeanDefinitionStoreException var4) {
            throw var4;
        } catch (SAXParseException var5) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
        } catch (SAXException var6) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
        } catch (ParserConfigurationException var7) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
        } catch (IOException var8) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
        } catch (Throwable var9) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
        }
    }

@1

//使用标准的JAXP将载入的Bean定义资源转换成document对象
 public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
        //创建文件解析器工厂 
        DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);
        if(logger.isDebugEnabled()) {
            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        //创建文档解析器  
        DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);
        //解析Spring的Bean定义资源
        return builder.parse(inputSource);
    }

    protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException {
     //创建文档解析工厂
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(namespaceAware);
        if(validationMode != 0) {
           //设置解析XML的校验 
            factory.setValidating(true);
            if(validationMode == 3) {
                factory.setNamespaceAware(true);

                try {
                    factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
                } catch (IllegalArgumentException var6) {
                    ParserConfigurationException pcex = new ParserConfigurationException("Unable to validate using XSD: Your JAXP provider [" + factory + "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
                    pcex.initCause(var6);
                    throw pcex;
                }
            }
        }

        return factory;
    }

Spring IoC 컨테이너는 Bean을 로드하고 읽고 변환합니다. 위치에 따른 정의 리소스 파일 Document 객체가 되는 과정이 완료됩니다.

다음은 Spring IoC 컨테이너가 로드된 Bean 정의 리소스 파일을 Document 객체로 변환한 다음 이를 Spring IoC 관리 Bean 객체로 구문 분석하여 컨테이너에 등록하는 방법입니다.
@2

 //按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构
 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        /得到BeanDefinitionDocumentReader来对xml格式的BeanDefinition解析 
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
        //获得容器中注册的Bean数量
        int countBefore = this.getRegistry().getBeanDefinitionCount();
        //解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口
        //具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成
        //@1
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        /统计解析的Bean数量 
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }
    //创建BeanDefinitionDocumentReader对象,解析Document对象
    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
        return (BeanDefinitionDocumentReader)BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
    }

DefaultBeanDefinitionDocumentReader가 문서를 구문 분석하는 객체 Spring Bean
@1

 public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
    public static final String BEAN_ELEMENT = "bean";
    public static final String NESTED_BEANS_ELEMENT = "beans";
    public static final String ALIAS_ELEMENT = "alias";
    public static final String NAME_ATTRIBUTE = "name";
    public static final String ALIAS_ATTRIBUTE = "alias";
    public static final String IMPORT_ELEMENT = "import";
    public static final String RESOURCE_ATTRIBUTE = "resource";
    public static final String PROFILE_ATTRIBUTE = "profile";
    protected final Log logger = LogFactory.getLog(this.getClass());
    private XmlReaderContext readerContext;
    private BeanDefinitionParserDelegate delegate;

    public DefaultBeanDefinitionDocumentReader() {
    }
    //根据Spring DTD对Bean的定义规则解析Bean定义Document对象 
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        //获得XML描述符 
        this.readerContext = readerContext;
        this.logger.debug("Loading bean definitions");
        //获得Document的根元素 
        Element root = doc.getDocumentElement();
        this.doRegisterBeanDefinitions(root);
    }

    protected final XmlReaderContext getReaderContext() {
        return this.readerContext;
    }

    protected Object extractSource(Element ele) {
        return this.getReaderContext().extractSource(ele);
    }
    //具体的解析过程由BeanDefinitionParserDelegate实现,  
    //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素
    protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
        if(this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute("profile");
            if(StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
                if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if(this.logger.isInfoEnabled()) {
                        this.logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
                    }

                    return;
                }
            }
        }
        //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
        this.preProcessXml(root);
        //从Document的根元素开始进行Bean定义的Document对象
        this.parseBeanDefinitions(root, this.delegate);
        //在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
        this.postProcessXml(root);
        this.delegate = parent;
    }
    //创建BeanDefinitionParserDelegate,用于完成真正的解析过程
    protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
        BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
        //BeanDefinitionParserDelegate初始化Document根元素
        delegate.initDefaults(root, parentDelegate);
        return delegate;
    }
    //使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
         //Bean定义的Document对象使用了Spring默认的XML命名空间
        if(delegate.isDefaultNamespace(root)) {
           //获取Bean定义的Document对象根元素的所有子节点
            NodeList nl = root.getChildNodes();

            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                //获得Document节点是XML元素节点
                if(node instanceof Element) {
                    Element ele = (Element)node;
                    //Bean定义的Document的元素节点使用的是Spring默认的XML命名空间
                    if(delegate.isDefaultNamespace(ele)) {
                        //使用Spring的Bean规则解析元素节点
                        this.parseDefaultElement(ele, delegate);
                    } else {
                       //没有使用Spring默认的XML命名空间,则使用用户自定义的解//析规则解析元素节点
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            //Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的  
           //解析规则解析Document根节点
            delegate.parseCustomElement(root);
        }

    }

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        //如果元素节点是<Import>导入元素,进行导入解析  
        if(delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
            
        } else if(delegate.nodeNameEquals(ele, "alias")) {
        //如果元素节点是<Alias>别名元素,进行别名解析 
            this.processAliasRegistration(ele);
        } else if(delegate.nodeNameEquals(ele, "bean")) {
        //元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素,  
        //按照Spring的Bean规则解析元素  
            this.processBeanDefinition(ele, delegate);
        } else if(delegate.nodeNameEquals(ele, "beans")) {
         //如果元素节点是<beans>元素注册为BeanDefintion
            this.doRegisterBeanDefinitions(ele);
        }

    }
    //解析<Import>导入元素,从给定的导入路径加载Bean定义资源到Spring IoC容器中
    protected void importBeanDefinitionResource(Element ele) {
        /获取给定的导入元素的location属性 
        String location = ele.getAttribute("resource");
        if(!StringUtils.hasText(location)) {
            this.getReaderContext().error("Resource location must not be empty", ele);
        } else {
            //获取location的值 
            location = this.getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
            Set<Resource> actualResources = new LinkedHashSet(4);
            //标识给定的导入元素的location是否是绝对路径
            boolean absoluteLocation = false;

            try {
                absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
            } catch (URISyntaxException var11) {
                ;
            }

            int importCount;
            if(absoluteLocation) {
                try {
                    //使用资源读入器加载给定路径的Bean定义资源
                    importCount = this.getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
                    }
                } catch (BeanDefinitionStoreException var10) {
                    this.getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, var10);
                }
            } else {
            //给定的导入元素的location是相对路径  
                try {
                    Resource relativeResource = this.getReaderContext().getResource().createRelative(location);
                    if(relativeResource.exists()) {
                         //使用资源读入器加载Bean定义资源 
                        importCount = this.getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                        actualResources.add(relativeResource);
                    } else {
                        String baseLocation = this.getReaderContext().getResource().getURL().toString();
                        importCount = this.getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources);
                    }

                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
                    }
                } catch (IOException var8) {
                    this.getReaderContext().error("Failed to resolve current resource location", ele, var8);
                } catch (BeanDefinitionStoreException var9) {
                    this.getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, var9);
                }
            }
            //在解析完<Import>元素之后,发送容器导入其他资源处理完成事件
            Resource[] actResArray = (Resource[])actualResources.toArray(new Resource[actualResources.size()]);
            this.getReaderContext().fireImportProcessed(location, actResArray, this.extractSource(ele));
        }
    }
   //解析<Alias>别名元素,为Bean向Spring IoC容器注册别名  
    protected void processAliasRegistration(Element ele) {
        //获取<Alias>别名元素中name的属性值
        String name = ele.getAttribute("name");
        //获取<Alias>别名元素中alias的属性值  
        String alias = ele.getAttribute("alias");
        boolean valid = true;
        if(!StringUtils.hasText(name)) {
            this.getReaderContext().error("Name must not be empty", ele);
            valid = false;
        }

        if(!StringUtils.hasText(alias)) {
            this.getReaderContext().error("Alias must not be empty", ele);
            valid = false;
        }

        if(valid) {
            try {
                //向容器的资源读入器注册别名
                this.getReaderContext().getRegistry().registerAlias(name, alias);
            } catch (Exception var6) {
                this.getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, var6);
            }
            //在解析完<Alias>元素之后,发送容器别名处理完成事件
            this.getReaderContext().fireAliasRegistered(name, alias, this.extractSource(ele));
        }

    } 
    //解析Bean定义资源Document对象的普通元素
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类  
       //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现  BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
                //向Spring IoC容器注册解析得到的Bean定义,这是Bean定义向IoC容器注册的入口
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }
            //在完成向Spring IoC容器注册解析得到的Bean定义之后,发送注册事件
            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }

    protected void preProcessXml(Element root) {
    }

    protected void postProcessXml(Element root) {
    }
}

의 정의 규칙에 따라 BeanDefinition으로 변환됩니다. 로드된 Bean 정의 문서를 파싱하는 위의 Spring IoC 컨테이너에서 볼 수 있듯이 Spring을 사용할 때 IoC 컨테이너에 필요한 다른 리소스를 가져오기 위해 Spring IoC 컨테이너는 먼저 구문 분석 시 지정된 가져온 리소스를 컨테이너에 로드합니다. 별칭을 사용할 때 Spring IoC 컨테이너는 먼저 alias 요소에 의해 정의된 별칭을 컨테이너에 등록합니다.
요소나 요소가 아닌 경우, 즉 Spring 구성 파일의 일반 요소는 BeanDefinitionParserDelegate 클래스의 parsBeanDefinitionElement 메소드에 의해 구문 분석됩니다.

다음은 Bean 요소의 구문 분석 과정입니다

    //解析Bean定义资源文件中的<Bean>元素,这个方法中主要处理<Bean>元素的id,name
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        //获取id属性
        String id = ele.getAttribute("id");
        //获取name属性
        String nameAttr = ele.getAttribute("name");
        List<String> aliases = new ArrayList();
        //将Bean元素的name属性全部放到alias属性里面
        if(StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        if(!StringUtils.hasText(id) && !aliases.isEmpty()) {
            beanName = (String)aliases.remove(0);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
            }
        }

        if(containingBean == null) {
            //检查bean元素的id和name是否是唯一的 
            this.checkNameUniqueness(beanName, aliases, ele);
        }
        //详细对<Bean>元素中配置的Bean定义进行解析的地方
        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
        if(beanDefinition != null) {
            if(!StringUtils.hasText(beanName)) {
                try {
                    if(containingBean != null) {
                        //判断如果没有id和name属性时候是否包含子元素的<Bean>
                        beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                    } else {
                        //如果<Bean>元素中没有配置id、别名或者name,且包含了子//<Bean>元素,为解析的Bean使用别名向IoC容器注册  
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        String beanClassName = beanDefinition.getBeanClassName();
                        if(beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }

                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }

            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }
    //详细解析bean元素的地方
    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        String className = null;
        //是否包含class属性
        if(ele.hasAttribute("class")) {
            //获取class属性值 不做实例化,bean的实例化是在第一次获取bean的时候完成,这里只获取class的值
            className = ele.getAttribute("class").trim();
        }

        try {
            String parent = null;
            //如果<Bean>元素中配置了parent属性,则获取parent属性的值
            if(ele.hasAttribute("parent")) {
                parent = ele.getAttribute("parent");
            }
           //根据<Bean>元素配置的class名称和parent属性值创建BeanDefinition  
            //为载入Bean定义信息做准备 
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            //对当前的<Bean>元素中配置的一些属性进行解析和设置,如配置的单态(singleton)属性等
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            //为<Bean>元素解析的Bean设置description信息 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            //对<Bean>元素的meta(元信息)属性解析
            this.parseMetaElements(ele, bd);
            //对<Bean>元素的lookup-method属性解析
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //对<Bean>元素的replaced-method属性解析
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //解析<Bean>元素的构造方法设置
            this.parseConstructorArgElements(ele, bd);
             //解析<Bean>元素的<property>设置
            this.parsePropertyElements(ele, bd);
             //解析<Bean>元素的qualifier属性
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
        } catch (ClassNotFoundException var13) {
            this.error("Bean class [" + className + "] not found", ele, var13);
        } catch (NoClassDefFoundError var14) {
            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
        } catch (Throwable var15) {
            this.error("Unexpected failure during bean definition parsing", ele, var15);
        } finally {
            this.parseState.pop();
        }

        return null;
    }

위 소스 코드를 분석하면 Spring 구성 파일의 요소에 구성한 속성이 구문 분석되어 이 방법을 통해 콩 가세요.
참고: 요소를 구문 분석하는 동안 Bean 개체는 생성되거나 인스턴스화되지 않습니다. Bean 개체의 정의 클래스 BeanDefinition만 생성되고 요소의 구성 정보는 레코드로서의 BeanDefinition 의존성 주입 시 이러한 레코드 정보는 특정 Bean 객체를 생성하고 인스턴스화하는 데에만 사용됩니다.
위 방법에서 메타 정보(meta), 한정자 등과 같은 일부 구성의 구문 분석은 Spring의 요소를 사용할 때 많이 사용되지 않습니다. ;재산.

BeanDefinitionReaderUtils의 RegisterBeanDefinition 메소드를 호출하여 파싱된 Bean을 IoC 컨테이너에 등록합니다.

 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null) {
            //通过对document对象的解析和封装返回一个BeanDefinitionHolder
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
                //通过这个holder来注册bean对象
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }

            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }

BeanDefinitionReaderUtils가 호출되어 파싱된 BeanDefinition을 IoC 컨테이너에 등록할 때 실제로 등록 기능을 완료하는 것은 DefaultListableBeanFactory입니다.

    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
        String[] aliases = definitionHolder.getAliases();
        if(aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String alias = var4[var6];
                registry.registerAlias(beanName, alias);
            }
        }

    }

DefaultListableBeanFactoryregisterBeanDefinition method

  //存储注册的俄BeanDefinition
 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
 //向IoC容器注册解析的BeanDefiniton
 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        //校验解析的BeanDefiniton
        if(beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition)beanDefinition).validate();
            } catch (BeanDefinitionValidationException var9) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9);
            }
        }

        BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        if(oldBeanDefinition != null) {
            if(!this.isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
            }

            if(oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                if(this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            } else if(!beanDefinition.equals(oldBeanDefinition)) {
                if(this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            } else if(this.logger.isDebugEnabled()) {
                this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
            }

            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            if(this.hasBeanCreationStarted()) {
                Map var4 = this.beanDefinitionMap;
                //注册的过程中需要线程同步,以保证数据的一致性 
                synchronized(this.beanDefinitionMap) {
                    //把bean存放到map中
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if(this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            } else {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }

            this.frozenBeanDefinitionNames = null;
        }

        if(oldBeanDefinition != null || this.containsSingleton(beanName)) {
            this.resetBeanDefinition(beanName);
        }

    }

이제 Bean 정의 리소스 파일에 구성된 Bean을 파싱한 후 IoC 컨테이너에 등록하여 컨테이너에서 관리하며 IoC 컨테이너를 초기화하는 모든 작업을 수행합니다. 정말 완료되었습니다. 이제 전체 Bean 구성 정보가 IoC 컨테이너에 설정되었습니다. 이 BeanDefinition 정보는 이미 사용 가능하며 검색할 수 있습니다. IoC 컨테이너의 역할은 등록된 Bean 정의 정보를 처리하고 유지하는 것입니다. 이렇게 등록된 Bean 정의 정보는 IoC 컨테이너 제어 반전의 기초가 됩니다. 이러한 등록된 데이터를 사용하여 컨테이너는 종속성 주입을 수행할 수 있습니다.

이 기사는 여기에서 끝났습니다. 더 많은 흥미로운 콘텐츠를 보려면 PHP 중국어 웹사이트의 Java Video Tutorial 칼럼을 주목하세요!

위 내용은 Spring-IOC 컨테이너 소개(코드 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제