美文网首页spring全家桶
Spring学习1-ClassPathXmlApplicatio

Spring学习1-ClassPathXmlApplicatio

作者: 小鲍比大爷 | 来源:发表于2018-08-23 22:44 被阅读0次

spring是java的开源框架。由于在前公司系统框架都是自己实现,所以之前未使用过spring,通过所在新公司的项目代码看了一些spring的用法,比较好奇内部实现。虽然在前公司也用过很多技术,但由于太忙,很多时候都是知其然不知其所以然,作为技术人员,不了解内部实现,那种感觉相当难受,很多时候用过相关技术之后除了知道几个API或者是一些网上到处可以搜到的部署流程,实际上两手空空毫无收获。
来到ThoughtWorks,终于有点自己的时间,于是乎自己动手调试和阅读源码,目的是了解一下IOC和AOP的一些内部机制,顺便学习一下spring经典框架的代码架构。阅读版本为4.1.5。
以前并没有特别多的阅读源码经验,所以不知道如何读起,通过断点单步调试发现效果并不是很好,原因是继承层次较多、接口遍地,在不了解继承层次的情况下,会觉得比较乱,于是想尝试先了解下整体的继承层次,应该对于理解整体架构会有帮助。长话短说,我们一起开始看代码。
看代码由入口开始看,spring所有的信息都保存在ApplicationContext中,下图以ClassPathXmlApplicationContext为例开始走读源码。


Screen Shot 2018-08-19 at 22.37.01.png

从最上层的接口开始看,ResourceLoader接口,这个接口是提供查找资源的接口,DefaultResourceLoader和ResourcePatternResolver继承了这个类:

public interface ResourceLoader {

    /** Pseudo URL prefix for loading from the class path: "classpath:" */
    String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;


    /**
     * Return a Resource handle for the specified resource.
     * The handle should always be a reusable resource descriptor,
     * allowing for multiple {@link Resource#getInputStream()} calls.
     * <p><ul>
     * <li>Must support fully qualified URLs, e.g. "file:C:/test.dat".
     * <li>Must support classpath pseudo-URLs, e.g. "classpath:test.dat".
     * <li>Should support relative file paths, e.g. "WEB-INF/test.dat".
     * (This will be implementation-specific, typically provided by an
     * ApplicationContext implementation.)
     * </ul>
     * <p>Note that a Resource handle does not imply an existing resource;
     * you need to invoke {@link Resource#exists} to check for existence.
     * @param location the resource location
     * @return a corresponding Resource handle
     * @see #CLASSPATH_URL_PREFIX
     * @see org.springframework.core.io.Resource#exists
     * @see org.springframework.core.io.Resource#getInputStream
     */
    Resource getResource(String location);

    /**
     * Expose the ClassLoader used by this ResourceLoader.
     * <p>Clients which need to access the ClassLoader directly can do so
     * in a uniform manner with the ResourceLoader, rather than relying
     * on the thread context ClassLoader.
     * @return the ClassLoader (only {@code null} if even the system
     * ClassLoader isn't accessible)
     * @see org.springframework.util.ClassUtils#getDefaultClassLoader()
     */
    ClassLoader getClassLoader();

}

DefaultResourceLoader是具体类,对getResource提供了具体实现,该类用于获取资源:

    @Override
    public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");
        if (location.startsWith("/")) {
            return getResourceByPath(location);
        }
        else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
        }
        else {
            try {
                // Try to parse the location as a URL...
                URL url = new URL(location);
                return new UrlResource(url);
            }
            catch (MalformedURLException ex) {
                // No URL -> resolve as resource path.
                return getResourceByPath(location);
            }
        }
    }

ResourcePatternResolver继承后仍然为接口,没有具体实现,该接口在父接口上添加了一个接口,支持返回多个资源列表:

public interface ResourcePatternResolver extends ResourceLoader {

    /**
     * Pseudo URL prefix for all matching resources from the class path: "classpath*:"
     * This differs from ResourceLoader's classpath URL prefix in that it
     * retrieves all matching resources for a given name (e.g. "/beans.xml"),
     * for example in the root of all deployed JAR files.
     * @see org.springframework.core.io.ResourceLoader#CLASSPATH_URL_PREFIX
     */
    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    /**
     * Resolve the given location pattern into Resource objects.
     * <p>Overlapping resource entries that point to the same physical
     * resource should be avoided, as far as possible. The result should
     * have set semantics.
     * @param locationPattern the location pattern to resolve
     * @return the corresponding Resource objects
     * @throws IOException in case of I/O errors
     */
    Resource[] getResources(String locationPattern) throws IOException;

}

MessageSource看起来是一组用来解析字符串的接口,后面看到具体实现再说。
ApplicationEventPublisher,一个通知接口,用来通知注册的listeners发生的框架事件。

public interface ApplicationEventPublisher {

