阅读spring源码时,有许多 “核心类” 的作用我们了解了,才会阅读的更顺畅。这里总结下我阅读源码时认为比较重要,需要了解的一些 “核心类”
注:本文前三节 为参考【Spring4揭秘 基础2】PropertySource和Enviroment系列文章,进行的总结扩展
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()
public interface ResourceLoader {
/**
* 根据给定的路径,返回不同的Resource。例如路径中包含“classpath:”,则返回ClassPathResource
*/
Resource getResource(String location);
}
从源码也可以看出,ResourceLoader
其实就是Resource
的工厂类。根据资源位置 “location” 的不同,返回不同的Resource
供使用者读取资源。
常见子类:
- DefaultResourceLoader
:ResourceLoader
的基本功能实现类。返回Resource
的策略为:location中包含“classpath:”,则返回ClassPathResource
;包含“/”或出现异常返回ClassPathContextResource
;其他情况返回UrlResource
;
- FileSystemResourceLoader
:继承DefaultResourceLoader
,重写getResourceByPath()
方法,返回文件资源加载类FileSystemContextResource
- ServletContextResourceLoader
:继承DefaultResourceLoader
,重写getResourceByPath()
方法,返回servletContext资源加载类ServletContextResource
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中的所有容器都有根据通配符路径获取资源的功能
public abstract class PropertySource {
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)。这个源可以是Properties
、Map
、ServletContext
等。在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上下文中的参数
public interface PropertySources extends Iterable> {
/**
* 返回是否包含该名称的PropertySource
*/
boolean contains(String name);
/**
*返回指定名称的PropertySource
*/
@Nullable
PropertySource> get(String name);
}
PropertySources即多个PropertySource,可看成PropertySource集合。
常见子类:
- MutablePropertySources
:PropertySources接口的默认也是唯一实现类,内部维护了一个PropertySource的集合(CopyOnWriteArrayList实现)。支持向集合的头部、末尾、及指定位置添加PropertySource
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配置文件中的占位符最后便是这样被替换成对应的属性。
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>
常见子类:
- AbstractEnvironment
:Environment
的具体功能实现类
- StandardEnvironment
:标准环境类,会自动注册System.getProperties()
中的属性到环境中。spring应用启动时采用该环境类。
- StandardServletEnvironment
:标准servlet环境类,web应用时采用。
spring中bean对象的生成可以分成两步:
1. 读取配置文件中bean的配置,将其转换为bean配置类:BeanDefinition
(持有beanName、beanClass、properties等信息)
2. 根据BeanDefinition
中的配置信息,实例化并初始化bean
本节主要介绍第一步,bean配置相关的类。
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配置类为该类
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
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
常见子类:
- DefaultListableBeanFactory
:这个类是spring容器功能的核心类,它实现了BeanDefinitionRegistry
接口,代表spring中的beanFactory基本都有注册、删除BeanDefinition的功能
- GenericApplicationContext
:从类名也可以看出,该类是spring上下文的主要功能实现类,该类对BeanDefinition的注册、删除,实际是委托DefaultListableBeanFactory
来实现
- SimpleBeanDefinitionRegistry
:BeanDefinitionRegistry
接口功能的简单实现,主要用来测试功能的……
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
实现。
常见子类:
- AbstractBeanDefinitionReader
:BeanDefinitionReader
接口的主要功能实现抽象类
- 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
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
的属性转换功能。
常见子类:
- BeanWrapperImpl
:BeanWrapper
接口的默认实现。继承了AbstractNestablePropertyAccessor
类,父类中的registerCustomEditor()
方法可增加自定义的PropertyEditor属性编辑器(PropertyEditor和ConversionService一样用于属性的转换,具体可看:SpringMVC数据类型转换
)
public interface ObjectFactory {
//返回一个被工厂管理的实例
T getObject() throws BeansException;
}
就是一个很简单工厂接口,在调用时返回实例。在【啃啊啃 Spring5 源码】细碎二:bean的循环依赖中我们看到过它的运用:
为了解决bean的循环依赖,bean在第一次获取时,生成的ObjectFactory对象,getObject()
方法实际上会调用createBean()
方法创建bean。而bean在创建的过程中,实例化完成后会重新创建ObjectFactory对象,getObject()
方法会变成调用getEarlyBeanReference()
,用于获取的缓存的实例化的bean。这样依赖bean再通过ObjectFactory工厂获取实例时,获取的便是缓存中的bean。
public interface FactoryBean {
@Nullable
T getObject() throws Exception;
@Nullable
Class> getObjectType();
default boolean isSingleton() {
return true;
}
}
FactoryBean
对应spring中的工厂类bean。即定义的bean实际是一个工厂,可获取bean。这里不引申了,有兴趣的同学可以自行百度了解。
最后比较下ObjectFactory
、FactoryBean
和BeanFactory
:
1. ObjectFactory
和FactoryBean
很类似,都是工厂类,用于获取bean。区别在于ObjectFactory
是在代码中根据场景手动调用getObject()
方法获取bean,而FactoryBean
是配置写好,spring会自动调用getObject()
方法获取bean。
2. BeanFactory
是容器的父类,管理着bean,并不能简单的看成工厂类,和前两者区别很大
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
T getBean(String name, @Nullable Class requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
T getBean(Class requiredType) throws BeansException;
T getBean(Class 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的注册、加载、销毁、依赖,到后处理器的添加,以及属性编辑器和类型转换……
- ConfigurableListableBeanFactory
:ConfigurableBeanFactory
接口的补充,另外还继承了其余的beanFactory接口,基本包含了BeanFactory体系目前的所有方法,可以看成BeanFactory体系中功能最完善的接口
- ApplicationContext
:spring容器的核心接口,继承了BeanFactory体系的接口,在其功能上增加了资源加载、事件体制、环境配置、国际化支持、bean生命周期管理等功能
核心类:
- DefaultListableBeanFactory
:实现了ConfigurableListableBeanFactory
接口,spring容器最重要的一个核心类。实现了容器的大部分功能。已经废弃的XmlBeanFactory
便是继承自它。而现在我们使用的ApplicationContext
容器子类,也都是组合的它来实现重要功能