Springboot 笔记 2020年12月15日笔记

Spring boot 项目的搭建
第一步在这里插入图片描述
第二步 (选下一步)
在这里插入图片描述
第三步
在这里插入图片描述
第四步
在这里插入图片描述
ok了
在这里插入图片描述


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.1)

2020-12-15 15:32:37.984  INFO 17024 --- [           main] com.jj.demo.DemoApplication              : Starting DemoApplication using Java 1.8.0_231 on 小可爱的电脑 with PID 17024 (E:\springboot01\target\classes started by 可爱的小仙女 in E:\springboot01)
2020-12-15 15:32:37.992  INFO 17024 --- [           main] com.jj.demo.DemoApplication              : No active profile set, falling back to default profiles: default
2020-12-15 15:32:39.612  INFO 17024 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-12-15 15:32:39.629  INFO 17024 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-12-15 15:32:39.629  INFO 17024 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2020-12-15 15:32:39.781  INFO 17024 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-12-15 15:32:39.781  INFO 17024 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1652 ms
2020-12-15 15:32:40.047  INFO 17024 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-12-15 15:32:40.281  INFO 17024 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-12-15 15:32:40.298  INFO 17024 --- [           main] com.jj.demo.DemoApplication              : Started DemoApplication in 3.063 seconds (JVM running for 5.706)

写一个简单的小demo

package com.jj.demo.Controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    
    
    @RequestMapping("/")
    @ResponseBody
    public String demo(){
    
    

        return "hello fjj!!";
    }
}

在这里插入图片描述Springboot 优点
为所有Spring 开发者更块的入门
开箱即用,提供各种默认的配置来简化项目配置
内嵌式容器简化web 项目
没有冗余代码生成和xml 配置的要求
Springboot 自动配置的原理
1,pom.xml
所有的都在父容器中

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

点进去之后可以看到 里面有好多的版本号,所以我们在导入依赖的时候就不用写版本号了。

 <activemq.version>5.16.0</activemq.version>
    <antlr2.version>2.7.7</antlr2.version>
    <appengine-sdk.version>1.9.83</appengine-sdk.version>
    <artemis.version>2.15.0</artemis.version>
    <aspectj.version>1.9.6</aspectj.version>
    <assertj.version>3.18.1</assertj.version>
    <atomikos.version>4.0.6</atomikos.version>
    <awaitility.version>4.0.3</awaitility.version>
    <bitronix.version>2.1.4</bitronix.version>
    <build-helper-maven-plugin.version>3.2.0</build-helper-maven-plugin.version>
    <byte-buddy.version>1.10.18</byte-buddy.version>
    <caffeine.version>2.8.8</caffeine.version>
    <cassandra-driver.version>4.9.0</cassandra-driver.version>

放了部分的xml 版本
2,启动器

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

有好多的启动器,我们需要那个就在starter 后加上就可以,比如需要 web 的就写

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

sring boot 会自动把他们变成一个一个的启动器
3,主程序
@SpringBootApplication 注解 (点进去发现有以下混合注解)在这里插入图片描述

@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}
)}
)

这里着重的说下面的两个注解
在这里插入图片描述
第一个注解!!!重点的注解
@SpringBootConfiguration //spring boot 配置的注解 (点进去,又是混合注解)


