美文网首页Spring
【啃啊啃 Spring5 源码】细碎四:核心类总结

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

作者: MrDTree | 来源:发表于2018-09-09 22:22 被阅读148次

    [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中不同资源读取需求写不同代码的困难。

    常见子类

    • ClassPathResource:对class文件的读取,默认路径为项目根路径(/target),也可指定Class或ClassLoader来获取不同路径。
    • FileSystemResource:对文件系统资源的读和写,路径为文件系统路径,例如windos中:“D://a.json”
    • ByteArrayResource:对byte[]数组资源的读取
    • UrlResource:对url网络资源的读取
    • ServletContextResource:对web工程中文件的读取。通过ServletContext读取webRoot目录下的资源
    • InputStreamResource:对输入流资源的读取,直接通过给定的输入流读取。
    • BeanDefinitionResource:对BeanDefinition的读取,主要通过getBeanDefinition()方法,而不是getInputStream()

    1.2 ResourceLoader

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

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

    常见子类

    • DefaultResourceLoaderResourceLoader的基本功能实现类。返回Resource的策略为:location中包含“classpath:”,则返回ClassPathResource;包含“/”或出现异常返回ClassPathContextResource;其他情况返回UrlResource
    • FileSystemResourceLoader:继承DefaultResourceLoader,重写getResourceByPath()方法,返回文件资源加载类FileSystemContextResource
    • ServletContextResourceLoader:继承DefaultResourceLoader,重写getResourceByPath()方法,返回servletContext资源加载类ServletContextResource
      image.png

    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后返回。

    常见子类

    • PathMatchingResourcePatternResolver:接口的基础功能实现类,从类名也可看出,可解析通配符路径(如“application*.xml”)来返回Resources
    • ServletContextResourcePatternResolver:解析webRoot目录下的通配符路径,返回Resources
    • ApplicationContext:spring中的容器接口也继承了ResourcePatternResolver接口,代表spring中的所有容器都有根据通配符路径获取资源的功能

    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的形式存在。

    常见子类

    • MapPropertySource:source为一个Map,也就是键值对存在Map中
    • PropertiesPropertySource:从名字也可以看出,该类代表properties文件中键值对。继承MapPropertySource,source为Properties对象(Properties继承了HashMap,所以PropertiesPropertySource也是一个MapPropertySource)。
    • SystemEnvironmentPropertySource:继承MapPropertySource,source为Map对象,代表系统中的环境变量,如JAVA_HOME、MABEN_HOME之类。 与MapPropertySource不同的是,取值时它将会忽略大小写,”.”和”_”将会转化
    • ResourcePropertySource:source为Resource,代表spring中resource资源(例如:“/com/myco/foo.properties”、“file:/path/to/file.xml”)中的键值对属性
    • ServletContextPropertySource:source为ServletContext,代表web环境中的servlet上下文中的参数

    2.2 PropertySources

    public interface PropertySources extends Iterable<PropertySource<?>> {
    
        /**
         * 返回是否包含该名称的PropertySource
         */
        boolean contains(String name);
    
        /**
         *返回指定名称的PropertySource
         */
        @Nullable
        PropertySource<?> get(String name);
    
    }
    

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

    常见子类

    • MutablePropertySources:PropertySources接口的默认也是唯一实现类,内部维护了一个PropertySource的集合(CopyOnWriteArrayList实现)。支持向集合的头部、末尾、及指定位置添加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>
    

    常见子类

    • AbstractEnvironmentEnvironment的具体功能实现类
    • StandardEnvironment:标准环境类,会自动注册System.getProperties()中的属性到环境中。spring应用启动时采用该环境类。
    • StandardServletEnvironment:标准servlet环境类,web应用时采用。

    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、属性、描述、懒加载等配置信息。

    常见子类

    • GenericBeanDefinition:一个综合性的标准BeanDefiniton,包含了BeanDefinition中的主要功能
    • AnnotatedGenericBeanDefinition:一个注解式的标准BeanDefiniton,继承了GenericBeanDefinition,在其基础上增加了对类注解配置的支持,即可通过该类获取注解配置。
    • ConfigurationClassBeanDefinition:如果spring中的配置是用类来表示的,则解析后生成的bean配置类为该类
    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

    常见子类

    • DefaultListableBeanFactory:这个类是spring容器功能的核心类,它实现了BeanDefinitionRegistry接口,代表spring中的beanFactory基本都有注册、删除BeanDefinition的功能
    • GenericApplicationContext:从类名也可以看出,该类是spring上下文的主要功能实现类,该类对BeanDefinition的注册、删除,实际是委托DefaultListableBeanFactory来实现
    • SimpleBeanDefinitionRegistryBeanDefinitionRegistry接口功能的简单实现,主要用来测试功能的……

    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实现。

    常见子类

    • AbstractBeanDefinitionReaderBeanDefinitionReader接口的主要功能实现抽象类
    • PropertiesBeanDefinitionReader:用于从properties文件中加载注册BeanDefinition(ps:我也是第一次知道,properties文件也可以配置bean,配置方式可见该类注释)
    • XmlBeanDefinitionReader:用于从xml文件中加载注册BeanDefinition

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

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

    • AnnotatedBeanDefinitionReader:该类并没有实现BeanDefinitonReader接口,主要根据bean class来加载注册BeanDefinition
    • ClassPathBeanDefinitionScanner:从类名也可以看出,该类主要是扫描classpath中的注解类(@Component、@Repository、@Service、@Controller),然后加载注册对应的BeanDefinition

    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的属性转换功能。

    常见子类

    • BeanWrapperImplBeanWrapper接口的默认实现。继承了AbstractNestablePropertyAccessor类,父类中的registerCustomEditor()方法可增加自定义的PropertyEditor属性编辑器(PropertyEditor和ConversionService一样用于属性的转换,具体可看:SpringMVC数据类型转换

    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下面有三个子接口:

    • HierarchicalBeanFactory:提供容器分层功能,通过getParentBeanFactory()方法获取父容器
    • ListableBeanFactory:和类名一样,提供了getBeanDefinitionNames()列出容器内所有bean的名字、根据 “type” 获取所有bean名字 等方法
    • AutowireCapableBeanFactory:提供了自动装配的功能,根据类定义BeanDefinition装配Bean、执行前、后处理器等。

    主要接口:

    • ConfigurableBeanFactory:该接口包含大量容器工厂的配置方法,从bean的注册、加载、销毁、依赖,到后处理器的添加,以及属性编辑器和类型转换……
    • ConfigurableListableBeanFactoryConfigurableBeanFactory接口的补充,另外还继承了其余的beanFactory接口,基本包含了BeanFactory体系目前的所有方法,可以看成BeanFactory体系中功能最完善的接口
    • ApplicationContext:spring容器的核心接口,继承了BeanFactory体系的接口,在其功能上增加了资源加载、事件体制、环境配置、国际化支持、bean生命周期管理等功能

    核心类:

    • DefaultListableBeanFactory:实现了ConfigurableListableBeanFactory接口,spring容器最重要的一个核心类。实现了容器的大部分功能。已经废弃的XmlBeanFactory便是继承自它。而现在我们使用的ApplicationContext容器子类,也都是组合的它来实现重要功能

    相关文章

      网友评论

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

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