    /**
     * Notify all listeners registered with this application of an application
     * event. Events may be framework events (such as RequestHandledEvent)
     * or application-specific events.
     * @param event the event to publish
     * @see org.springframework.web.context.support.RequestHandledEvent
     */
    void publishEvent(ApplicationEvent event);

}

EnvironmentCapable,提供返回环境信息的接口:

public interface EnvironmentCapable {

    /**
     * Return the {@link Environment} associated with this component.
     */
    Environment getEnvironment();

}

BeanFactory,顾名思义,就是获取bean的工厂。这个接口基本算是spring中的核心接口吧,因为spring核心的IOC和AOP功能可以说是构建在BeanFactory之上的:

public interface BeanFactory {

    /**
     * Used to dereference a {@link FactoryBean} instance and distinguish it from
     * beans <i>created</i> by the FactoryBean. For example, if the bean named
     * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
     * will return the factory, not the instance returned by the factory.
     */
    String FACTORY_BEAN_PREFIX = "&";

    /**
     * 返回对象的类实例。该实例可以是单例模式或者是原型模式。
     单例模式意味着所有通过此工厂获取的引用都指向同一个实例;
     而原型模式返回的是实例的克隆对象。
     */
    Object getBean(String name) throws BeansException;

    /**
     * 与getBean(String name)方法的区别在于指定了返回对象的类型
     */
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

    /**
     * 不提供名称,只通过类型查询,然后返回相应类型的bean
     */
    <T> T getBean(Class<T> requiredType) throws BeansException;

    /**
     * 获取bean时提供相应参数,该参数可以用与生成bean的工厂或者bean的构造函数
     */
    Object getBean(String name, Object... args) throws BeansException;

    /**
     * 获取bean时,提供参数和指定bean的返回类型
     */
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    /**
     * 确认BeanFactory中是否包含bean的定义或者是否存在已经注册的bean。
     * 如果给定的name为别名,那么实现需要将该别名转换成bean的真实名称;
     * 如果BeanFactory有Parents(HierarchicalBeanFactory),那么需要到Parents工厂那里查询bean实例是否已经注册
     *(注意这里的Parents并非继承关系,而是类似java类加载中的双亲委派机制,先在下层中查找相应类,
     * 查找不到再到上层查找,他们之间构建了一个层次关系,由最底层可以向上层找,上层为祖先)
     * 这个函数返回true时,并不以为可以获取bean的实例,这个因为只要bean的定义存在或者对象已经注册就可以返回true,
     * 然而bean有可能是抽象类。
     */
    boolean containsBean(String name);

    /**
     * 是否为单例模式
     */
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    /**
     * 是否未原型模式
     */
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    /**
     * 给定的bean name是否匹配目标类型targetType
     */
    boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;

    /**
     * 返回指定name的bean的类型
     */
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    /**
     * 返回指定bean name的别名列表。如果参数name本身为别名,
        那么将会返回bean name原始名称和其他别名的列表,原始名称保      
        存在返回数组的第一个元素中。
     */
    String[] getAliases(String name);

}

HierarchicalBeanFactory,这个接口说明BeanFactory可以存在层次模型,可以获取ParentBeanFactory,刚才�BeanFactory中的大多数方法都会在自身查找失败的时候继续查找ParentBeanFactory,比如getType等。

public interface HierarchicalBeanFactory extends BeanFactory {

    /**
     * Return the parent bean factory, or null if there is none.
     */
    BeanFactory getParentBeanFactory();

    /**
     * 忽略双亲委派模型(查找不到也不到parent bean factory中去查找),只在本地BeanFactory中查找相关的bean
     * @param name the name of the bean to query
     * @return whether a bean with the given name is defined in the local factory
     * @see BeanFactory#containsBean
     */
    boolean containsLocalBean(String name);

}

接口ListableBeanFactory,继承自BeanFactory。ListableBeanFactory的实现类需要预先加载所有的bean定义信息(例如基于xml的BeanFactory),而不是根据客户端的请求再去发现相应的bean信息。该类只关注当前Factory中bean的定义,该类会忽略通过其他方式注册的bean(所以该类不会进行双亲委托的查询且只关注自身bean定义信息,忽略双亲委托和非该Factory注册的bean,)。感觉该类是为了封闭自己的bean定义信息,保持类的纯净,看到后面知道其实际用法后再补充。这个接口的方法很简单,都是获取bean信息或者bean本身的,一些方法的不同点在于是依赖类型获取还是依靠注释获取bean的信息。

public interface ListableBeanFactory extends BeanFactory {

    /**
     * 检查是否包含name的bean定义
     * @param beanName the name of the bean to look for
     * @return if this bean factory contains a bean definition with the given name
     * @see #containsBean
     */
    boolean containsBeanDefinition(String beanName);

    /**
     * 返回bean的数量
     * @return the number of beans defined in the factory
     */
    int getBeanDefinitionCount();

