spring学习笔记(Ioc)

1.BeanFactory
BeanFactory接口及其子类定义了Spring IoC容器体系结构,由于BeanFactory体系非常的庞大和复杂,因此要理解Spring IoC,需要先搞懂 BeanFactory 的继承机构。
这里写图片描述
实现的方法
这里写图片描述
详细解释:
(1).Object getBean(Stringname) throws BeansException;

getBean是IoC容器中最重要的方法,通过该方法可以取得IoC容器中管理的Bean,Bean的取得是通过指定名字来进行所引的。

(2). T getBean(String name, Class requiredType) throws BeansException;

根据指定的名字和类型取得IoC容器中管理的Bean,和getBean(String name)方法类似,只是多提供了一个类型安全验证机制。

(3). T getBean(Class requiredType) throws BeansException;

根据指定的类型取得IoC容器中管理的Bean,该方法根据指定的类型调用ListableBeanFactory(BeanFactory下的)中的取得Bean方法,但是也可能根据给定的类型调用通过名字取得Bean的方法。

(4). Object getBean(String name, Object… args) throws BeansException;

该方法重载了getBean(String name)方法,可变参数主要用来指定是否显示使用静态工厂方法创建一个原型(prototype)Bean。

(5). boolean containsBean(String name);

该方法让用户判断IoC容器中是否含有指定名字的Bean。

(6). boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

该方法用来查询指定名字的Bean是否是单态类型(singleton)的Bean。

(7). boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

该方法用来查询指定名字的Bean是否是原型(prototype)类型的Bean。

(8). boolean isTypeMatch(String name, Class targetType)throws NoSuchBeanDefinitionException;

该方法用来查询指定名字的Bean的class类型是否支持特定的class类型。

(9). Class

public interface ApplicationContext extends ListableBeanFactory, HierarchicalBeanFactory,  
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {  
    //获取ApplicationContext的id  
    String getId();  
    //获取ApplicationContext的displayName  
    String getDisplayName();  
    //获取ApplicationContext第一次加载的时间戳  
    long getStartupDate();  
    //获取ApplicationContext容器的父容器  
    ApplicationContext getParent();  
    //获取自动装配功能的BeanFactory  
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;  
}  

2、Ioc 容器初始化:applicationcontext.xml配置文件的定位、载入和注册3个基本过程。
(1) 配置文件的定位:ApplicationContext是一个在BeanFactory基础上提供了扩展的接口,具体的IoC容器实现常用的有:
(从文件系统中读入Bean定义资源文件)FileSystemXmlApplicationContet
ClassPathXmlApplicationContext(从Classpath类路径中读入Bean定义资源文件)和XmlWebApplicationContext(从Web容器如Tomcat等中读入Bean定义资源文件)等。以FileSystemXmlApplicationContet为例,通过分FileSystemXmlApplicationContet及其父类的源码来分析IoC容器定位Bean定义资源文件的实现过程

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {  

    public FileSystemXmlApplicationContext() {  
    }  
    public FileSystemXmlApplicationContext(ApplicationContext parent) {  
        super(parent);  
    }  
    //configLocation是Bean定义资源文件路径  
    public FileSystemXmlApplicationContext(String configLocation) throws BeansException {  
        this(new String[] {configLocation}, true, null);  
    }  
    //可以传入多个Bean定义资源文件路径  
    public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {  
        this(configLocations, true, null);  
    }  
    public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {  
        this(configLocations, true, parent);  
    }  
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {  
        this(configLocations, refresh, null);  
    }  
//FileSystemXmlApplicationContext IoC容器进行初始化的入口构造函数  
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)  
            throws BeansException {  
        super(parent);  
//调用父类AbstractRefreshableConfigApplicationContext的方法,设置//Bean定义的资源文件,完成IoC容器Bean定义资源的定位  
        setConfigLocations(configLocations);  
        if (refresh) {  
//调用父类AbstractApplicationContext的refresh()  
//函数启动载入Bean定义的过程,是Ioc容器载入Bean定义的入口  
            refresh();  
        }  
    }  
