本系列文章旨在让小白也可以轻松学习Spring源码
本节主要学习几个类。看Spring的源码之前,需要先了解其中几个比较重要的类,这几个类也是在看源码中经常看到的类,刚开始看不懂没关系,后面遇到这些类在回来看本节会有恍然大悟的感觉。
- DefaultListabelBeanFactory
- XmlBeanFactory
- AbstractAutowireCapableBeanFactory
- ConfigurableListabelBeanFactory
- AbstractBeanDefinition
- BeanDefinitionReader
- BeanDefinitionRegistry
- BeanDefinitionHolder
一、例子
创建一个Spring的项目有很多种方式,本系列主要讲解XML配置文件的方式来注册Bean和加载。
1. 项目结构
1.2 Person
package beans;
/**
* @author 环杰
* @date 2021/07/09
*/
public class Person {
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1.3
package org.example;
import beans.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
}
}
1.3 App
<?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="person" class="beans.Person">
<property name="age" value="12"/>
</bean>
</beans>
1.4 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="person" class="beans.Person">
<property name="age" value="12"/>
</bean>
</beans>
1.5 pom.xml
其实主要是org.springframework的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>studySpring</artifactId>
<version>1.0-SNAPSHOT</version>
<name>studySpring</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
二、类图
接着讲回主题,本节前面讲解的几个类的类图如下。
Spring如何知道他需要注册和加载哪些Bean?那一定是根据代码来找的,那他从哪行代码开始找起?就是从ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
这一行。
这一行,我们只传了 配置文件的文件名字,因此Spring一定是去解析这个配置文件,并将配置文件转换为类,根据配置文件中配置的类信息,来加载对应的类,那么现在的问题就变成了:
- Spring如何解析配置文件
- Spring如何根据解析后的配置文件来生成对应的bean
带着这2个问题,我们再来想。Spring中有很多Bean,这些bean要有一个池子来装,那么这个池子在Spring中我们就叫他bean工厂,想一想,鞋厂生产鞋,手套厂生产手套,bean工程生产bean,也是很合理的。
这个bean工厂在spring中有很多,但是根都是一个叫BeanFactory接口。为什么有很多个不同类型的bean工厂呢?因为创建bean的方式有很多,通过配置文件的叫XmlBeanFactory,不同类型的工厂只是增加了他一些特有的功能。比如鞋厂生产鞋,Nike鞋厂生产Nike鞋,adidas鞋厂生产adidas鞋,Nike鞋厂和adidas鞋厂的源头都是鞋厂。
-
DefaultListableBeanFactory
类在Spring中是非常非常重要的一个类。它是Spring注册及加载Bean的默认实现。 -
XmlBeanFactory
类是DefaultListableBeanFactory
类的子类,对其进行了扩展,主要用于从XML配置文件中解析配置,将配置转换为BeanDefiniton
。
下面是XmlBeanFactory
类。
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
-
BeanDefinitionRegistry
:定义对BeanDefinition的增删改操作 -
ConfigurableListabelBeanFactory:BeanFactory
配置清单,指定忽略类型及接口等
2.1 AbstractBeanDefinition
不论我们是以配置文件Xml的方式注册Bean还是以注解@Bean的方式注册bean,最后Bean的信息都会放到AbstractBeanDefiniton
中,我们在AbstractBeanDefinition
的字段中会找到我们对应的配置信息。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
@Nullable
private volatile Object beanClass;
// bean的作用范围,对应 bean属性的scope
@Nullable
private String scope = SCOPE_DEFAULT;
// 是否是抽象,对应bean属性的abstract
private boolean abstractFlag = false;
// 是否是延迟加载,bean属性的 lazy-init
@Nullable
private Boolean lazyInit;
// 自动注入模式,bean属性的 autowire
private int autowireMode = AUTOWIRE_NO;
// 依赖检查
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
// 用来表示一个Bean的实例化依靠另一个bean先实例化,bean属性的 depend-on
@Nullable
private String[] dependsOn;
// 对应bean属性 autowire-candidate
private boolean autowireCandidate = true;
private boolean primary = false;
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
@Nullable
private Supplier<?> instanceSupplier;
private boolean nonPublicAccessAllowed = true;
private boolean lenientConstructorResolution = true;
@Nullable
private String factoryBeanName;
@Nullable
private String factoryMethodName;
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
@Nullable
private MutablePropertyValues propertyValues;
private MethodOverrides methodOverrides = new MethodOverrides();
@Nullable
private String initMethodName;
@Nullable
private String destroyMethodName;
private boolean enforceInitMethod = true;
private boolean enforceDestroyMethod = true;
private boolean synthetic = false;
private int role = BeanDefinition.ROLE_APPLICATION;
@Nullable
private String description;
@Nullable
private Resource resource;
下面我们会根据前面写的例子一步一步讲解Spring的解析和加载Bean流程。