Spring

【啃啊啃 Spring5 源码】细碎四:核心类总结

2018-09-09  本文已影响148人  MrDTree

[TOC]

阅读spring源码时,有许多 “核心类” 的作用我们了解了,才会阅读的更顺畅。这里总结下我阅读源码时认为比较重要,需要了解的一些 “核心类”

注:本文前三节 为参考【Spring4揭秘 基础2】PropertySource和Enviroment系列文章,进行的总结扩展

1. 资源配置相关

1.1 Resource

public interface Resource extends InputStreamSource {  
       URL getURL() throws IOException;  
       URI getURI() throws IOException;  
       File getFile() throws IOException;  
       
       …………
}  

Resource 主要是对spring中各种资源(包括文件系统资源、class路径资源、Byte、servletContext资源、url资源)的抽象,spring中xml配置文件便是通过Resource 子类读取。

它继承了InputStreamSource接口,子类通过重写getInputStream()方法,便可轻松的读取各种资源。解决了Java中不同资源读取需求写不同代码的困难。

常见子类

1.2 ResourceLoader

public interface ResourceLoader {
     /**
      * 根据给定的路径,返回不同的Resource。例如路径中包含“classpath:”,则返回ClassPathResource
       */
    Resource getResource(String location);
}

从源码也可以看出,ResourceLoader其实就是Resource的工厂类。根据资源位置 “location” 的不同,返回不同的Resource供使用者读取资源。

常见子类

1.3 ResourcePatternResolver

public interface ResourcePatternResolver extends ResourceLoader {

    /**
     * 多resource匹配location 前缀
     */
    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    /**
     * 根据给定路径返回多个资源
     */
    Resource[] getResources(String locationPattern) throws IOException;
}

ResourcePatternResolver继承ResourceLoader接口,增加了getResources()方法用于根据匹配多个资源返回。例如对于路径:“classpath:.xml” 将匹配class路径下的所有的xml文件,加载成对应Resource后返回。

常见子类

2. 环境属性相关

2.1 PropertySource

public abstract class PropertySource<T> {
    protected final String name;//属性源名称
    protected final T source;//属性源(包含键值对的对象,如Properties、Map、ServletContext等)
    public String getName();  //获取属性源的名字  
    public T getSource();        //获取属性源  
    public boolean containsProperty(String name);  //是否包含某个属性  
    public abstract Object getProperty(String name);   //得到属性名对应的属性值   
} 

PropertySource 代表包含若干键值对(key-value)的数据源(source)。这个源可以是PropertiesMapServletContext等。在spring中,读取的propertie配置、servlet中的环境参数、乃至JDK系统参数、系统变量,都会以PropertySource的形式存在。

常见子类

2.2 PropertySources

public interface PropertySources extends Iterable<PropertySource<?>> {

    /**
     * 返回是否包含该名称的PropertySource
     */
    boolean contains(String name);

    /**
     *返回指定名称的PropertySource
     */
    @Nullable
    PropertySource<?> get(String name);

}

PropertySources即多个PropertySource,可看成PropertySource集合。

常见子类

2.3 PropertyResolver

public interface PropertyResolver {  

    //是否包含某个属性  
    boolean containsProperty(String key);  

    //获取属性值 如果找不到返回null   
    String getProperty(String key);  

    //获取属性值,如果找不到返回默认值        
    String getProperty(String key, String defaultValue);  

    //获取指定类型的属性值,找不到返回null  
    <T> T getProperty(String key, Class<T> targetType);  

    //获取指定类型的属性值,找不到返回默认值  
    <T> T getProperty(String key, Class<T> targetType, T defaultValue);  

    //获取属性值为某个Class类型,找不到返回null,如果类型不兼容将抛出ConversionException  
    <T> Class<T> getPropertyAsClass(String key, Class<T> targetType);  

    //获取属性值,找不到抛出异常IllegalStateException  
    String getRequiredProperty(String key) throws IllegalStateException;  

    //获取指定类型的属性值,找不到抛出异常IllegalStateException         
    <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;  

    //替换文本中的占位符(${key})到属性值,找不到不解析  
    String resolvePlaceholders(String text);  

    //替换文本中的占位符(${key})到属性值,找不到抛出异常IllegalArgumentException  
    String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;  
}  

实现PropertyResolver接口的子类,一般拥有了PropertySources的成员变量,该接口主要用于从PropertySources中获取对应属性。

从接口的resolvePlaceholders()方法可以看出,该接口还有解析文本,将文本中占位符转换为PropertySources对应属性的功能。spring配置文件中的占位符最后便是这样被替换成对应的属性。