    /**
     * Return the names of all beans defined in this factory.
     * <p>Does not consider any hierarchy this factory may participate in,
     * and ignores any singleton beans that have been registered by
     * other means than bean definitions.
     * @return the names of all beans defined in this factory,
     * or an empty array if none defined
     */
    String[] getBeanDefinitionNames();

    /**
     * Return the names of beans matching the given type (including subclasses),
     * judging from either bean definitions or the value of {@code getObjectType}
     * in the case of FactoryBeans.
     * <p><b>NOTE: This method introspects top-level beans only.</b> It does <i>not</i>
     * check nested beans which might match the specified type as well.
     * <p>Does consider objects created by FactoryBeans, which means that FactoryBeans
     * will get initialized. If the object created by the FactoryBean doesn't match,
     * the raw FactoryBean itself will be matched against the type.
     * <p>Does not consider any hierarchy this factory may participate in.
     * Use BeanFactoryUtils' {@code beanNamesForTypeIncludingAncestors}
     * to include beans in ancestor factories too.
     * <p>Note: Does <i>not</i> ignore singleton beans that have been registered
     * by other means than bean definitions.
     * <p>This version of {@code getBeanNamesForType} matches all kinds of beans,
     * be it singletons, prototypes, or FactoryBeans. In most implementations, the
     * result will be the same as for {@code getBeanNamesForType(type, true, true)}.
     * <p>Bean names returned by this method should always return bean names <i>in the
     * order of definition</i> in the backend configuration, as far as possible.
     * @param type the class or interface to match, or {@code null} for all bean names
     * @return the names of beans (or objects created by FactoryBeans) matching
     * the given object type (including subclasses), or an empty array if none
     * @see FactoryBean#getObjectType
     * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class)
     */
    String[] getBeanNamesForType(Class<?> type);

