SpringBoot学习笔记

简介

SpringBoot 就是脚手架,就是把像 SSM 中非常繁杂的配置工作给融合并简化了。

1、SpringBoot 入门

1.1、SpringBoot 的功能

  • 创建独立的 Spring应用程序

  • 直接嵌入 Tomcat、 Jetty 或 Undertow (无需部署 WAR包,打包成 Jar 本身就是个可以运行的应用程序 )

  • 提供一站式的“starter”依赖项, 以简化 Maven配置 ( 需要整合计么框架,直接导对应框架的 starter依赖)

  • 尽可能地自动配置 Spring 和第三方库(除非特殊情况,否则几乎不需要你进行什么配置)

  • 提供生产就绪功能,如指标、运行状况检查和外部化配置

  • 没有代码生成,也没有 XML配置的要求

1.2、项目文件目录介绍

.mvn、mvnw、mvnw.cmd 这几个文件删了都可以,就是解决如果没有 maven 环境的话。HELP.md 也可以直接删掉。

主函数类、pom.xml、application.properties、.gitignore 这几个文件比较重要

.gitignore 是 git 版本控制的忽略清单

application.properties 是配置类,在里面可以修改许多 SpringBoot 默认的配置,还可以自定义一些属性,然后在代码的变量上 @Value("${aaa.bbb}") 就可以取到了。

1.3、SpringBoot 整合 Web 相关框架

主要就是加入 Spring Web 依赖。引入依赖就会内置 tomcat服务器。

然后就可以直接写 Controller,加上 @RestController 注解就可以使用了。

因为 SpringBoot 的默认包扫描机制:从启动类所在包开始,扫描当前包及其子级包下的所有文件,所以一般可以不用加 @ComponentScan(basePackages = {"xxx"}) 这个注解了。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

1.3.1、整合 Thymeleaf框架

thymeleaf 是前后端不分离的项目使用的,需要后端去解析。

