文章目录
代码准备
新建一个简单的Java Bean
/**
* @ClassName Student
* @author: shouanzh
* @Description POJO: Plain Old Java Object 简单的java对象,也就是普通JavaBeans
* @date 2022/1/3 18:19
*/
public class Student {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
resources目录下编写applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.kernel.spring.bean.Student">
<property name="age" value="26"/>
<property name="name" value="zhangsan"/>
</bean>
</beans>
一个main方法
/*
IOC(Inverse of Control,控制反转) 本该由使用者来创建对象我们将指定资源交给工厂 此时由工厂进行创建其对应对象 将其加载到内存当中
DI (Dependency Injection,依赖注入) A中依赖B此时将A加载到IOC 此时B也得被加载到IOC 此时A才能被调用。 此时就称为依赖注入
关于Spring容器管理Bean的过程以及加载模式:
1.需要将bean的定义信息声明在Spring的配置文件当中
2.需要通过Spring抽象出的各种Resource来指定对应的配置文件。
3.需要显示的声明一个Spring工厂,该工厂用来掌控我们在配置文件中所声明的各种bean以及bean之间的依赖关系与注入关系
4.需要定义一个配置信息读取器,该读取器用来读取之前所定义的bean配置文件信息
5.读取器的作用是读取我们所声明的配置文件信息,并且将读取后的信息装配到之前所声明的工厂当中
6.需要将读取器与工厂以及资源对象进行相应的关联处理。
7.工厂所管理的全部对象装配完毕,可以供客户端直接调用,获取客户端想要使用的各种bean对象。
Spring对于Bean管理的核心组件:
1.资源抽象ClassPathResource
2.工厂DefaultListableBeanFactory
3.配置信息读取器XmlBeanDefinitionReader (当读取器将资源读取到工厂当中 此时我们只需要跟工厂打交道)
BeanFactory 是Spring工厂 最顶层的抽象(类似Object类) 我们使用的抽象bean工厂都是直接或间接的衍生至BeanFactory
关于Spring Bean实例的注册流程
1.定义好Spring的配置文件。
2.通过Resource对象奖Spring配置文件进行抽象,抽象成一个具体的Resource对象(如ClassPathResource)。
3.定义好将要使用的Bean工厂(各种BeanFactory)。
4.定义好XmlBeanDefinitionReader对象,并将工厂对象作为参数传递进去,从而构建好二者之间的关联关系。
5.通过XmlBeanDefinitionReader对象读取之前所抽取出的Resource对象。
6.流程开始进行解析。
7.针对XML文件进行各种元素以及元素属性的解析,这里面,真正的解析是通过BeanDefinitionParserDelegate对象来完成的(委托模式)
8.通过BeanDefinitionParserDelegate对象在解析XML文件时,又使用到了模版方法设计模式(pre,process,post)。
9.当所有的bean标签元素都解析完毕后,开始定义一个BeanDefinition对象,该对象是一个非常重要的对象,里面容纳了一个Bean相关的所有属性。
10.BeanDefinition对象创建完毕后,Spring又会创建一个BeanDefinitionHolder对象来持有这个BeanDefinition对象。
11.BeanDefinitionHolder对象主要包含俩部分内容:beanName与BeanDefinition。
12.工厂会将解析出来的Bean信息存放到内部的一个ConcurrentHashMap中,该Map的键是beanName(唯一),值是BeanDefinition对象。
13.调用Bean解析完毕的触发动作,从而触发相应的监听器的方法的执行(使用了观察者模式)。
*/
public class SpringClient {
public static void main(String[] args) {
// 类路径下的资源 将其具体抽象成资源对象
Resource resource = new ClassPathResource("applicationContext.xml");
// 创建Bean工厂实例
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
// 创建bean读取器实例
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
// 将读取的资源放到defaultListableBeanFactory工厂当中
beanDefinitionReader.loadBeanDefinitions(resource);
// 读取完我们需要哪个对象找工厂要
Student student = (Student) defaultListableBeanFactory.getBean("student");
Student student2 = (Student) defaultListableBeanFactory.getBean("student");
System.out.println(student.getAge());
System.out.println(student.getName());
System.out.println(student == student2);
}
}
Spring容器管理Bean的过程以及加载模式
- 需要将bean的定义信息声明在Spring的配置文件当中
- 需要通过Spring抽象出的各种Resource来指定对应的配置文件。
- 需要显示的声明一个Spring工厂,该工厂用来掌控我们在配置文件中所声明的各种bean以及bean之间的依赖关系与注入关系
- 需要定义一个配置信息读取器,该读取器用来读取之前所定义的bean配置文件信息
- 读取器的作用是读取我们所声明的配置文件信息,并且将读取后的信息装配到之前所声明的工厂当中
- 需要将读取器与工厂以及资源对象进行相应的关联处理。
- 工厂所管理的全部对象装配完毕,可以供客户端直接调用,获取客户端想要使用的各种bean对象。
Spring对于Bean管理的核心组件
- 资源抽象ClassPathResource
- 工厂DefaultListableBeanFactory
- 配置信息读取器XmlBeanDefinitionReader (当读取器将资源读取到工厂当中 此时我们只需要跟工厂打交道)
IOC和DI概念
- IOC(Inverse of Control,控制反转) 本该由使用者来创建对象我们将指定资源交给工厂 此时由工厂进行创建其对应对象 将其加载到内存当中
- DI (Dependency Injection,依赖注入) A中依赖B此时将A加载到IOC 此时B也得被加载到IOC 此时A才能被调用。 此时就称为依赖注入
1.Resource概述及ClassPathResource源码分析
从底层资源的实际类型(例如文件或类路径资源)中抽象出来的资源描述符的接口。
Resource实现有:文件系统资源(FileSystemResource)、类路径资源(ClassPathResource)、字节数组资源(ByteArrayResource)、URL资源(UrlResource)等。
Resource源码
public interface Resource extends InputStreamSource {
/**
* 资源是否存在
*/
boolean exists();
/**
* 资源是否可读
*/
default boolean isReadable() {
return exists();
}
default boolean isOpen() {
return false;
}
/**
* 资源是否为 File
*/
default boolean isFile() {
return false;
}
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
/**
* 资源名
*/
@Nullable
String getFilename();
String getDescription();
}
ClassPathResource源码分析
类路径下的资源 将其具体抽象成资源对象
补充:
@NonNull 可以标注在方法、字段、参数之上,表示对应的值不可以为空
@Nullable 注解可以标注在方法、字段、参数之上,表示对应的值可以为空
// 类路径下的资源 将其具体抽象成资源对象
Resource resource = new ClassPathResource("applicationContext.xml");
/**
* 类路径资源的Resource实现。 使用给定的ClassLoader或给定的Class来加载资源。
*/
public class ClassPathResource extends AbstractFileResolvingResource {
// 文件路径 如:applicationContext.xml
private final String path;
// 类加载器
@Nullable
private ClassLoader classLoader;
@Nullable
private Class<?> clazz;
// 构造函数
// 为ClassLoader使用创建一个新的ClassPathResource 。
// 前导斜杠将被删除,因为 ClassLoader 资源访问方法将不接受它。
// 线程上下文类加载器将用于加载资源。
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}
// 为ClassLoader使用创建一个新的ClassPathResource 。
// 前导斜杠将被删除,因为 ClassLoader 资源访问方法将不接受它
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
// 将传过来的路径进行校正得到合法的路径
String pathToUse = StringUtils.cleanPath(path);
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
// 初始化文件路径
this.path = pathToUse;
// 指定类加载器,如果没有传类加载器,则用默认的类加载器,翻看源码是:Thread.currentThread().getContextClassLoader()
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
public ClassPathResource(String path, @Nullable Class<?> clazz) {
Assert.notNull(path, "Path must not be null");
this.path = StringUtils.cleanPath(path);
this.clazz = clazz;
}
@Deprecated
protected ClassPathResource(String path, @Nullable ClassLoader classLoader, @Nullable Class<?> clazz) {
this.path = StringUtils.cleanPath(path);
this.classLoader = classLoader;
this.clazz = clazz;
}
// 获取配置文件路径
public final String getPath() {
return this.path;
}
// 获取类加载器
@Nullable
public final ClassLoader getClassLoader() {
return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader);
}
// 判断文件是否存在
@Override
public boolean exists() {
return (resolveURL() != null);
}
@Nullable
protected URL resolveURL() {
try {
if (this.clazz != null) {
return this.clazz.getResource(this.path);
}
else if (this.classLoader != null) {
return this.classLoader.getResource(this.path);
}
else {
return ClassLoader.getSystemResource(this.path);
}
}
catch (IllegalArgumentException ex) {
// Should not happen according to the JDK's contract:
// see https://github.com/openjdk/jdk/pull/2662
return null;
}
}
// 此方法继承自InputStreamSource,ClassPathResource实现了具体逻辑
// 主要就是通过类加载器加载配置文件到内存 InputStream中
@Override
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.clazz != null) {
is = this.clazz.getResourceAsStream(this.path);
}
else if (this.classLoader != null) {
is = this.classLoader.getResourceAsStream(this.path);
}
else {
is = ClassLoader.getSystemResourceAsStream(this.path);
}
if (is == null) {
throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
}
return is;
}
@Override
public URL getURL() throws IOException {
URL url = resolveURL();
if (url == null) {
throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");
}
return url;
}
@Override
public Resource createRelative(String relativePath) {
String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
return (this.clazz != null ? new ClassPathResource(pathToUse, this.clazz) :
new ClassPathResource(pathToUse, this.classLoader));
}
@Override
@Nullable
public String getFilename() {
return StringUtils.getFilename(this.path);
}
@Override
public String getDescription() {
StringBuilder builder = new StringBuilder("class path resource [");
String pathToUse = this.path;
if (this.clazz != null && !pathToUse.startsWith("/")) {
builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));
builder.append('/');
}
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
builder.append(pathToUse);
builder.append(']');
return builder.toString();
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ClassPathResource)) {
return false;
}
ClassPathResource otherRes = (ClassPathResource) other;
return (this.path.equals(otherRes.path) &&
ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) &&
ObjectUtils.nullSafeEquals(this.clazz, otherRes.clazz));
}
@Override
public int hashCode() {
return this.path.hashCode();
}
}
ClassPathResource 初始化时主要保存 ClassPath路径下配置文件的路径,选择类加载器,然后在继承自 InputStreamResource 的方法 getInputStream中 通过 类加载器加载配置文件到内存(InputStream)中,供Reader使用。
2.创建Bean工厂实例
// 创建Bean工厂实例
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
看一下DefaultListableBeanFactory的类图。
首先跟进DefaultListableBeanFactory类的无参构造函数
/**
* Create a new DefaultListableBeanFactory.
*/
public DefaultListableBeanFactory() {
super();
}
可以看到什么都没有做,只是调用了父类的无参构造函数。我们来看看它的父类AbstractAutowireCapableBeanFactory的无参构造函数
/**
* Create a new AbstractAutowireCapableBeanFactory.
*/
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
if (NativeDetector.inNativeImage()) {
this.instantiationStrategy = new SimpleInstantiationStrategy();
}
else {
this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
}
}
可以看到其调用了父类的无参构造函数,接着调用了三次ignoreDependencyInterface方法,该方法其作用是指定自动装配(autowiring)的时候忽略的接口
打开BeanFactory ignoreDependencyInterface方法的正确姿势:参考https://www.jianshu.com/p/3c7e0608ff1f
我们来看看其调用的父类AbstractBeanFactory的无参构造函数
/**
* Create a new AbstractBeanFactory.
*/
public AbstractBeanFactory() {
}
其中什么都没有做。到这里没有再显式地调用父类的构造函数。
当我们再看AbstractBeanFactory的父类FactoryBeanRegistrySupport,FactoryBeanRegistrySupport的父类DefaultSingletonBeanRegistry,DefaultSingletonBeanRegistry的父类SimpleAliasRegistry的源码会发现其都没有写构造方法,也就是说其都是默认的空的无参构造函数。
3.Spring配置信息读取器加载流程解析
// 创建bean读取器实例
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
XmlBeanDefinitionReader,xml的bean定义的读取器
这里新建一个XmlBeanDefinitionReader对象,并以此前创建的DefaultListableBeanFactory的对象defaultListableBeanFactory作为参数。
/**
*为给定的bean工厂创建新的XmlBeanDefinitionReader。
*参数:
*registry–以BeanDefinitionRegistr的形式将bean定义加载到其中的BeanFactory
*/
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
再看其构造器,发现需要的参数只需要实现BeanDefinitionRegistry 接口即可,观察类图或者查看源码可知DefaultListableBeanFactory实现了BeanDefinitionRegistry接口
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
看一下BeanDefinitionRegistry源码
该接口中有bean定义数量和bean定义名称两个属性,有注册bean定义、移除bean定义,得到bean定义、判断是否包含bean定义、bean名称是否在使用等方法。
public interface BeanDefinitionRegistry extends AliasRegistry {
/**
* 在此注册表中注册一个新的bean定义。
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
/**
* 删除给定名称的Bean定义。
*/
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* 返回给定bean名称的bean定义。
*/
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* 检查此注册表是否包含具有给定名称的bean定义。
*/
boolean containsBeanDefinition(String beanName);
/**
* 返回此注册表中定义的所有bean的名称。
*/
String[] getBeanDefinitionNames();
/**
* 返回注册表中定义的bean数。
*/
int getBeanDefinitionCount();
/**
* 确定给定的bean名称是否已在此注册表中使用
*/
boolean isBeanNameInUse(String beanName);
}
XmlBeanDefinitionReader调用了父类的构造器如下:
/*
为给定的bean工厂创建一个新的AbstractBeanDefinitionReader。
如果传入的bean工厂不仅实现BeanDefinitionRegistry接口,还实现ResourceLoader接口,那么它也将用作默认的ResourceLoader。
如果给定普通BeanDefinitionRegistry,默认的ResourceLoader将是PathMatchingResourcePatternResolver。
如果传入的bean工厂也实现了Environmentable,那么该读取器将使用它的环境。
否则,读取器将初始化并使用StandardEnvironment。
所有ApplicationContext实现都支持环境,而普通BeanFactory实现则不支持环境。
参数:
registry–以BeanDefinitionRegistry的形式加载bean定义的BeanFactory
*/
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// bean工厂 defaultListableBeanFactory
this.registry = registry;
// Determine ResourceLoader to use.
// ResourceLoader 资源加载器
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
//初始化environment
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
}
}
首先进行必要的判空和赋值,然后判断传入的参数(这个registry对象参数肯定实现了BeanDefinitionRegistry ,但是否实现了ResourceLoader未知)是否实现了ResourceLoader。
我们这里传入的DefaultListableBeanFactory对象没有实现这个接口,因此在else里面,会新建一个PathMatchingResourcePatternResolver对象。
ResourceLoader提供 ClassPath下单资源文件的载入,而ResourcePatternResolver提供了多资源文件的载入。ResourcePatternResolver有一个实现类:PathMatchingResourcePatternResolver
初始化environment
Environment 是用来获取配置文件中的属性值。它主要为我们的应用程序环境的两个方面的支持:profiles 和 properties。
多种配置信息来源的一种抽象和提取。Environment定义了Profiles的方法处理。PropertyResolver定义了Property属性相关的处理
4.将读取的资源放到defaultListableBeanFactory工厂当中
// 将读取的资源放到defaultListableBeanFactory工厂当中
beanDefinitionReader.loadBeanDefinitions(resource);
这里使用了XmlBeanDefinitionReader类的loadBeanDefinitions方法加载Resource类的对象resource
/*
从指定的XML文件加载bean定义。
参数:
resource–XML文件的资源描述符
返回:
找到的bean定义数
抛出:
BeanDefinitionStoreException–在加载或分析错误的情况下
*/
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
// EncodedResource里封装的待解析的资源 和 编码的信息
return loadBeanDefinitions(new EncodedResource(resource));
}
这里首先将resource进行encode,作用是进行编码。然后我们看看loadBeanDefinitions的具体实现。
/*
从指定的XML文件加载bean定义。
参数:
encodedResource–XML文件的资源描述符,允许指定用于解析文件的编码
返回:
找到的bean定义数
抛出:
BeanDefinitionStoreException–在加载或分析错误的情况下
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
// XmlBeanDefinitionReader内部维护了一个private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded变量,
// 用于保存最近被加载的资源。
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
// 然后将传入的参数加入currentResources中
// set集合add 返回false 说明该资源已经加载
// 防止资源导入中AB互相依赖 循环导入 陷入死循环
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
// 检测到“+encodedResource+”的循环加载-检查您的导入定义!
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
// 获取资源文件的输入流 JDK 1.7 新特性 try-with-resources 自动释放资源
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
// SAX以流的方式解析XML文件 文件较大时效率比dom方式快
InputSource inputSource = new InputSource(inputStream);
// 如果编码不为空
if (encodedResource.getEncoding() != null) {
// 采用encodedResource的编码格式 解析xml
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
// 最后将传入的资源从最近被加载的资源中删除。
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
// threadLocal 是弱引用 使用完需要主动关闭 防止内存泄露
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
接下来看一下doLoadBeanDefinitions方法的实现
/*
实际上,从指定的XML文件加载bean定义。
参数:
inputSource–要读取的SAX inputSource
resource–XML文件的资源描述符
返回:
找到的bean定义数
抛出:
BeanDefinitionStoreException–在加载或分析错误的情况下
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
/*
Document接口表示整个HTML或XML文档。
从概念上讲,它是文档树的根,提供对文档数据的主要访问。
将XML数据封装成一个Document 他表示整个HTML或XML文档
*/
Document doc = doLoadDocument(inputSource, resource);
// 解析Document 文档数据 返回解析bean数量
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
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);
}
}
然后使用this.documentLoader.loadDocument方法来加载xml文档
private DocumentLoader documentLoader = new DefaultDocumentLoader();
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
让我们来看看DefaultDocumentLoader类的loadDocument方法。
@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
它有几个参数,分别是输入源inputSource,实体解析器entityResolver,错误处理器errorHandler,XML验证模式validationMode,namespaceAware。最终落实到DocumentBuilder的parse方法。
接着调用registerBeanDefinitions(doc, resource);
/*
注册给定DOM文档中包含的bean定义。由loadBeanDefinitions调用。
创建解析器类的新实例,并对其调用registerBeanDefinitions。
参数:
doc–DOM文档
resource–资源描述符(用于上下文信息)
返回:
找到的bean定义数
*/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 创建BeanDefinitionDocumentReader资源读取器,用于从XML文档中实际读取bean定义。
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获取工厂解析之前解析的数量
int countBefore = getRegistry().getBeanDefinitionCount();
// 通过解析器正式开始解析
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 解析后解析数-解析前解析数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
中场休息-小小结
紧接着DefaultBeanDefinitionDocumentReader调用其registerBeanDefinitions方法
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
@SuppressWarnings("deprecation")
// 其中root代表了xml文档的根元素 <beans></beans>
// 在给定的根<beans/>元素中注册每个bean定义。
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
// 采用委托模式解析<beans>
this.delegate = createDelegate(getReaderContext(), root, parent);
// delegate是默认的命名空间"http://www.springframework.org/schema/beans";
if (this.delegate.isDefaultNamespace(root)) {
// PROFILE_ATTRIBUTE = "profile";
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
// 判断是否有内容
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
/*该地方用到了模板方法模式
父类规定好执行流程 具体执行逻辑由子类自由扩展 并严格遵守父类定义好的执行流程
*/
preProcessXml(root); // 文档解析之前可以做的事情 可扩展
// 使用委托对象去解析rootElement数据
parseBeanDefinitions(root, this.delegate);
postProcessXml(root); //文档解析之后可以做的事情
//委托对象重新赋值
this.delegate = parent;
}
我们来看看parseBeanDefinitions方法
// Parse the elements at the root level in the document: "import", "alias", "bean".
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
首先判断是否是默认的命名空间,如果是,则执行parseDefaultElement,否则执行parseCustomElement。
我们这里是使用的默认的命名空间,因此接着调用getChildNodes方法获得<beans></beans>下面的子节点,也就是<bean></bean>。
然后对于每个子节点,根据当前是否是默认命名空间来调用不同方法解析。
我们这里先只看parseDefaultElement。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
这里分了3种情况,分别是节点标签名对应import alias 和bean的情况。
它们分别处理<import/> <alias/>和<bean/>
我们这里只涉及bean的解析。来看看。
/**
* 完成两件事情
* 1.处理给定的bean元素,解析bean定义
* 2.并将其注册到工厂中。
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// BeanDefinitionHolder顾名思义就是对BeanDefinition的持有,
// 同时持有的包括BeanDefinition的名称和别名
// 一个BeanDefinition 对应一个bean标签
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 这里是向IoC容器注册解析得到的BeanDefinition的地方。
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
parseBeanDefinitionElement
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 获取id 和 name属性值
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// 获取别名
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// beanName = id值
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 获取beanDefinition 对象 里面封装了当前bean的所有信息
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
// 获取到bean类的名字
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
// beanDefinition 解析的<Bean>标签下所有标签数据,id对应的name 别名数组
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
BeanDefinitionHolder是BeanDefinition的封装
而BeanDefinition可以看成是<bean>定义的抽象。
具体的加载过程由BeanDefinitionParserDelegate对XML元素的信息按照Spring的Bean规则进行解析得到的,入口是parseBeanDefinitionElement
// 解析bean定义本身,不考虑名称或别名。如果在分析bean定义期间出现问题,则可能返回null。
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
// CLASS_ATTRIBUTE = "class";
// 我们这里 <bean id="student" class="com.kernel.spring.bean.Student">
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
//如果元素有parent属性
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
//得到parent节点
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 根据parent创建AbstractBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析bean定义的属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 为bean定义设置描述
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析元数据
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析构造器参数元素
parseConstructorArgElements(ele, bd);
// 解析property属性元素 如 <property name="age" value="26"/>
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
// BeanDefinition 装配完毕
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
其中createBeanDefinition创建一个BeanDefinition的实现GenericBeanDefinition。然后调用parseConstructorArgElements、parsePropertyElements等解析构造器参数,解析属性元素等。
createBeanDefinition中直接使用BeanDefinitionReaderUtils.createBeanDefinition创建bean。
/*
为给定的类名和父名称创建bean定义。
参数:
className–bean类的名称
parentName–bean的父bean的名称
返回:
新创建的bean定义
*/
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
AbstractBeanDefinition
// beanClass代表俩层含义
// 1. Class对象
// 2. 待实例化的那个bean字符串表示 className
@Nullable
private volatile Object beanClass;
@Override
public void setBeanClassName(@Nullable String beanClassName) {
this.beanClass = beanClassName;
}
public String getBeanClassName() {
Object beanClassObject = this.beanClass;
if (beanClassObject instanceof Class) {
return ((Class<?>) beanClassObject).getName();
}
else {
return (String) beanClassObject;
}
}
public void setBeanClass(@Nullable Class<?> beanClass) {
this.beanClass = beanClass;
}
其中使用了ClassUtils加载类的定义,然后为BeanDefinition设置了bean的class属性。
parseBeanDefinitionAttributes 解析Bean定义属性
bean里各种属性
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 处理作用域
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
}
else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
// 设置作用域
bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
}
else if (containingBean != null) {
// Take default from containing bean in case of an inner bean definition.
bd.setScope(containingBean.getScope());
}
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (isDefaultValue(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire));
if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
}
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
if (isDefaultValue(autowireCandidate)) {
String candidatePattern = this.defaults.getAutowireCandidates();
if (candidatePattern != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
}
else {
bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
}
if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
}
if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
bd.setInitMethodName(initMethodName);
}
else if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
bd.setDestroyMethodName(destroyMethodName);
}
else if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
}
if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
}
return bd;
}
spring的scope属性默认是单例
然后回到:DefaultBeanDefinitionDocumentReader
/**
* 完成两件事情
* 1.处理给定的bean元素,解析bean定义
* 2.并将其注册到工厂中。
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// BeanDefinitionHolder顾名思义就是对BeanDefinition的持有,
// 同时持有的包括BeanDefinition的名称和别名
// 一个BeanDefinition 对应一个bean标签
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 对BeanDefinitionHolder进一步封装 如自定义标签
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 这里是向IoC容器注册解析得到的BeanDefinition的地方。
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
解析bean定义后,使用如下方法注册bean定义,这里的getReaderContext().getRegistry()就是最开始新建的工厂对象DefaultListableBeanFactory。
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
/*
向给定的bean工厂注册给定的bean定义。
参数:
definitionHolder–bean定义,包括名称和别名
注册表–要注册的bean工厂
抛出:
BeanDefinitionStoreException–如果注册失败
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
// 获取bean的名字
String beanName = definitionHolder.getBeanName();
// 将对应的bean注册到工厂上
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
// 注册bean名称的别名
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
再向给定的bean工厂注册给定的bean定义前已经获取到了bean的所有信息。
registry.registerBeanDefinition将对应的bean注册到工厂上
//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//---------------------------------------------------------------------
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
// bean的验证
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// ConcurrentHashMap中获取持有对象
// Spring是拿beanname 做key 持有对象做value 将数据存在 ConcurrentHashMap中
// 1.5 之前用的HashMap
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
// 判断是否存在同id的BeanDefinition
if (existingDefinition != null) {
// 允许Bean定义重写吗
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
// 若已存在的和需要装配的bean不同
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
// 如果不存在上述情况 加载到工厂当中(id做key,beanDefinition做value)
this.beanDefinitionMap.put(beanName, beanDefinition);
}
// 不存在
else {
// 检查工厂的bean创建阶段是否已经开始,即是否有bean被标记为已创建。
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
该beanDefinitionMap是DefaultListableBeanFactory工厂的一个属性。此时将bean的唯一id做key ,解析bean BeanDefinition 做value 存储的工厂当中当中
此时我们将Spring读取的资源放到DefaultListableBeanFactory工厂中的底层源码流程解析完毕。
Spring Bean实例的注册流程总结
- 1.定义好Spring的配置文件。
- 2.通过Resource对象奖Spring配置文件进行抽象,抽象成一个具体的Resource对象(如ClassPathResource)。
- 3.定义好将要使用的Bean工厂(各种BeanFactory)。
- 4.定义好XmlBeanDefinitionReader对象,并将工厂对象作为参数传递进去,从而构建好二者之间的关联关系。
- 5.通过XmlBeanDefinitionReader对象读取之前所抽取出的Resource对象。
- 6.流程开始进行解析。
- 7.针对XML文件进行各种元素以及元素属性的解析,这里面,真正的解析是通过BeanDefinitionParserDelegate对象来完成的(委托模式)
- 8.通过BeanDefinitionParserDelegate对象在解析XML文件时,又使用到了模版方法设计模式(pre,process,post)。
- 9.当所有的bean标签元素都解析完毕后,开始定义一个BeanDefinition对象,该对象是一个非常重要的对象,里面容纳了一个Bean相关的所有属性。
- 10.BeanDefinition对象创建完毕后,Spring又会创建一个BeanDefinitionHolder对象来持有这个BeanDefinition对象。
- 11.BeanDefinitionHolder对象主要包含俩部分内容:beanName与BeanDefinition。
- 12.工厂会将解析出来的Bean信息存放到内部的一个ConcurrentHashMap中,该Map的键是beanName(唯一),值是BeanDefinition对象。
- 13.调用Bean解析完毕的触发动作,从而触发相应的监听器的方法的执行(使用了观察者模式)。