    /**
     * Return the names of beans matching the given type (including subclasses),
     * judging from either bean definitions or the value of {@code getObjectType}
     * in the case of FactoryBeans.
     * <p><b>NOTE: This method introspects top-level beans only.</b> It does <i>not</i>
     * check nested beans which might match the specified type as well.
     * <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,
     * which means that FactoryBeans will get initialized. If the object created by the
     * FactoryBean doesn't match, the raw FactoryBean itself will be matched against the
     * type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked
     * (which doesn't require initialization of each FactoryBean).
     * <p>Does not consider any hierarchy this factory may participate in.
     * Use BeanFactoryUtils' {@code beanNamesForTypeIncludingAncestors}
     * to include beans in ancestor factories too.
     * <p>Note: Does <i>not</i> ignore singleton beans that have been registered
     * by other means than bean definitions.
     * <p>Bean names returned by this method should always return bean names <i>in the
     * order of definition</i> in the backend configuration, as far as possible.
     * @param type the class or interface to match, or {@code null} for all bean names
     * @param includeNonSingletons whether to include prototype or scoped beans too
     * or just singletons (also applies to FactoryBeans)
     * @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and
     * <i>objects created by FactoryBeans</i> (or by factory methods with a
     * "factory-bean" reference) for the type check. Note that FactoryBeans need to be
     * eagerly initialized to determine their type: So be aware that passing in "true"
     * for this flag will initialize FactoryBeans and "factory-bean" references.
     * @return the names of beans (or objects created by FactoryBeans) matching
     * the given object type (including subclasses), or an empty array if none
     * @see FactoryBean#getObjectType
     * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean)
     */
    String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);

    /**
     * Return the bean instances that match the given object type (including
     * subclasses), judging from either bean definitions or the value of
     * {@code getObjectType} in the case of FactoryBeans.
     * <p><b>NOTE: This method introspects top-level beans only.</b> It does <i>not</i>
     * check nested beans which might match the specified type as well.
     * <p>Does consider objects created by FactoryBeans, which means that FactoryBeans
     * will get initialized. If the object created by the FactoryBean doesn't match,
     * the raw FactoryBean itself will be matched against the type.
     * <p>Does not consider any hierarchy this factory may participate in.
     * Use BeanFactoryUtils' {@code beansOfTypeIncludingAncestors}
     * to include beans in ancestor factories too.
     * <p>Note: Does <i>not</i> ignore singleton beans that have been registered
     * by other means than bean definitions.
     * <p>This version of getBeansOfType matches all kinds of beans, be it
     * singletons, prototypes, or FactoryBeans. In most implementations, the
     * result will be the same as for {@code getBeansOfType(type, true, true)}.
     * <p>The Map returned by this method should always return bean names and
     * corresponding bean instances <i>in the order of definition</i> in the
     * backend configuration, as far as possible.
     * @param type the class or interface to match, or {@code null} for all concrete beans
     * @return a Map with the matching beans, containing the bean names as
     * keys and the corresponding bean instances as values
     * @throws BeansException if a bean could not be created
     * @since 1.1.2
     * @see FactoryBean#getObjectType
     * @see BeanFactoryUtils#beansOfTypeIncludingAncestors(ListableBeanFactory, Class)
     */
    <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;

    /**
     * Return the bean instances that match the given object type (including
     * subclasses), judging from either bean definitions or the value of
     * {@code getObjectType} in the case of FactoryBeans.
     * <p><b>NOTE: This method introspects top-level beans only.</b> It does <i>not</i>
     * check nested beans which might match the specified type as well.
     * <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,
     * which means that FactoryBeans will get initialized. If the object created by the
     * FactoryBean doesn't match, the raw FactoryBean itself will be matched against the
     * type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked
     * (which doesn't require initialization of each FactoryBean).
     * <p>Does not consider any hierarchy this factory may participate in.
     * Use BeanFactoryUtils' {@code beansOfTypeIncludingAncestors}
     * to include beans in ancestor factories too.
     * <p>Note: Does <i>not</i> ignore singleton beans that have been registered
     * by other means than bean definitions.
     * <p>The Map returned by this method should always return bean names and
     * corresponding bean instances <i>in the order of definition</i> in the
     * backend configuration, as far as possible.
     * @param type the class or interface to match, or {@code null} for all concrete beans
     * @param includeNonSingletons whether to include prototype or scoped beans too
     * or just singletons (also applies to FactoryBeans)
     * @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and
     * <i>objects created by FactoryBeans</i> (or by factory methods with a
     * "factory-bean" reference) for the type check. Note that FactoryBeans need to be
     * eagerly initialized to determine their type: So be aware that passing in "true"
     * for this flag will initialize FactoryBeans and "factory-bean" references.
     * @return a Map with the matching beans, containing the bean names as
     * keys and the corresponding bean instances as values
     * @throws BeansException if a bean could not be created
     * @see FactoryBean#getObjectType
     * @see BeanFactoryUtils#beansOfTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean)
     */
    <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
            throws BeansException;

    /**
     * Find all names of beans whose {@code Class} has the supplied {@link Annotation}
     * type, without creating any bean instances yet.
     * @param annotationType the type of annotation to look for
     * @return the names of all matching beans
     * @since 4.0
     */
    String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);

    /**
     * Find all beans whose {@code Class} has the supplied {@link Annotation} type,
     * returning a Map of bean names with corresponding bean instances.
     * @param annotationType the type of annotation to look for
     * @return a Map with the matching beans, containing the bean names as
     * keys and the corresponding bean instances as values
     * @throws BeansException if a bean could not be created
     * @since 3.0
     */
    Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;

    /**
     * Find an {@link Annotation} of {@code annotationType} on the specified
     * bean, traversing its interfaces and super classes if no annotation can be
     * found on the given class itself.
     * @param beanName the name of the bean to look for annotations on
     * @param annotationType the annotation class to look for
     * @return the annotation of the given type if found, or {@code null}
     * @throws NoSuchBeanDefinitionException if there is no bean with the given name
     * @since 3.0
     */
    <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
            throws NoSuchBeanDefinitionException;

}

ApplicationContext,这个接口继承了多个接口,这些接口在前面已经提到,所以ApplicationContext具有之前所提到接口的所有能力:获取指定资源的信息、获取bean和bean定义、获取ParentBeanFactory等。另外,它也新增了一些接口方法。

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

    /**
     * Return the unique id of this application context.
     * @return the unique id of the context, or {@code null} if none
     */
    String getId();

    /**
     * Return a name for the deployed application that this context belongs to.
     * @return a name for the deployed application, or the empty String by default
     */
    String getApplicationName();

    /**
     * Return a friendly name for this context.
     * @return a display name for this context (never {@code null})
     */
    String getDisplayName();

    /**
     * Return the timestamp when this context was first loaded.
     * @return the timestamp (ms) when this context was first loaded
     */
    long getStartupDate();

    /**
     * Return the parent context, or {@code null} if there is no parent
     * and this is the root of the context hierarchy.
     * @return the parent context, or {@code null} if there is no parent
     */
    ApplicationContext getParent();

    /**
     * Expose AutowireCapableBeanFactory functionality for this context.
     * <p>This is not typically used by application code, except for the purpose of
     * initializing bean instances that live outside of the application context,
     * applying the Spring bean lifecycle (fully or partly) to them.
     * <p>Alternatively, the internal BeanFactory exposed by the
     * {@link ConfigurableApplicationContext} interface offers access to the
     * {@link AutowireCapableBeanFactory} interface too. The present method mainly
     * serves as a convenient, specific facility on the ApplicationContext interface.
     * <p><b>NOTE: As of 4.2, this method will consistently throw IllegalStateException
     * after the application context has been closed.</b> In current Spring Framework
     * versions, only refreshable application contexts behave that way; as of 4.2,
     * all application context implementations will be required to comply.
     * @return the AutowireCapableBeanFactory for this context
     * @throws IllegalStateException if the context does not support the
     * {@link AutowireCapableBeanFactory} interface, or does not hold an
     * autowire-capable bean factory yet (e.g. if {@code refresh()} has
     * never been called), or if the context has been closed already
     * @see ConfigurableApplicationContext#refresh()
     * @see ConfigurableApplicationContext#getBeanFactory()
     */
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;

}