先引入 thymeleaf依赖,然后静态的资源方到 resources/static/ 下面,页面资源放到 resources/templates/ 下面,然后配置前缀。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
spring:
  mvc:
    static-path-pattern: /static/**

1.4、SpringBoot 整合 MyBatis框架

需要引入两个依赖,MyBatis、数据库对应的 Connector 的依赖。

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
​
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

引入依赖后,若没有给主类取消数据源的配置,则必须去配置数据源

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
​
# mysql数据库连接
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/student?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: 123456

1.5、SpringBoot 的日志框架

日志级别:TRACE < DEBUG < INFO < WARN < ERROR < FATAL

1.5.1、日志门面和日志实现

我们首先要区分一下,什么是日志门面(Facade),什么是日志实现,我们之前学习的 JUL 实际上就是一种日志实现,我们可以直接使用 JUL 为我们提供的日志框架来规范化打印日志,

而日志门面,如 SIf4j, 是把不同的日志系统的实现进行了具体的抽象化,只提供了统

一的日志使用接口,使用时只需要按照其提供的接口方法进行调用即可,由于它只是一个接口,并不是一个具体的可以直接单独使用的日志框架,所以最终日志的格式、记录级别、输出方式等都要通过接口绑定的具体的日志系统来实现,这些具体的日志系统就有 log4j、 logback、java.util.logging 等, 它们才实现了具体的日志系统的功能。

日志门面就像 JDBC 一样,是中间层。

为了做到在众多日志框架下一律统一使用 Slf4j 进行日志打印,就保留不同日志框架的接口和类定义等关键信息,而将实现全部定向为 SIf4j 的调用。相当于有着和原有日志框架一样的外壳, 对于其他框架来说依然可以使用对应的类进行操作,而具体的实现已经是Slf4j 的了。

SpringBoot 使用 Slf4j 作为日志门面,然后内置了 Logback 作为日志实现,其依赖是 spring-boot-starter-logging。

1.5.2、使用日志

// 这种方法较为麻烦
Logger logger = LoggerFactory.getLogger(指定类.class);
logger.info("xxxx");
​
// 引入 lombok注解,在当前类上加上 @Slf4j注解
log.info("xxxx");

1.5.3、配置 Logback日志

可以定制化,写一个配置文件,SpringBoot 推荐的命名是 logback-spring.xml,放在 resources文件夹下。

一旦添加了这个文件,就会覆盖掉原有的文件。所以最好下载别人写好的模板,然后用 <include resource="相对路径" /> 导入使用。

然后 banner 和日志是分开的,如果想修改,就在 resources/ 下添加 banner.txt 即可,然后还可以写一些代码进行自定义。

对于不同的日志输出,可以添加不同的 appender,然后加入 root 里面,就可以直接使用了,比如控制台打印、文件打印

1.5.4、MDC机制

Logback 内置的日志字段还是比较少,如果我们需要打印有关业务的更多的内容,包括自定义的一些数据,需要借助 logback MDC 机制,MDC 为“Mapped Diagnostic Context" (映射诊断上下文),即将一些运行时的上下文数据通过 logback 打印出来;此时我们需要借助org.sl4j.MDC 类。

比如我们现在需要记录是哪个用户访问我们网站的日志,只要是此用户访问我们网站,都会在日志中携带该用户的 ID,我们希望每条日志中都携带这样一段信息文本,而官方提供的字段无法实现此功能,这时就需要使用 MDC机制,是用 ThreadLocal 实现的。

1.6、多环境配置

1.6.1、配置文件的多环境

# 在 application.yml 中指定使用的配置文件
# 这样就会去追加使用 application-dev.yml,如果指定为 prod,则是 application-prod.yml
spring:
  profiles:
    # 这样是直接指定,使用下面这种方式就需要在 pom.xml 中配置 maven 的
    # active: dev
    active: '@environment@'

1.6.2、日志系统的多环境

<!-- 修改 logback-spring.xml 文件的那一段,即在 root 上加一层 -->
<springProfile name="dev">
  <root level="INFO">
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="FILE" />
  </root>
</springProfile>
​
<springProfile name="prod">
  <root level="INFO">
    <appender-ref ref="FILE" />
  </root>
</springProfile>

1.6.3、Maven打包 的多环境

<!-- 加在 pom.xml 文件的 project标签里面 -->
<profiles>
  <profile>
    <id>dev</id>
    <avtivation>
      <activeByDefault>true</activeByDefault>
    </avtivation>
    <properties>
      <environment>dev</environment>
    </properties>
  </profile>
  
  <profile>
    <id>prod</id>
    <avtivation>
      <activeByDefault>false</activeByDefault>
    </avtivation>
    <properties>
      <environment>prod</environment>
    </properties>
  </profile>
</profiles>
​
​
​
<!-- 加在 pom.xml 文件的 build标签里面 -->
<resources>
  <!-- 排除配置文件 -->
  <resource>
    <directory>src/main/resources</directory>
    <!-- 先排除所有的配置文件 -->
    <excludes>
      <!-- 这里使用了通配符,也可以写多个 exclude标签进行排除 -->
      <exclude>application*.yml</exclude>
    </excludes>
  </resource>
  
  <!-- 根据激活条件引入打包所需的配置和文件 -->
  <resource>
    <directory>src/main/resources</directory>
    <!-- 引入所需环境的配置文件 -->
    <filtering>true</filtering>
    <includes>
      <include>application.yml</include>
      <!-- 根据 maven 选择的环境导入配置文件 -->
      <include>application-${environment}.yml</include>
    </includes>
  </resource>
</resources>

1.7、项目打包部署

切换到对应的环境,比如 prod,然后刷新一下 maven,然后 clean 掉之前的东西,然后点 package 进行打包。

部署就是将 jar 包放到指定的文件夹下,然后 cmd,然后 java -jar jar包的名称。这样就运行了

也可以创建一个 txt 文件,然后名称改为 start.bat,然后在里面写入 java -jar jar包的名称。

1.7.1、执行 maven 命令

  • mvn package -DskipTests:打包时通过测试

1.8、实现 Runner接口

如果我们需要在项目启动完成之后,紧接着执行一段代码,那我们就可以编写自定义的 ApplicationRunner、CommandLineRunner 来解决,它会在项目启动完成后执行。

当然,如果你写在主类的 main方法的 run方法之后,也是可以的,因为 SpringBoot 提供了异步执行机制,但是肯定不优雅。

1.8.1、Runner实现类

可以有多个自定义的 Runner,若需要给他们排序,就可以加上 @Order(数字)注解,数字越小优先级越高。

除了 @Order注解,还可以实现 Ordered接口,然后重写 getOrder方法,返回值就行了。

@Order(1)
@Component
public class TestRunner implements ApplicationRunner {
  @Override
  public void run(ApplicationArguments args) throws Exception {
    System.out.println("我是自定义执行!");
  }
}

2、扩展

2.1、异步任务

在配置类或启动类上添加 @EnableAsync 开启异步,然后在要进行异步的方法上添加 @Async注解,但类必须是一个 bean,可被扫描到。

2.2、定时任务

在配置类或启动类上添加注解 @EnableScheduling,开启定时任务

在方法上添加注解 @Scheduled(fixedRate = 10006030),里面也可以是 cron表达式

fixedRate 是无论上一次任务执行完与否,两次任务开始时间的间隔,

fixedDelay 是必须等上一次执行完之后,即上一个任务执行结束与下一个任务开始执行的间隔

2.3、监听器

监听器就是等待某个事件的触发,触发后执行相关操作

不仅有 ContextRefreshedEvent,还可以监听其他的事件。

@Component
public class TestListener implements ApplicationListener<ContextRefreshedEvent> {
  @override
  public void onApplicationEvent(ContextRefreshedEvent event) {
    // 做相关操作
  }
}
​
// 自定义事件
public class TestEvent extends ApplicationEvent {
  public TestEvent(Object source) {
    super(source);
  }
}
​
// 发布事件
public class TestController {
  @Resource
  ApplicationContext context;
  
  @GetMapping("publishTestEvent")
  public void publishTestEvent() {
    context.publishEvent(new TestEvent("哈哈哈"));
  }
}

2.4、Aware系列接口

Aware 的中文意想为感知。简单来说,他就是一个标识,实现此接口的类会获得某些感知能力,Spring容器会在 Bean 被加载时,根据类实现的感知接口,会调用类中实现的对应感知方法。

比如 AbstractAuthenticationProcessingilter 实现了 ApplicationEventPublisherAware接口,此接口的感知功能为事件发布器,在 Bean 加载时,会调用实现类中的 setApplicationEventPublisher方法,就可以得到时间发布者了,而 AbstractAuthenticationProcessingFilter类则利用此方法,在 Bean加载阶段获得了容器的事件发布器,以便之后发布事件使用。

@Service
public class TestService implements BeanNameAware {
  @override
  public void setBeanName(String s) {
    // BeanNameAware 会在当前 service 被注册成 bean 的时候感知到 bean 的名称,
    // 然后调用 setBeanName 就可以给到你名称 s,s 其实就是 testService
  }
}

2.5、邮件 Mail

2.5.1、开启邮箱的服务

发邮件之前需要打开邮箱的 POP3/SMTP服务,开启服务之后会给一个签名,有用的。

2.5.2、SpringBoot 整合

2.5.2.1、配置
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
​
spring:
  mail:
    host: 邮箱提供的 smtp服务器地址,比如 smtp.163.com
    username: 你的邮箱账号
    password: 开启服务给的签名
2.5.2.2、代码测试
public class Test {
  @Autowired
  JavaMailSender mailSender;
  
  void sendTest() {
    // SimpleMailMessage 是一个比较简单的邮件封装,不能加附件;MimeMessage 可以
    // MimeMessage mimeMessage = mailSender.createMimeMessage();
    // MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
    SimpleMailMessage mailMessage = new SimpleMailMessage();
    // 设置邮件标题
    mailMessage.setSubject("睡觉通知书");
    // 设置邮件内容
    mailMessage.setText("XXX你好,请您睡觉!");
    // 设置邮件发送者,需要与配置文件中的邮箱一致
    mailMessage.setFrom("发送方邮箱号");
    // 设置邮件接收方
    mailMessage.setTo("接收方邮箱号");
    mailSender.send(mailMessage);
  }
}

3、SpringBoot原理

3.1、SpringApplication类

3.1.1、项目启动类

总之,就是在初始阶段将主类注册成为一个 Bean。

  • 首先是在启动类里面,我们调用 SpringApplication 的 run方法来启动项目。所以去看 run

public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

3.1.2、SpringApplication类

  • 然后 run 的返回类型是一个可配置的应用上下文,然后看 return 的 run方法

  • 这个 run 先 new 了一个 SpringApplication类的实例,然后再调用类方法 run

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class[]{primarySource}, args);
}
​
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return (new SpringApplication(primarySources)).run(args);
}
3.1.2.1、构造方法
  • 构造方法其实就是在初始化赋值等一系列操作,很重要的就是 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class))

然后去调用类中的非静态 run方法

public SpringApplication(Class<?>... primarySources) {
    this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  ......
  this.resourceLoader = resourceLoader;
  Assert.notNull(primarySources, "PrimarySources must not be null");
  this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
  // 判断当前 SpringBoot应用程序是否为 Web项目,并返回当前的项目类型
  // 一般就是返回 NONE 或 SERVLET,还有一个 return 是 REACTIVE
  // 根据类路径下判断是否包含 spring-boot-web依赖,有就是 SERVLET类型,没有就是 NONE类型
  this.webApplicationType = WebApplicationType.deduceFromClasspath();
  this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
  // 创建所有 ApplicationContextInitializer 的实现类的实例对象
  this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
  this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
  this.mainApplicationClass = this.deduceMainApplicationClass();
}
3.1.2.2、getSpringFactoriesInstances方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return this.getSpringFactoriesInstances(type, new Class[0]);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  ClassLoader classLoader = this.getClassLoader();
  // 主要是会调用 SpringFactoriesLoader.loadFactoryNames 这个方法
  // 获取项目所有的依赖中 META-INF/spring.factories 中配置的对应接口类的实现类的全限定名列表
  // 如果传的 type 不是 null,那么就会去找对应接口类的实现类,否则就是找默认的
  Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  // 根据 全限定名Set 迭代创建实例对象集合 List
  List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  // 根据对应类上的 Order接口或是注解进行排序
  AnnotationAwareOrderComparator.sort(instances);
  return instances;
}
3.1.2.3、类方法 run

查看这个可以发现,SpringBoot 就是 Spring 的一层壳,是在 ApplicationContext 之上做了封装。

public ConfigurableApplicationContext run(String... args) {
  long startTime = System.nanoTime();
  DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
  ConfigurableApplicationContext context = null;
  this.configureHeadlessProperty();
  // 获取所有的 SpringApplicationRunListener,并通知启动事件,
  // 默认只有一个实现类 EventPublishingRunListener
  // EventPublishingRunListener 会将初始化各个阶段的事件转发给所有监听器
  SpringApplicationRunListeners listeners = this.getRunListeners(args);
  listeners.starting(bootstrapContext, this.mainApplicationClass);
  try {
    // 环境配置
    ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
    this.configureIgnoreBeanInfo(environment);
    // 打印 Banner
    Banner printedBanner = this.printBanner(environment);
    // 创建 ApplicationContext,会根据是否为 Web容器使用不同的 ApplicationContext实现类
    context = this.createApplicationContext();
    context.setApplicationStartup(this.applicationStartup);
    // 初始化 ApplicationContext
    this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
    // 初始化 ApplicationContext 的 refresh方法。bean 的注册、生成都在这里面
    this.refreshContext(context);
    this.afterRefresh(context, applicationArguments);
    Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
    if (this.logStartupInfo) {
      (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
    }
    listeners.started(context, timeTakenToStartup);
    // 在这里就是执行所有的自定义 Runner,只要实现了 ApplicationRunner 或 CommandLineRunner
    this.callRunners(context, applicationArguments);
  } catch (Throwable var12) {
    this.handleRunFailure(context, var12, listeners);
    throw new IllegalStateException(var12);
  }
  try {
    Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
    listeners.ready(context, timeTakenToReady);
    return context;
  } catch (Throwable var11) {
    this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
    throw new IllegalStateException(var11);
  }
}
3.1.2.4、createApplicationContext方法

这个类对象 applicationContextFactory 是 ApplicationContextFactory类型。

protected ConfigurableApplicationContext createApplicationContext() {
  return this.applicationContextFactory.create(this.webApplicationType);
}
3.1.2.5、prepareContext方法
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
  // 环境配置
  ......
  // 将 Banner 注册为一个 Bean
  ......
​
  // 获取一开始传入的项目主类
  Set<Object> sources = this.getAllSources();
  Assert.notEmpty(sources, "Sources must not be empty");
  // 将主类直接注册成 Bean,这样就可以通过注解加载了
  this.load(context, sources.toArray(new Object[0]));
  listeners.contextLoaded(context);
}
protected void load(ApplicationContext context, Object[] sources) {
  ......
  // 这个 loader 是 BeanDefinitionLoader类的对象,套了很多层
  loader.load();
}

3.1.3、WebApplicationType类

3.1.3.1、deduceFromClasspath方法

deduce方法就是推断项目类型,如果项目导入的依赖里有指定的依赖,就判断为对应的项目类型。

static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
        return REACTIVE;
    } else {
        String[] var0 = SERVLET_INDICATOR_CLASSES;
        int var1 = var0.length;
​
        for(int var2 = 0; var2 < var1; ++var2) {
            String className = var0[var2];
            if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                return NONE;
            }
        }
​
        return SERVLET;
    }
}

3.1.4、SpringFactoriesLoader类

3.1.4.1、loadFactoryNames方法
  • this.setInitializers 的时候,传的 type 是 ApplicationContextInitializer.class spring.factories 是 Spring 仿造 Java SPI 实现的一种类加载机制,在 spring.factories 中配置接口的实现类名称,然后在程序中读取这些配置文件并实例化。

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
  ClassLoader classLoaderToUse = classLoader;
  if (classLoader == null) {
      classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
  }
  // 得到全限定名
  String factoryTypeName = factoryType.getName();
  // 又调用了 loadSpringFactories 和 getOrDefault 这两个方法
  // loadSpringFactories 会得到所有的实现类
  // getOrDefault 即如果传的 type 不是 null,那么就会去找对应接口类的实现类,否则就是找默认的
  return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
3.1.4.2、loadSpringFactories方法
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
  Map<String, List<String>> result = (Map)cache.get(classLoader);
  if (result != null) {
    return result;
  } else {
    HashMap result = new HashMap();
    try {
      // 通过 classLoader 获取指定路径 META-INF/spring.factories 下的资源
      // 自动装配的核心内容
      Enumeration urls = classLoader.getResources("META-INF/spring.factories");
      while(urls.hasMoreElements()) {
          URL url = (URL)urls.nextElement();
          UrlResource resource = new UrlResource(url);
          Properties properties = PropertiesLoaderUtils.loadProperties(resource);
          Iterator var6 = properties.entrySet().iterator();
          while(var6.hasNext()) {
              Entry<?, ?> entry = (Entry)var6.next();
              String factoryTypeName = ((String)entry.getKey()).trim();
              String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
              String[] var10 = factoryImplementationNames;
              int var11 = factoryImplementationNames.length;
              for(int var12 = 0; var12 < var11; ++var12) {
                  String factoryImplementationName = var10[var12];
                  ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                      return new ArrayList();
                  })).add(factoryImplementationName.trim());
              }
          }
      }
      result.replaceAll((factoryType, implementations) -> {
          return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
      });
      cache.put(classLoader, result);
      return result;
    } catch (IOException var14) {
      throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
    }
  }
}

3.1.5、ApplicationContextFactory类

在构造方法中已经用 Lambda表达式通过匿名内部类创建了一个 DEFAULT

public interface ApplicationContextFactory {
  ApplicationContextFactory DEFAULT = (webApplicationType) -> {
    try {
      switch(webApplicationType) {
      case SERVLET:
        return new AnnotationConfigServletWebServerApplicationContext();
      case REACTIVE:
        return new AnnotationConfigReactiveWebServerApplicationContext();
      default:
        // 这个就是 Spring 中使用的类,
        return new AnnotationConfigApplicationContext();
      }
    } catch (Exception var2) {
      throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
    }
  };
  
  ConfigurableApplicationContext create(WebApplicationType webApplicationType);
  
  static ApplicationContextFactory ofContextClass(Class<? extends ConfigurableApplicationContext> contextClass) {
    return of(() -> {
      return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    });
  }
  
  static ApplicationContextFactory of(Supplier<ConfigurableApplicationContext> supplier) {
    return (webApplicationType) -> {
      return (ConfigurableApplicationContext)supplier.get();
    };
  }
}

3.1.6、AnnotationConfigApplicationContext类

创建了一个 reader 和一个 scanner,

public AnnotationConfigApplicationContext() {
  StartupStep createAnnotatedBeanDefReader = 
      this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
  // 一个 AnnotatedBeanDefinitionReader类型的 reader
  this.reader = new AnnotatedBeanDefinitionReader(this);
  createAnnotatedBeanDefReader.end();
  // 一个 ClassPathBeanDefinitionScanner类型的 scanner
  this.scanner = new ClassPathBeanDefinitionScanner(this);
}

3.1.7、AnnotatedBeanDefinitionReader类

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
  ......
  // 注册一些后置处理器
  AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

3.1.8、AnnotationConfigUtils类

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    registerAnnotationConfigProcessors(registry, (Object)null);
}
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {
  DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
  if (beanFactory != null) {
    if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
      beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
    }
    if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
      beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
    }
  }
  Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet(8);
  RootBeanDefinition def;
  if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {
    // 注册了 ConfigurationClassPostProcessor 用于处理 @Configuration、@Import 等注解
    // 它继承自 BeanDefinitionRegistryPostProcessor,
    // 所以它的执行时间在 Bean 定义加载完成之后,Bean 初始化之前
    def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));
  }
  
  if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor")) {
    // AutowiredAnnotationBeanPostProcessor 用于处理 @Value 等注解自动注入
    def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));
  }
  ......
.  
  return beanDefs;
}

3.2、@SpringBootApplication 的自动配置原理

启动类已经在初始阶段注册为 Bean,那么在加载时,就会根据注解进行更多额外的操作。

导的依赖全是以 jar包的形式打包的,只有自己写的代码,在打包的时候才会是 class文件。

3.2.1、@SpringBootApplication

  • @ComponentScan 会默认将主类所在包作为 basePackage,然后进行自动扫描

  • @SpringBootConfiguration 就是声明是一个配置类,再进去有 @Configuration注解

  • @EnableAutoConfiguration 非常重要,

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    // 许多 @AliasFor
}

3.2.2、@EnableAutoConfiguration

  • 主要就是 @Import 这个注解,老套路了,通过这种方式将一些外部的 Bean 加载到容器中,这里加载了 AutoConfigurationImportSelector @Import、@Configuration 能生效是因为 ConfigurationClassPostProcessor。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
}

3.2.3、AutoConfigurationImportSelector类

可以看到 AutoConfigurationImportSelector 实现了大量的接口,包括很多 Aware类型的接口,主要就是来感知某些必要的对象,并将其存到当前类中。

其中最核心的是 DeferredImportSelector接口,它是 ImportSelector的子类,它定义了 selectImports方法,用于返回需要加载的类名称,在 Spring 加载 ImportSelector类型的 Bean 的时候,就会调用此方法获取更多需要加载的类,然后将这些类注册为 Bean。

现在知道了项目中的 @Configuration配置类的大致配置流程,即知道了 SpringBoot框架如何注册项目中的 Bean;再看看 AutoConfigurationImportSelector 是如何实现自动配置的,即如何把外部依赖的配置类注册成为 Bean。

静态内部类AutoConfigurationGroup 有一个 process方法,它是父接口 DeferredImportSelector 的实现。会调用 process方法获取所有的自动配置类。

process 这个方法就是最终的处理,可以得到 EnableAutoConfiguration 的实现类,然后进行自动配置。

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
  // ...
  
  // 有一个静态内部类 AutoConfigurationGroup
  private static class AutoConfigurationGroup implements Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
  
  }
}
3.2.3.1、静态内部类的 process方法
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
  Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {
      return String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName());
  });
  // 调用 getAutoConfigurationEntry 这个方法,
  // 获取所有的 配置类Entry,其实就是读取 spring.factories 来查看有哪些自动配置类
  AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
  this.autoConfigurationEntries.add(autoConfigurationEntry);
  Iterator var4 = autoConfigurationEntry.getConfigurations().iterator();
​
  while(var4.hasNext()) {
      String importClassName = (String)var4.next();
      this.entries.putIfAbsent(importClassName, annotationMetadata);
  }
}
3.2.3.2、getAutoConfigurationEntry方法
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
  if (!this.isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
  } else {
    AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
    // getCandidateConfigurations方法得到 候选配置类集合
    // 就是得到了所有依赖给的 自动配置类,
    List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
    // 进行去重操作
    configurations = this.removeDuplicates(configurations);
    // 得到手动排除掉的自动配置类,然后去排除掉。一般没有
    Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
    this.checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    // 排除操作完成之后,根据注解进行过滤。会根据条件注解进行过滤,
    // 即一般依赖的配置类中会有 @ConditionalOnClass 等等@ConditionalOn开头的注解,
    // 当引入对应依赖后,依赖给的配置才生效,SpringBoot 就不会把相关的配置类过滤掉
    configurations = this.getConfigurationClassFilter().filter(configurations);
    this.fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
  }
}
3.2.3.3、getCandidateConfigurations方法
  • 就是根据 EnableAutoConfiguration 这个类型,去调用 loadFactoryNames方法,

  • 然后 loadFactoryNames 这个方法我们之前看过,就会去调用 loadSpringFactories方法

  • 然后 loadSpringFactories方法就是去 META-INF/spring.factories 中来查看有哪些 EnableAutoConfiguration 的实现类,即自动配置类

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
  Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
  return configurations;
}

3.2.4、ImportSelector类

selectImports方法用于返回需要加载的类名称,在 Spring 加载 ImportSelector类型的 Bean 的时候,就会调用此方法获取更多需要加载的类,然后将这些类注册为 Bean。

目前已知使用 @Import 有特殊机制的接口:Importselector、ImportBeanDefinitionRegistrar,以及 @Confoiguration,都是由 ConfigurationClassPostProcessor 来处理 @Import 的。

public interface ImportSelector {
  String[] selectImports(AnnotationMetadata importingClassMetadata);
​
  @Nullable
  default Predicate<String> getExclusionFilter() {
      return null;
  }
}

3.2.5、ConfigurationClassPostProcessor类

这个类是 Spring 的一个类,不是 SpringBoot 的。

它实现了 BeanDefinitionRegistryPostProcessor 这个接口,这个接口有 postProcessBeanDefinitionRegistry 这个方法,就是在 Bean 注册完成之后进行一个后置处理

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {
  // ...
}
3.2.5.1、postProcessBeanDefinitionRegistry方法

主要是去调用了 processConfigBeanDefinitions方法。

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  int registryId = System.identityHashCode(registry);
  if (this.registriesPostProcessed.contains(registryId)) {
    throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
  } else if (this.factoriesPostProcessed.contains(registryId)) {
    throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
  } else {
    this.registriesPostProcessed.add(registryId);
    this.processConfigBeanDefinitions(registry);
  }
}
3.2.5.2、processConfigBeanDefinitions方法
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
  List<BeanDefinitionHolder> configCandidates = new ArrayList();
  // 注意:这个阶段仅仅是将所有的 Bean 完成扫描,得到了所有的 BeanDefinition,
  // 但还没进行任何区分。即此时只有 Bean定义,但 Bean 还没有被初始化。
  // 是后置处理器,在 BeanDefinition 全部加载完成后,Bean 初始化加载前,进行工作。
  // Candidate 即候选者,一会会将标记了 @Configuration 的类,
  // 作为 ConfigurationClass 加入到 configCandidates 中
  // 获取所有 Bean定义的名称
  String[] candidateNames = registry.getBeanDefinitionNames();
  String[] var4 = candidateNames;
  int var5 = candidateNames.length;
  
  // 遍历 Bean定义的名称的数组
  for(int var6 = 0; var6 < var5; ++var6) {
    String beanName = var4[var6];
    BeanDefinition beanDef = registry.getBeanDefinition(beanName);
    if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
      if (this.logger.isDebugEnabled()) {
        this.logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
      }
    } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
      // 这里判断此 Bean定义上是否添加了 @Configuration注解,即是否是一个配置类
      // 如果添加了 @Configuration注解,是一个配置类,那么就加入候选者列表去。
      configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
    }
  }
​
  if (!configCandidates.isEmpty()) {
    // ......
    
    // 创建了一个 ConfigurationClassParser解析器,用于解析配置类 @Import 这些注解
    ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    // 所有配置类的 BeanDefinitionHolder集合,存放所有的待解析配置类
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);
    // 这个 Set集合用于存放已经解析完成的类
    HashSet alreadyParsed = new HashSet(configCandidates.size());
​
    do {
      StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
      // 调用 parse 这个核心方法,进行解析
      parser.parse(candidates);
      parser.validate();
      // 得到 configurationClasses 的 ketSet(),即解析好的配置类信息
      // parser.getConfigurationClasses() 就是 parser类对象的 getter方法
      Set<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());
      configClasses.removeAll(alreadyParsed);
      if (this.reader == null) {
        this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());
      }
      // 已经解析出所有的配置类了,就通过 BeanDefinition 去注册 Bean
      this.reader.loadBeanDefinitions(configClasses);
      alreadyParsed.addAll(configClasses);
      
          // ......
      // 这里就是将 candidates 这个 Set集合全部进行解析
      // 循环中可能会因为 @Import 新增更多的待解析配置类,全放进 candidates 里面
    } while(!candidates.isEmpty());
    
    // ......
  }
}

3.2.6、ConfigurationClassParser类

3.2.6.1、parse方法
public void parse(Set<BeanDefinitionHolder> configCandidates) {
  Iterator var2 = configCandidates.iterator();
  while(var2.hasNext()) {
    BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
    BeanDefinition bd = holder.getBeanDefinition();
    try {
      if (bd instanceof AnnotatedBeanDefinition) {
        // 主要是调用这个 parse方法
        this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
      } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
        this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
      } else {
        this.parse(bd.getBeanClassName(), holder.getBeanName());
      }
    } catch (BeanDefinitionStoreException var6) {
      throw var6;
    } catch (Throwable var7) {
      throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
    }
  }
  // 最后延迟处理的配置类,调用内部类DeferredImportSelectorHandler 的 process方法
  // 最后调用的是 AutoConfigurationImportSelector 的静态内部类AutoConfigurationGroup 的实现方法 process
  this.deferredImportSelectorHandler.process();
}
​
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    this.processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
3.2.6.2、processConfigurationClass方法

这个方法就是在处理配置类,

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
  // @Configuration 相关注解处理
  if (!this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
    ConfigurationClass existingClass = (ConfigurationClass)this.configurationClasses.get(configClass);
    if (existingClass != null) {
      if (configClass.isImported()) {
        if (existingClass.isImported()) {
          existingClass.mergeImportedBy(configClass);
        }
        return;
      }
      this.configurationClasses.remove(configClass);
      this.knownSuperclasses.values().removeIf(configClass::equals);
    }
​
    ConfigurationClassParser.SourceClass sourceClass = this.asSourceClass(configClass, filter);
​
    do {
      // doProcessConfigurationClass 是核心方法,
      sourceClass = this.doProcessConfigurationClass(configClass, sourceClass, filter);
    } while(sourceClass != null);
    // 把解析完成的类信息放到 configurationClasses 里面
    this.configurationClasses.put(configClass, configClass);
  }
}
3.2.6.3、doProcessConfigurationClass方法
@Nullable
protected final ConfigurationClassParser.SourceClass doProcessConfigurationClass(ConfigurationClass configClass, ConfigurationClassParser.SourceClass sourceClass, Predicate<String> filter) throws IOException {
  // ......
​
  // 处理 Import注解
  this.processImports(configClass, sourceClass, this.getImports(sourceClass), filter, true);
  // ......
  return null;
}
3.2.6.4、processImports方法
private void processImports(ConfigurationClass configClass, ConfigurationClassParser.SourceClass currentSourceClass, Collection<ConfigurationClassParser.SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) {
  if (!importCandidates.isEmpty()) {
    if (checkForCircularImports && this.isChainedImportOnStack(configClass)) {
      this.problemReporter.error(new ConfigurationClassParser.CircularImportProblem(configClass, this.importStack));
    } else {
      this.importStack.push(configClass);
​
      try {
        Iterator var6 = importCandidates.iterator();
​
        while(var6.hasNext()) {
          ConfigurationClassParser.SourceClass candidate = (ConfigurationClassParser.SourceClass)var6.next();
          Class candidateClass;
          // 如果是 ImportSelector类型,就进入 if 做一系列工作
          if (candidate.isAssignable(ImportSelector.class)) {
            candidateClass = candidate.loadClass();
            ImportSelector selector = (ImportSelector)ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry);
            Predicate<String> selectorFilter = selector.getExclusionFilter();
            if (selectorFilter != null) {
              exclusionFilter = exclusionFilter.or(selectorFilter);
            }
            // 再判断是不是 DeferredImportSelector 的实现类,是就做 handler方法
            // 不是的话就正常按照 ImportSelector类型进行加载
            // Deferred 就是延迟的意思,即不会像 else 里面一样,立即做一个递归处理
            // 而是交给内部类deferredImportSelectorHandler 去处理
            // 最后会在 parse方法的最后一行调用内部类的 process方法去处理
            // 内部类的 process方法其实最后调用的是 AutoConfigurationImportSelector 的静态内部类AutoConfigurationGroup 的实现方法
            if (selector instanceof DeferredImportSelector) {
              this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector)selector);
            } else {
              // 不是 DeferredImportSelector 的实现类,就立即进行递归处理
              // 调用 selectImports方法获取所有需要加载的类
              String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
              Collection<ConfigurationClassParser.SourceClass> importSourceClasses = this.asSourceClasses(importClassNames, exclusionFilter);
              // 递归处理,直到全部处理完
              this.processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
            }
          } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
            // 如果不是 ImportSelector类型,再判断是不是 ImportBeanDefinitionRegistrar 类型
            candidateClass = candidate.loadClass();
            ImportBeanDefinitionRegistrar registrar = (ImportBeanDefinitionRegistrar)ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry);
            // 往 configClass 放入 ImportBeanDefinitionRegistrar信息,之后再处理
            // 处理这个 configClass 的时机是 loadBeanDefinitions的实现方法的最后一行
            configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
          } else {
            // 如果两个类型都不是,即是一个普通的配置类
            this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
            this.processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
          }
        }
      } catch (BeanDefinitionStoreException var17) {
        throw var17;
      } catch (Throwable var18) {
        throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", var18);
      } finally {
        this.importStack.pop();
      }
    }
  }
}
3.2.6.5、DeferredImportSelectorHandler内部类

这个内部类的 process方法其实最后调用的是 AutoConfigurationImportSelector 的静态内部类AutoConfigurationGroup 的实现方法 process。

private class DeferredImportSelectorHandler {
  @Nullable
  private List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImportSelectors;
  private DeferredImportSelectorHandler() {
    this.deferredImportSelectors = new ArrayList();
  }
  
  public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
    ConfigurationClassParser.DeferredImportSelectorHolder holder = new ConfigurationClassParser.DeferredImportSelectorHolder(configClass, importSelector);
    if (this.deferredImportSelectors == null) {
      ConfigurationClassParser.DeferredImportSelectorGroupingHandler handler = ConfigurationClassParser.this.new DeferredImportSelectorGroupingHandler();
      handler.register(holder);
      handler.processGroupImports();
    } else {
      this.deferredImportSelectors.add(holder);
    }
  }
  
  public void process() {
    List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    this.deferredImportSelectors = null;
    try {
      if (deferredImports != null) {
        ConfigurationClassParser.DeferredImportSelectorGroupingHandler handler = ConfigurationClassParser.this.new DeferredImportSelectorGroupingHandler();
        deferredImports.sort(ConfigurationClassParser.DEFERRED_IMPORT_COMPARATOR);
        deferredImports.forEach(handler::register);
        handler.processGroupImports();
      }
    } finally {
      this.deferredImportSelectors = new ArrayList();
    }
  }
}

3.2.7、DeferredImportSelector接口

这个 process方法是 AutoConfigurationImportSelector类的静态内部类的 process方法的抽象方法。

public interface DeferredImportSelector extends ImportSelector {
  @Nullable
  default Class<? extends DeferredImportSelector.Group> getImportGroup() {
    return null;
  }
​
  public interface Group {
    void process(AnnotationMetadata metadata, DeferredImportSelector selector);
​
    Iterable<DeferredImportSelector.Group.Entry> selectImports();
​
    public static class Entry {
      // ......
    }
  }
}

3.2.8、ConfigurationClassBeanDefinitionReader类

3.2.8.1、loadBeanDefinitions方法

进行迭代注册

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
  ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator trackedConditionEvaluator = new ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator();
  Iterator var3 = configurationModel.iterator();
​
  while(var3.hasNext()) {
    ConfigurationClass configClass = (ConfigurationClass)var3.next();
    this.loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
  }
}
3.2.8.2、loadBeanDefinitionsForConfigurationClass方法
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator trackedConditionEvaluator) {
  if (trackedConditionEvaluator.shouldSkip(configClass)) {
    String beanName = configClass.getBeanName();
    if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
      this.registry.removeBeanDefinition(beanName);
    }
    this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
  } else {
    if (configClass.isImported()) {
      // 把配置类自己给注册了,即先注册自己
      this.registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
    Iterator var3 = configClass.getBeanMethods().iterator();
    while(var3.hasNext()) {
      BeanMethod beanMethod = (BeanMethod)var3.next();
      // 还要注册配置类中有 @Bean注解标识的方法
      this.loadBeanDefinitionsForBeanMethod(beanMethod);
    }
    // 注册 @ImportResources 引入的 XML配置文件中读取的 Bean定义
    this.loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    // 注册 configClass 中经过解析后保存的所有 ImportBeanDefinitionRegistrar,
    // 注册对应的 BeanDefinition。即之前在 processImports方法中,
    // 配置类是 ImportBeanDefinitionRegistrar类型的情况下放入的
    this.loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
  }
}

  • 25
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值