2.4 Environment

public interface Environment extends PropertyResolver {  
        //得到当前激活的配置环境 
    String[] getActiveProfiles();  

        //得到默认激活的配置环境
    String[] getDefaultProfiles();  

        //是否接受某些配置环境
    boolean acceptsProfiles(String... profiles);  
}  

Environment接口继承了PropertyResolver接口,主要添加了“激活配置环境”功能。

在实际开发中,一般维护了多套开发环境,例如:dev、test、uat、prodcut。每种开发环境的配置是有差别的,spring中实现了多环境配置的功能:

如下,定义了test、dev两个配置环境,它们加载的bean并不相同,启动spring时,可指定active profile来加载指定配置环境下的bean

    <beans profile="test">
        <bean class="test.wsz.spring.aop.AspectDemo" />
        <bean id="a" class="test.wsz.spring.bean.A" >
            <constructor-arg value="wsz1" index="0" />
        </bean>
    </beans>

    <beans profile="dev">
        <bean id="b" class="test.wsz.spring.bean.B" />
        <bean class="test.wsz.spring.postProcess.MyBeanPostProcessor" />
    </beans>

常见子类

3. bean配置相关

spring中bean对象的生成可以分成两步:

  1. 读取配置文件中bean的配置,将其转换为bean配置类:BeanDefinition(持有beanName、beanClass、properties等信息)
  2. 根据BeanDefinition中的配置信息,实例化并初始化bean

本节主要介绍第一步,bean配置相关的类。

3.1 BeanDefinition

ublic interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    //单例或原型
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; 
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

     //Bean角色
    int ROLE_APPLICATION = 0; 
    int ROLE_SUPPORT = 1; 
    int ROLE_INFRASTRUCTURE = 2;

    // 返回/设置父BeanDefinition 
    String getParentName(); 
    void setParentName(String parentName);

    //返回/设置 当前的BeanClassName(不等于最终Bean的名称)
    String getBeanClassName(); 
    void setBeanClassName(String beanClassName);

    //返回设置 factory bean name  
    String getFactoryBeanName(); 
    void setFactoryBeanName(String factoryBeanName);

    String getFactoryMethodName(); 
    void setFactoryMethodName(String factoryMethodName);
    
    //返回/设置 bean的Scope:单例、原型等等
    String getScope(); 
    void setScope(String scope);

    //返回/设置 bean是否懒加载
    boolean isLazyInit(); 
    void setLazyInit(boolean lazyInit);

    String[] getDependsOn(); 
    void setDependsOn(String... dependsOn);

    boolean isAutowireCandidate(); 
    void setAutowireCandidate(boolean autowireCandidate);

    boolean isPrimary(); 
    void setPrimary(boolean primary);

    ConstructorArgumentValues getConstructorArgumentValues();
    
    //返回/设置 bean的属性
    MutablePropertyValues getPropertyValues(); 
    boolean isSingleton(); 
    boolean isPrototype(); 
    boolean isAbstract(); 
    int getRole(); 
    String getDescription(); 
    String getResourceDescription(); 
    BeanDefinition getOriginatingBeanDefinition();
}

从接口方法可以看出,BeanDefiniton主要包含了bean的名称、class、scope、属性、描述、懒加载等配置信息。

常见子类

image.png

3.2 BeanDefinitionHolder

public class BeanDefinitionHolder implements BeanMetadataElement {

    private final BeanDefinition beanDefinition;

    private final String beanName;

    @Nullable
    private final String[] aliases;

    public boolean matchesName(@Nullable String candidateName) {
        ……省略
    }
}

从类代码中可以看出,BeanDefinitionHolder其实就是一个持有了beanDefinition和bean名称beanName,及bean的别名数组aliases的类。

matchesName()方法可以知道,该类能够在beanDefinition注册时,匹配占位符,如果匹配中则注册该BeanDefinition

3.3 BeanDefinitionRegistry

public interface BeanDefinitionRegistry extends AliasRegistry {

     // 注册一个BeanDeinition
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;

     // 删除注册的BeanDeinition
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    //获取注册的BeanDefinition
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    boolean containsBeanDefinition(String beanName);

    String[] getBeanDefinitionNames();

    int getBeanDefinitionCount();

    boolean isBeanNameInUse(String beanName);

}

BeanDefinitionRegistry接口定义了‘注册/获取BeanDefinition’的方法。实现该接口的子类一般都维护了一个BeanDeinition集合:Map<String, BeanDefinition> beanDefinitionMap