//该方法覆盖父类DefaultResourceLoader的方法,通过Bean定义文件路径封装得到//IoC容器要读入的定位Bean定义的资源  
    @Override  
    protected Resource getResourceByPath(String path) {  
        if (path != null && path.startsWith("/")) {  
            path = path.substring(1);  
        }  
//其他类型的IoC容器会用其他类型的Resource来定位Bean定义,如//ClasspathResource等  
        return new FileSystemResource(path);  
    }  
}  

在FileSystemXmlApplicationContext 中我们发现追踪其父类的源码:

public abstract class AbstractApplicationContext extends DefaultResourceLoader  
        implements ConfigurableApplicationContext, DisposableBean {  
//静态初始化块,在整个容器创建过程中只执行一次  
static {  
        //为了避免应用程序在Weblogic8.1关闭时出现类加载异常加载问题,加载IoC容  
//器关闭事件(ContextClosedEvent)类  
        ContextClosedEvent.class.getName();  
    }  
    //FileSystemXmlApplicationContext调用父类构造方法调用的就是该方法  
    public AbstractApplicationContext(ApplicationContext parent) {  
        this.parent = parent;  
        this.resourcePatternResolver = getResourcePatternResolver();  
    }  
//获取一个Spring Source的加载器用于读入Spring Bean定义资源文件  
protected ResourcePatternResolver getResourcePatternResolver() {  
        // AbstractApplicationContext继承DefaultResourceLoader,也是一个S  
        //Spring资源加载器,其getResource(String location)方法用于载入资源  
        return new PathMatchingResourcePatternResolver(this);  
    }   
……  
}  

追踪 PathMatchingResourcePatternResolver

public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {  
        Assert.notNull(resourceLoader, "ResourceLoader must not be null");  
        //设置Spring的资源加载器  
        this.resourceLoader = resourceLoader;  
    } 

(2).bean配置文件的载入:

是将配置文件中配置的Bean转换成IoC容器中所管理Bean的数据结构形式。SpringIoC中管理的Bean的数据结构是BeanDefinition,BeanDefinition是POJO对象在IoC容器中的抽象。
当Spring的IoC容器将Bean定义的资源文件封装为Spring的Resource之后,接下来要做的就是通过Spring的资源加载器(resourceLoader)读入Bean定义资源文件的过程。对于IoC容器来说,Bean定义的载入过程就是将Bean定义资源文件读入进内存并解析转换成Spring所管理的Bean的数据结构的过程。
首先上面我们已经看到了FileSystemXmlApplicationContext的源码,其中的构造器中,
FileSystemXmlApplicationContext通过调用其父类AbstractApplicationContext的refresh()函数启动整个IoC容器对Bean定义的载入过程。

public void refresh() throws BeansException, IllegalStateException {  
        synchronized (this.startupShutdownMonitor) {  
            //调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识  
            prepareRefresh();  
            //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从  
//子类的refreshBeanFactory()方法启动  
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
//为BeanFactory配置容器特性,例如类加载器、事件处理器等  
            prepareBeanFactory(beanFactory);  
            try {  
                //为容器的某些子类指定特殊的BeanPost事件处理器  
                postProcessBeanFactory(beanFactory);  
                //调用所有注册的BeanFactoryPostProcessor的Bean  
                invokeBeanFactoryPostProcessors(beanFactory);  
                //为BeanFactory注册BeanPost事件处理器.  
                //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件  
                registerBeanPostProcessors(beanFactory);  
                //初始化信息源,和国际化相关.  
                initMessageSource();  
                //初始化容器事件传播器.  
                initApplicationEventMulticaster();  
                //调用子类的某些特殊Bean初始化方法  
                onRefresh();  
                //为事件传播器注册事件监听器.  
                registerListeners();  
                //初始化所有剩余的单态Bean.  
                finishBeanFactoryInitialization(beanFactory);  
                //初始化容器的生命周期事件处理器,并发布容器的生命周期事件  
                finishRefresh();  
            }  
            catch (BeansException ex) {  
                //销毁以创建的单态Bean  
                destroyBeans();  
//取消refresh操作,重置容器的同步标识.  
                cancelRefresh(ex);  
                throw ex;  
            }  
        }  
    }  

refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,refresh()方法中我们可以看到这句ConfigurableListableBeanFactorybeanFactory=obtainFreshBean
调用子类容器的refreshBeanFactory()方法,启动容器载入配置文件的过程

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  
//这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具//体实现调用子类容器的refreshBeanFactory()方法          
refreshBeanFactory();  
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();  
        if (logger.isDebugEnabled()) {  
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  
        }  
        return beanFactory;  
    }  

AbstractApplicationContext类中只抽象定义了refreshBeanFactory()方法,容器真正调用的是其子类AbstractRefreshableApplicationContext实现的refreshBeanFactory()方法,方法的源码如下:

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

从中可以看到调用了AbstractRefreshableApplicationContext子类的loadBeanDefinitions方法:

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {  


//实现父类抽象的载入Bean定义方法  
    @Override  
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {  
        //创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器       //中去,容器使用该读取器读取Bean定义资源  
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
//为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的  
//祖先父类AbstractApplicationContext继承DefaultResourceLoader,因//此,容器本身也是一个资源加载器  
        beanDefinitionReader.setResourceLoader(this);  
        //为Bean读取器设置SAX xml解析器  
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
        //当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制  
        initBeanDefinitionReader(beanDefinitionReader);  
        //Bean读取器真正实现加载的方法  
        loadBeanDefinitions(beanDefinitionReader);  
    }  
    //Xml Bean读取器加载Bean定义资源  
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {  
        //获取Bean定义资源的定位  
        Resource[] configResources = getConfigResources();  
        if (configResources != null) {  
            //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位  
//的Bean定义资源  
            reader.loadBeanDefinitions(configResources);  
        }  
//如果子类中获取的Bean定义资源定位为空,则获取//FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源  
        String[] configLocations = getConfigLocations();  
        if (configLocations != null) {  
            //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位  
//的Bean定义资源  
            reader.loadBeanDefinitions(configLocations);  
        }  
    }  
    //这里又使用了一个委托模式,调用子类的获取Bean定义资源定位的方法  
    //该方法在ClassPathXmlApplicationContext中进行实现,对于我们  
    //举例分析源码的FileSystemXmlApplicationContext没有使用该方法  
protected Resource[] getConfigResources() {  
        return null;  
    }   

}  

顺着 reader.loadBeanDefinitions(configLocations); 方法我们进去:

 public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {  
        return loadBeanDefinitions(location, null);  
    }  
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {  
        //获取在IoC容器初始化过程中设置的资源加载器  
        ResourceLoader resourceLoader = getResourceLoader();  
        if (resourceLoader == null) {  
            throw new BeanDefinitionStoreException(  
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");  
        }  
        if (resourceLoader instanceof ResourcePatternResolver) {  
            try {  
                //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
                //加载多个指定位置的Bean定义资源文件  
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);  
                //委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能  
                int loadCount = loadBeanDefinitions(resources);  
                if (actualResources != null) {  
                    for (Resource resource : resources) {  
                        actualResources.add(resource);  
                    }  
                }  
                if (logger.isDebugEnabled()) {  
                    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");  
                }  
                return loadCount;  
            }  
            catch (IOException ex) {  
                throw new BeanDefinitionStoreException(  
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);  
            }  
        }  
        else {  
            //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
            //加载单个指定位置的Bean定义资源文件  
            Resource resource = resourceLoader.getResource(location);  
            //委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能  
            int loadCount = loadBeanDefinitions(resource);  
            if (actualResources != null) {  
                actualResources.add(resource);  
            }  
            if (logger.isDebugEnabled()) {  
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");  
            }  
            return loadCount;  
        }  
    }  
    //重载方法,调用loadBeanDefinitions(String);  
    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;  
    }  

