本系列文章旨在让小白也可以轻松学习Spring源码
本节主要学习几个类。看Spring的源码之前,需要先了解其中几个比较重要的类,这几个类也是在看源码中经常看到的类,刚开始看不懂没关系,后面遇到这些类在回来看本节会有恍然大悟的感觉。
创建一个Spring的项目有很多种方式,本系列主要讲解XML配置文件的方式来注册Bean和加载。
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 + '}'; } }
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); } }
<?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>
<?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>
其实主要是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一定是去解析这个配置文件,并将配置文件转换为类,根据配置文件中配置的类信息,来加载对应的类,那么现在的问题就变成了:
带着这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
配置清单,指定忽略类型及接口等不论我们是以配置文件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流程。