常见子类

3.4 BeanDefinitionReader

public interface BeanDefinitionReader {
    //获取BeanDefinition的注册器
    BeanDefinitionRegistry getRegistry();

    //获取用于加载配置的ResourceLoader(上文有提到)
    ResourceLoader getResourceLoader();

    //获取用于加载bean class的ClassLoader
    ClassLoader getBeanClassLoader();

    BeanNameGenerator getBeanNameGenerator();

        //加载解析配置,并注册解析后的BeanDefinition
    int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;

        //加载解析多个配置,并注册解析后的BeanDefinition
    int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;

    //根据配置路径,加载解析配置,并注册解析后的BeanDefinition
    int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;

    //根据多个配置路径,加载解析多个配置,并注册解析后的BeanDefinition
    int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;

}

BeanDefinitionReader接口的方法可以看出,这个接口主要实现了 直接从配置中加载并注册所有BeanDefinition的功能,注册的动作实际委托了BeanDefinitionRegister实现。

常见子类

扩展
上面的BeanDefinitionReader子类都是从配置文件中加载注册beanDefinition,但是实际应用中,我们经常采用注解方式来声明一个bean。那这中注解bean又是如何被发现并注册的呢?

注解式bean的加载注册,主要看两个类:

4. bean相关

4.1 BeanWrapper

public interface BeanWrapper extends ConfigurablePropertyAccessor {

    void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);

    int getAutoGrowCollectionLimit();

    //返回被包装的bean实例
    Object getWrappedInstance();

    //返回被包装的bean的class
    Class<?> getWrappedClass();

    //返回被包装的bean的属性集合
    PropertyDescriptor[] getPropertyDescriptors();

    //根据属性名称,返回被包装的bean的属性
    PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;

}

BeanWrapper是spring中bean的包装类的接口,从接口定义的方法可以看出,beanWrapper的子类包含bean的实例及属性信息。

它的父接口ConfigurablePropertyAccessor定义了setConversionService()方法来设置属性转换器(spring中ConversionService负责属性的转换,例如将 字符串“2018-08-20”转换为Date类型)。

ConfigurablePropertyAccessor继承的TypeConverter接口提供了属性转换的方法convertIfNecessary()。故BeanWrapper还有将bean中的属性进行转换的功能。

spring中实例化bean结束后,会将生成的BeanWrapper作为形参传给populateBean()方法,进行bean的初始化:即bean的属性设值。这个设值操作便会用到BeanWrapper的属性转换功能。

常见子类

4.2 ObjectFactory

public interface ObjectFactory<T> {

    //返回一个被工厂管理的实例
    T getObject() throws BeansException;

}

就是一个很简单工厂接口,在调用时返回实例。在【啃啊啃 Spring5 源码】细碎二:bean的循环依赖中我们看到过它的运用:

为了解决bean的循环依赖,bean在第一次获取时,生成的ObjectFactory对象,getObject()方法实际上会调用createBean()方法创建bean。而bean在创建的过程中,实例化完成后会重新创建ObjectFactory对象,getObject()方法会变成调用getEarlyBeanReference(),用于获取的缓存的实例化的bean。这样依赖bean再通过ObjectFactory工厂获取实例时,获取的便是缓存中的bean。

4.3 FactoryBean

public interface FactoryBean<T> {

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }

}

FactoryBean对应spring中的工厂类bean。即定义的bean实际是一个工厂,可获取bean。这里不引申了,有兴趣的同学可以自行百度了解。

最后比较下ObjectFactoryFactoryBeanBeanFactory

  1. ObjectFactoryFactoryBean很类似,都是工厂类,用于获取bean。区别在于ObjectFactory是在代码中根据场景手动调用getObject()方法获取bean,而FactoryBean是配置写好,spring会自动调用getObject()方法获取bean。
  2. BeanFactory是容器的父类,管理着bean,并不能简单的看成工厂类,和前两者区别很大

5. 容器相关

5.1 BeanFactory

public interface BeanFactory {

    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String name) throws BeansException;

    <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

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

    <T> T getBean(Class<T> requiredType) throws BeansException;

    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    boolean containsBean(String name);

    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    
    String[] getAliases(String name);

}

BeanFactory是spring容器的核心接口,spring中的容器类,都实现了该接口。定义了获取bean、获取bean类型、判断bean是否单例等基础方法。

常见子类

BeanFactory下面有三个子接口:

主要接口:

核心类:

上一篇 下一篇

猜你喜欢

热点阅读