@Target({
    
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration  //spring 的配置类  (点进去发现还是个混合注解)

点进去@Configuration后看到以下的

@Target({
    
    ElementType.TYPE})
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	@Component  // spring 的组件扫描。 spring boot 本质其实还是一 spring

第二个注解!!!重点的注解
@EnableAutoConfiguration //自动导入配置,(点进去看以下内容)

@Target({
    
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage  (自动配置包)(点进去)
@Import({
    
    AutoConfigurationImportSelector.class})  //自动配置到入选择的(点入进去里面有一些扫描组件,应该是用来扫描那些我们呢maven 里的东西的,我是这样想的)

@AutoConfigurationPackage (自动配置包)(点进去)

@Target({
    
    ElementType.TYPE})
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	@Inherited
	@Import({
    
    Registrar.class})  //自动配置包 注册 (点进去 ,看到有一些注册的 ,数据源)

@Import({AutoConfigurationImportSelector.class}) (点入后)

里有一个重要的类 //获取候选的配置
   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;
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
小结论
springboot 所有的配置都在自动配置类里卖弄,导入对应的start 就有对应的启动器了,自动配置就成功了。最后就生效了。

流程主要分为三个部分
1,SpringApplication 的初始化模块,配置基本的环境变量,资源,构造器,监听器.
2,应用具体的启动方案,包括启动的监听模块,加载配置核心,及核心的创建上下文环境模块
3,自动化模块,是Springboot 自动配置核心。

run启动
main 方法 调用SpringApplication.run()启动整个spring-boot程序,需要使用
@SpringBootApplication 以及 @ImportResource
@EnableAutoConfiguration:Springboot 根据应用所声明的依赖对spring 框架自动进行配置

package com.jj.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class DemoApplication {
    
    

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

}

这个类主要做了一下四件事情
1,推断应用的类型时普通的项目还是WEB项目
2,查找并加载所有可用初始化器,设置到initializers 属性中
3,找出所有的应用程序监听器,设置到listeners 属性中
4,推断并设置main 方法 的定义类,找到运行的主类

进入run 方法

    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    
    
        return (new SpringApplication(primarySources)).run(args);
    }

run 创建了SpringApplication 实例,经去后发现


    public SpringApplication(Class<?>... primarySources) {
    
    
        this((ResourceLoader)null, primarySources);
    }

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    
    
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = Collections.emptySet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

关键步骤
1 创建应用监听器SpringApplicationRunListeners 并开始监听
2 加载SpringBoot 配置环境(ConfigurableEnvironment),如果是web 容器发布,会加载
StandardEnvironment,其最终也是继承了ConfigurableEnvironment,类图如下
在这里插入图片描述
最终都实现lPropertyResolver接口我们平时通过environment 对象获取配置文件的key
得到对应的value 时就调用了propertyResolver接口的getProperty方法

3配置环境加入到监听器中
4 创建run 方法的返回对象:ConfigurableApplicaton(应用配置上下文)

    protected ConfigurableApplicationContext createApplicationContext() {
    
    
        return this.applicationContextFactory.create(this.webApplicationType);
    }

方法会先获取显示设置的应用上下文(ApplicationCotextClass) ,如果不存在,在加载默认环境配置
默认选择的时AnnotationConfigApplicationContext注解上下文(通过扫描所有注解类来加载bean),最后通过BeanUtils实例化上下文对象,并返回
ConfigurableApplicationContext类图如下:
在这里插入图片描述
ApplicationContext:应用上下文类,主要继承了beanFactory(bean 的工厂类)
5,回到run 方法内,prepareContext方法将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联
6.接下来的refreshContext(context)方法(初始化方法如下)将是实现spring-boot-starter-*(mybatis、redis等)自动化配置的关键,包括spring.factories的加载,bean的实例化等核心工作。

  public ConfigurableApplicationContext run(String... args) {
    
    
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        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 printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
    
    
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
    
    
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }

        try {
    
    
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
    
    
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

refresh 方法
配置结束后,就只剩下收尾了,返回应用环境的上下文,主要创建了配置环境,事件监听,应用上下文,并基于以上条件,在容器中开始实例化我们需要的bean .

总结
1、新建module,在主程序类加入断点,启动springboot

2、首先进入SpringAplication类run方法

3、run方法新建SpringApplication对象

4、SpringApplication对象的run方法,首先创建并启动计时监控类

5、接着通过configureHeadlessProperty设置java.awt.headless的值

6、接着调用getRunListeners创建所有spring监听器

7、接着DefaultApplicationArguments初始化应用应用参数

8、接着prepareEnvironment根据运行监听器和参数准备spring环境

9、接着调用createApplicationContext方法创建应用上下文

10、通过prepareContext准备应用上下文

11、refreshContext方法刷新上下文

12、调用stop方法停止计时监控器类

13、调用started发布应用上下文启动完成事件

14、callRunners方法执行所有runner运行器

15、调用running发布应用上下文就绪事件

16、最后返回应用上下文

猜你喜欢

转载自blog.csdn.net/m0_46937429/article/details/111218589