ApplicationContext最后的接口方法是getAutowireCapableBeanFactory,返回了一个AutowireCapableBeanFactory类型的对象,该对象同样继承自接口BeanFactory。该BeanFactory对bean有更多的操作。
Lifecycle接口,拥有start,stop,isRunning三个接口方法,如下:

public interface Lifecycle {

    /**
     * Start this component.
     * Should not throw an exception if the component is already running.
     * <p>In the case of a container, this will propagate the start signal
     * to all components that apply.
     */
    void start();

    /**
     * Stop this component, typically in a synchronous fashion, such that
     * the component is fully stopped upon return of this method. Consider
     * implementing {@link SmartLifecycle} and its {@code stop(Runnable)}
     * variant in cases where asynchronous stop behavior is necessary.
     * <p>Should not throw an exception if the component isn't started yet.
     * <p>In the case of a container, this will propagate the stop signal
     * to all components that apply.
     * @see SmartLifecycle#stop(Runnable)
     */
    void stop();

    /**
     * Check whether this component is currently running.
     * <p>In the case of a container, this will return {@code true}
     * only if <i>all</i> components that apply are currently running.
     * @return whether the component is currently running
     */
    boolean isRunning();

}

ConfigurableApplicationContext接口,继承自 ApplicationContext, Lifecycle, Closeable,他拥有这三个接口所有的行为,支持启动、停止、关闭、运行期间状态查询以及ApplicationContext的行为。setId等方法很简单,一看便知。这块只记录一些重要方法。
void refresh()方法,用于加载或者刷新配置(xml文件、配置文件、关系数据库schema),这是初始化所有bean时的方法,所以要么全部bean初始化,要么全部初始化失败,不能存在部分bean初始化的情况,假设某些bean初始化失败,那么需要对已初始化的bean进行清理,保证没有悬挂的对象存在。
void setParent(ApplicationContext parent)方法,这个方法的存在说明ConfigurableApplicationContext也存在层次关系,可以拥有parent ApplicationContext。
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor)方法,顾名思义,BeanFactory的后处理器,该方法用来注册这些处理,虽然现在还未看到具体实现类,但是可以想象,这些处理器肯定具有改变BeanFactory功能的能力,值得期待。这些后处理器会在ApplicationContext配置化期间被调用。
void addApplicationListener(ApplicationListener<?> listener),添加listener,当上下文做某些动作时,通知事件发出后,这些注册的listener可以收到相应的事件。
void registerShutdownHook(),在JVM上注册一个关闭上下文的钩子,这样应该可以确保JVM关闭时,上下文可以正确被关闭,如果上下文已经关闭,那么JVM什么都不做。

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {

    /**
     * Any number of these characters are considered delimiters between
     * multiple context config paths in a single String value.
     */
    String CONFIG_LOCATION_DELIMITERS = ",; \t\n";

    /**
     * Name of the ConversionService bean in the factory.
     * If none is supplied, default conversion rules apply.
     * @see org.springframework.core.convert.ConversionService
     */
    String CONVERSION_SERVICE_BEAN_NAME = "conversionService";

    /**
     * Name of the LoadTimeWeaver bean in the factory. 
     * @see org.springframework.instrument.classloading.LoadTimeWeaver
     */
    String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";

    /**
     * Name of the {@link Environment} bean in the factory.
     */
    String ENVIRONMENT_BEAN_NAME = "environment";

    /**
     * Name of the System properties bean in the factory.
     * @see java.lang.System#getProperties()
     */
    String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";

    /**
     * Name of the System environment bean in the factory.
     * @see java.lang.System#getenv()
     */
    String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";


    /**
     * Set the unique id of this application context.
     */
    void setId(String id);

    /**
     * Set the parent of this application context.
     * <p>Note that the parent shouldn't be changed: It should only be set outside
     * a constructor if it isn't available when an object of this class is created,
     * for example in case of WebApplicationContext setup.
     * @param parent the parent context
     * @see org.springframework.web.context.ConfigurableWebApplicationContext
     */
    void setParent(ApplicationContext parent);

    /**
     * Return the Environment for this application context in configurable form.
     */
    @Override
    ConfigurableEnvironment getEnvironment();

    /**
     * Set the {@code Environment} for this application context.
     * @param environment the new environment
     */
    void setEnvironment(ConfigurableEnvironment environment);

    /**
     * Add a new BeanFactoryPostProcessor that will get applied to the internal
     * bean factory of this application context on refresh, before any of the
     * bean definitions get evaluated. To be invoked during context configuration.
     * @param beanFactoryPostProcessor the factory processor to register
     */
    void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor);

    /**
     * Add a new ApplicationListener that will be notified on context events
     * such as context refresh and context shutdown.
     * <p>Note that any ApplicationListener registered here will be applied
     * on refresh if the context is not active yet, or on the fly with the
     * current event multicaster in case of a context that is already active.
     * @param listener the ApplicationListener to register
     * @see org.springframework.context.event.ContextRefreshedEvent
     * @see org.springframework.context.event.ContextClosedEvent
     */
    void addApplicationListener(ApplicationListener<?> listener);

    /**
     * Load or refresh the persistent representation of the configuration,
     * which might an XML file, properties file, or relational database schema.
     * <p>As this is a startup method, it should destroy already created singletons
     * if it fails, to avoid dangling resources. In other words, after invocation
     * of that method, either all or no singletons at all should be instantiated.
     * @throws BeansException if the bean factory could not be initialized
     * @throws IllegalStateException if already initialized and multiple refresh
     * attempts are not supported
     */
    void refresh() throws BeansException, IllegalStateException;

    /**
     * Register a shutdown hook with the JVM runtime, closing this context
     * on JVM shutdown unless it has already been closed at that time.
     * <p>This method can be called multiple times. Only one shutdown hook
     * (at max) will be registered for each context instance.
     * @see java.lang.Runtime#addShutdownHook
     * @see #close()
     */
    void registerShutdownHook();

    /**
     * Close this application context, releasing all resources and locks that the
     * implementation might hold. This includes destroying all cached singleton beans.
     * <p>Note: Does <i>not</i> invoke {@code close} on a parent context;
     * parent contexts have their own, independent lifecycle.
     * <p>This method can be called multiple times without side effects: Subsequent
     * {@code close} calls on an already closed context will be ignored.
     */
    @Override
    void close();

    /**
     * Determine whether this application context is active, that is,
     * whether it has been refreshed at least once and has not been closed yet.
     * @return whether the context is still active
     * @see #refresh()
     * @see #close()
     * @see #getBeanFactory()
     */
    boolean isActive();

    /**
     * Return the internal bean factory of this application context.
     * Can be used to access specific functionality of the underlying factory.
     * <p>Note: Do not use this to post-process the bean factory; singletons
     * will already have been instantiated before. Use a BeanFactoryPostProcessor
     * to intercept the BeanFactory setup process before beans get touched.
     * <p>Generally, this internal factory will only be accessible while the context
     * is active, that is, inbetween {@link #refresh()} and {@link #close()}.
     * The {@link #isActive()} flag can be used to check whether the context
     * is in an appropriate state.
     * @return the underlying bean factory
     * @throws IllegalStateException if the context does not hold an internal
     * bean factory (usually if {@link #refresh()} hasn't been called yet or
     * if {@link #close()} has already been called)
     * @see #isActive()
     * @see #refresh()
     * @see #close()
     * @see #addBeanFactoryPostProcessor
     */
    ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

}

