概述

在正式分析 Spring 源码之前,我们有必要先来回顾一下 Spring 中最简单的用法。尽管我相信您已经对下面例子非常熟悉了。Bean 是 Spring 中最核心的概念,因为 Spring 就像是个大水桶,而 Bean 就像是水桶中的水,水桶脱离了水也就没什么用处了。

搭建基础框架

XML方案搭建Spring容器

引入jar包

  1. <properties>
  2. <java.version>1.8</java.version>
  3. <spring.version>5.1.5.RELEASE</spring.version>
  4. </properties>
  5. <dependencies>
  6. <dependency>
  7. <groupId>org.springframework</groupId>
  8. <artifactId>spring-context</artifactId>
  9. <version>${spring.version}</version>
  10. </dependency>
  11. </dependencies>

引入 spring-context jar,它会自动帮我引入aop、beans、core、expression、jcl 如下图:
图片.png

User 实体类

  1. /**
  2. * User实体类
  3. * @date: 2021/2/24 17:47
  4. */
  5. public class User {
  6. private String userName;
  7. private Integer age;
  8. public void setUserName(String userName) {
  9. this.userName = userName;
  10. }
  11. public void setAge(Integer age) {
  12. this.age = age;
  13. }
  14. @Override
  15. public String toString() {
  16. return "User{" +
  17. "userName='" + userName + '\'' +
  18. ", age=" + age +
  19. '}';
  20. }
  21. }

spring-config.xml 配置文件

在项目resources目录下创建 spring-config.xml,把User实体类注入到Spring容器中

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="user" class="com.zlp.spring.v1.entity.User">
  7. <property name="age" value="10" />
  8. <property name="userName" value="smile" />
  9. </bean>
  10. </beans>

XmlUserTest 测试类

  1. /**
  2. * XML容器测试类
  3. * @author Zou.LiPing
  4. * @date: 2021/2/24 17:13
  5. */
  6. public class XmlUserTest {
  7. public static void main(String[] args) {
  8. ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");
  9. User user = ac.getBean("user", User.class);
  10. System.out.println(user.toString());
  11. }
  12. }

控制打印输出

  1. User{userName='smile', age=10}

Annotation方案搭建 Spring容器

UserEntity 实体类

  1. @Component
  2. public class UserEntity {
  3. private String userName = "change";
  4. private Integer age = 28;
  5. @Override
  6. public String toString() {
  7. return "User{" +
  8. "userName='" + userName + '\'' +
  9. ", age=" + age +
  10. '}';
  11. }
  12. }

SpringConfig 配置类

  1. @Configuration
  2. @ComponentScan("com.zlp.spring.v2")
  3. public class SpringConfig {
  4. }

AnnotationUserTest 测试类

  1. /**
  2. * 注解测试类
  3. * @author Zou.LiPing
  4. * @date: 2021/2/24 17:13
  5. */
  6. public class AnnotationUserTest {
  7. private static AnnotationConfigApplicationContext applicationContext;
  8. public static void main(String[] args) {
  9. applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
  10. UserEntity user = applicationContext.getBean("userEntity", UserEntity.class);
  11. System.out.println(user.toString());
  12. // 打印注入Spring有哪些对象
  13. String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
  14. for (String beanDefinitionName : beanDefinitionNames) {
  15. System.out.println(beanDefinitionName);
  16. }
  17. }
  18. }

控制打印输出

  1. User{userName='change', age=28}

Spring 启动流程详解

执行流程图

Spring 容器启动方式(四) - 图2执行流程详解

  1. 加载 Bean 定义信息(xml 配置、注解、配置类);
  2. 解析 Bean 信息(BeanDefinitionReader 读取器 Bean 信息);
  3. 读取 Bean 定义信息,用 ConcurrentHashMap 存储(BeanDefinition 存放Bean 实例、作用域等);
  4. BeanFactoryPostProcessor 扩展接口(BeanDefinition 属性增强器,如 @Value(“${xxxx}”)替换);
  5. 通过反射来创建 Bean 对象信);
  6. 初始化对象(在堆中开辟新的空间→属性都是默认值);
  7. 如果该方法依赖其它的接口(@Autowired),通过 DI 注入(填充属性);
  8. *aware接口实现(设置aware接口属性);
  9. 如果实现了 BeanPostProcessor 接口(增强器,可以对方法前置和后置进行扩展);
  10. 前置增强器(postProcessBeforeInitialization 方法);
  11. Bean 初始化[init-method];
  12. 后置增强器(postProcessAfterInitialization 方法);
  13. Bean基本使用;
  14. 销毁(DisposableBean);