从对AbstractBeanDefinitionReader的loadBeanDefinitions方法源码分析可以看出该方法做了以下两件事:

首先,调用资源加载器的获取资源方法resourceLoader.getResource(location),获取到要加载的资源。

其次,真正执行加载功能是其子类XmlBeanDefinitionReader的loadBeanDefinitions方法。
那么来看XmlBeanDefinitionReader通过调用其父类DefaultResourceLoader的getResource方法

public Resource getResource(String location) {  
        Assert.notNull(location, "Location must not be null");  
        //这里除了带有classpath标识的Resource  
        if (location.startsWith(CLASSPATH_URL_PREFIX)) {  
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());  
        }  
        else {  
            try {  
                //这里处理URL标识的Resource定位  
                URL url = new URL(location);  
                return new UrlResource(url);  
            }  
            catch (MalformedURLException ex) {  
                //如果既不是classpath标识,又不是URL标识的Resource定位,则调用  
                //容器本身的getResourceByPath方法获取Resource  
                return getResourceByPath(location);  
            }  
        }  
    }  

接着来看XmlBeanDefinitionReader的loadBeanDefinitions方法:

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {  
        //将读入的XML资源进行特殊编码处理  
        return loadBeanDefinitions(new EncodedResource(resource));  
    }  
//这里是载入XML形式Bean定义资源文件方法  
    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {  
        Assert.notNull(encodedResource, "EncodedResource must not be null");  
        if (logger.isInfoEnabled()) {  
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());  
        }  
        //这里是获取线程局部变量  
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();  
        if (currentResources == null) {  
            currentResources = new HashSet<EncodedResource>(4);  
            this.resourcesCurrentlyBeingLoaded.set(currentResources);  
        }  
        if (!currentResources.add(encodedResource)) {  
            throw new BeanDefinitionStoreException(  
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");  
        }  
        try {  
            //将资源文件转换为IO输入流  
            InputStream inputStream = encodedResource.getResource().getInputStream();  
            try {  
                InputSource inputSource = new InputSource(inputStream);  
                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();  
            }  
        }  
    }  
//从特定XML文件中实际载入Bean定义资源的方法  
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)  
            throws BeanDefinitionStoreException {  
        try {  
            int validationMode = getValidationModeForResource(resource);  
            //将XML文件转换为DOM对象,解析过程由documentLoader实现  
            Document doc = this.documentLoader.loadDocument(  
                    inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());  
            //这里是启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean  
            //配置规则  
            return registerBeanDefinitions(doc, resource);  
        }  
        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);  
        }  
    }  

DocumentLoader将Bean定义资源转换为Document对象,DocumentLoader将Bean定义资源转换成Document对象的源码如下:

public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,  
            ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {  
        //创建文件解析器工厂  
        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);  
        if (logger.isDebugEnabled()) {  
            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");  
        }  
        //创建文档解析器  
        DocumentBuilder builder = 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);  
        //设置解析XML的校验  
        if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {  
            factory.setValidating(true);  
            if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {  
                factory.setNamespaceAware(true);  
                try {  
                    factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);  
                }  
                catch (IllegalArgumentException ex) {  
                    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(ex);  
                    throw pcex;  
                }  
            }  
        }  
        return factory;  
    }  

至此就是Spring IoC容器根据定位的applicationcontext.xml文件,将其加载读入并转换成为Document对象过程。

(3).Bean定义的注册:

通过调用BeanDefinitionRegistry接口把从Bean定义资源文件中解析的Bean向IoC容器进行注册,在IoC容器内部,是通过一个HashMap来存储这些Bean对象数据的。

猜你喜欢

转载自blog.csdn.net/weixin_38008100/article/details/81515743