AbstractApplicationContext,看了这个抽象类,仿佛终于看到了一丝胜利的曙光了。
第一,这个类是抽象类,说明离真正的实现不远了;
第二,这个类基本上实现了多数的接口,一定程度说明这个类就是spring context的核心类,提前浏览了下它后面的几个子类,里面只是一些抽象方法的子类实现,所以,初步判断掌握此类就可以掌握spring context初始化过程。

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean

AbstractApplicationContext是个抽象类,继承自DefaultResourceLoader,ConfigurableApplicationContext,DisposableBean,不得不佩服java不支持多继承的缺陷,逼迫开发人员使用DefaultResourceLoader作为直接父类也是没谁了,首先说明AbstractApplicationContext是一个资源类;同时,继承了两个接口ConfigurableApplicationContext, DisposableBean,DisposableBean中只有一个destroy方法,但是想起来之前继承过Closeable接口,里面是个close方法,很奇怪destroy方法和closeable方法之间有啥区别?查看AbstractApplicationContext中的实现后发现destroy方法中啥也没干,直接调用了close方法。。。ConfigurableApplicationContext接口前面已经提过。

    @Override
    public void destroy() {
        close();
    }

    /**
     * Close this application context, destroying all beans in its bean factory.
     * <p>Delegates to {@code doClose()} for the actual closing procedure.
     * Also removes a JVM shutdown hook, if registered, as it's not needed anymore.
     * @see #doClose()
     * @see #registerShutdownHook()
     */
    @Override
    public void close() {
        synchronized (this.startupShutdownMonitor) {
            doClose();
            // If we registered a JVM shutdown hook, we don't need it anymore now:
            // We've already explicitly closed the context.
            if (this.shutdownHook != null) {
                try {
                    Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
                }
                catch (IllegalStateException ex) {
                    // ignore - VM is already shutting down
                }
            }
        }
    }

我们再一起看下AbstractApplicationContext中的实现,从之前的继承层次来看,AbstractApplicationContext继承了LifecycleProcessor,ResourcePatternResolver,MessageSource,在AbstractApplicationContext定义了三个对象:

    /** ResourcePatternResolver used by this context */
    private ResourcePatternResolver resourcePatternResolver;

    /** LifecycleProcessor for managing the lifecycle of beans within this context */
    private LifecycleProcessor lifecycleProcessor;

    /** MessageSource we delegate our implementation of this interface to */
    private MessageSource messageSource;

很显然,AbstractApplicationContext没有自己去直接实现相关接口,而是委托给了这几个接口的实现类来进行具体的操作(其实整个AbstractApplicationContext都是这样设计思路,后面会看其他接口的实现策略),这样设计可以避免AbstractApplicationContext太过臃肿,同时这几个接口的实现类还可以被多个类复用,这也算是组合优于继承的典型应用吧。既然有这三个实现类,那么必定会有他们的初始化过程。

下面是initMessageSource的初始化过程。可以看到会先获取一个BeanFactory,判断该BeanFactory中是否包含该bean,如果包含该bean,则从BeanFactory中取出该实例;否则使用默认的DelegatingMessageSource作为具体实现,再将该实例注册到BeanFactory中。同时,从第一个if分支可以看出,HierarchicalMessageSource也存在层次。

    /**
     * Initialize the MessageSource.
     * Use parent's if none defined in this context.
     */
    protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
            this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
            // Make MessageSource aware of parent MessageSource.
            if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
                HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
                if (hms.getParentMessageSource() == null) {
                    // Only set parent context as parent MessageSource if no parent MessageSource
                    // registered already.
                    hms.setParentMessageSource(getInternalParentMessageSource());
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Using MessageSource [" + this.messageSource + "]");
            }
        }
        else {
            // Use empty MessageSource to be able to accept getMessage calls.
            DelegatingMessageSource dms = new DelegatingMessageSource();
            dms.setParentMessageSource(getInternalParentMessageSource());
            this.messageSource = dms;
            beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
                        "': using default [" + this.messageSource + "]");
            }
        }
    }

initLifecycleProcessor的初始化过程。跟initMessageSource类似,beanFactory中可以查找到该bean则从beanFactory中取,否则使用默认的DefaultLifecycleProcessor。

    /**
     * Initialize the LifecycleProcessor.
     * Uses DefaultLifecycleProcessor if none defined in the context.
     * @see org.springframework.context.support.DefaultLifecycleProcessor
     */
    protected void initLifecycleProcessor() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
            this.lifecycleProcessor =
                    beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
            if (logger.isDebugEnabled()) {
                logger.debug("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
            }
        }
        else {
            DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
            defaultProcessor.setBeanFactory(beanFactory);
            this.lifecycleProcessor = defaultProcessor;
            beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate LifecycleProcessor with name '" +
                        LIFECYCLE_PROCESSOR_BEAN_NAME +
                        "': using default [" + this.lifecycleProcessor + "]");
            }
        }
    }

resourcePatternResolver在构造函数中初始化,直接使用getResourcePatternResolver方法返回一个默认的PathMatchingResourcePatternResolver对象

    /**
     * Create a new AbstractApplicationContext with no parent.
     */
    public AbstractApplicationContext() {
        this.resourcePatternResolver = getResourcePatternResolver();
    }

    protected ResourcePatternResolver getResourcePatternResolver() {
        return new PathMatchingResourcePatternResolver(this);
    }

ApplicationContext继承的接口中支持发布事件,通知具体的监听器做出相应的动作。ApplicationEventMulticaster负责监听器的注册以及通知工作,具体为负责发布事件到监听器的是publishEvent方法。

    @Override
    public void publishEvent(ApplicationEvent event) {
        Assert.notNull(event, "Event must not be null");
        if (logger.isTraceEnabled()) {
            logger.trace("Publishing event in " + getDisplayName() + ": " + event);
        }
        getApplicationEventMulticaster().multicastEvent(event);
        if (this.parent != null) {
            this.parent.publishEvent(event);
        }
    }

initApplicationEventMulticaster对负责事件广播的ApplicationEventMulticaste对象进行初始化。仍然是从BeanFactory优先获取,其他使用默认的SimpleApplicationEventMulticaster进行事件广播。

    protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isDebugEnabled()) {
                logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                        APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                        "': using default [" + this.applicationEventMulticaster + "]");
            }
        }
    }

LifeCycle接口的具体实现LifecycleProcessor。start之后,通过广播发布上下文启动事件ContextStartedEvent,触发相应监听器做出相应动作;stop之后也是类似。isRunning仅返回processring的状态。

    @Override
    public void start() {
        getLifecycleProcessor().start();
        publishEvent(new ContextStartedEvent(this));
    }

    @Override
    public void stop() {
        getLifecycleProcessor().stop();
        publishEvent(new ContextStoppedEvent(this));
    }

    @Override
    public boolean isRunning() {
        return getLifecycleProcessor().isRunning();
    }

小知识点来了,JVM在关闭之前会调用注册的hook,注册方法为Runtime.getRuntime().addShutdownHook(JVM自身提供),这个hook(实际为一个线程)可以保证JVM关闭之前被调用。这个方法在我们实现其他组件时也非常好用。

    @Override
    public void registerShutdownHook() {
        if (this.shutdownHook == null) {
            // No shutdown hook registered yet.
            this.shutdownHook = new Thread() {
                @Override
                public void run() {
                    doClose();
                }
            };
            Runtime.getRuntime().addShutdownHook(this.shutdownHook);
        }
    }

getBeanFactory是该抽象类中的关键方法,因为该BeanFactory代理了AbstractApplicationContext中所有涉及bean操作的方法,该方法需要在子类中进行实现。

public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

最重要的方法登场:public void refresh(),该方法负责所有bean信息的加载,bean的初始化等工作,名副其实的大佬。由于其涉及的工作比较多,留到后面分析。

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }
        }
    }

到这里,整体AbtractApplicationContext所涉及的工作就比较清楚了,它包括了上下文的启动停止,bean的加载、创建、查询,监听器的注册,广播事件的发布等。当子类继承了该抽象类,实现了具体抽象类后,我们便可以使用spring上下文做真正的工作了。

AbstractRefreshableApplicationContext继承自AbstractApplicationContext。实现的方法主要是对BeanFactory的操作(创建、刷新、销毁等)。

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext

AbstractRefreshableApplicationContext通过实现refreshBeanFactory()方法,支持多次调用重建BeanFactory,如下:

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

createBeanFactory方法负责创建BeanFactory,类型为DefaultListableBeanFactory。

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

新增抽象方法loadBeanDefinitions,由子类负责实现。

protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
            throws BeansException, IOException;

AbstractRefreshableConfigApplicationContext是AbstractRefreshableApplicationContext的子类,仍然为抽象类,继承了两个接口BeanNameAware, InitializingBean,InitializingBean只有一个方法:void afterPropertiesSet(),此方法会在某些属性全部设置后触发,偷看了下子类实现,该实现调用了下refresh这个关键方法。BeanNameAware接口也只有一个方法,setBeanName(String),看了下方法实现,实际上就是设置ApplicationContext的名称。AbstractRefreshableConfigApplicationContext抽象类中主要增加了configLocations属性,并支持该属性的设置和获取,该抽象类是xml上下文的基类。

public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
        implements BeanNameAware, InitializingBean {
            private String[] configLocations;
            ...
        }

到这里,已经快抵达终点了,加把劲,继续分析。抽象类AbstractXmlApplicationContext直接继承自父类AbstractRefreshableConfigApplicationContext。

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext

这个类已经非常清楚了,因为从名字上就可以看出来它到底负责什么功能,它主要方法都负责架加载bean的信息,通过XmlBeanDefinitionReader读取xml配置信息后对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);
    }

ClassPathXmlApplicationContext,用户使用的实现类,支持解析xml配置的spring上下文,继承自AbstractXmlApplicationContext。该类比较简单,使用时只需要把xml配置名称传入即可。整个类基本是各种构造函数,没有什么要说的。

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext 

至此,ClassPathXmlApplicationContext整体层次结构已经比较清晰。最后再总结下,ClassPathXmlApplicationContext:它是一个BeanFactory,所以它具有所有获取bean状态,获取bean定义,获取bean对象的一系列方法;它是一个资源加载器,它可以查找相关资源文件,加载相应的xml配置为bean定义信息;它具有生命周期,可以启动、停止、获取其运行状态;它具有层次,可以获取自己的parent;它具有一些工具类(MessageSource,LifeCycle等),虽然它本身继承了相关接口,但是它自己并不实现这些接口,而是通过组合方式直接使用相关代理类执行继承的接口操作,增强了程序的扩展性,也让这些代理类在其他地方可以复用,减少了需要实现的接口方法。本文主要剖析了ClassPathXmlApplicationContext的整体继承模型以及列出了本人觉得可能是重点功能的函数方法。类似refresh这种重点函数并没有阅读,是因为这些内部涉及更多的类之间的组合关系,工作量较大,留待后续学习。

相关文章

网友评论

    本文标题:Spring学习1-ClassPathXmlApplicatio

    本文链接:https://www.haomeiwen.com/subject/wvfhiftx.html