springboot官方文档解读

官网地址:https://docs.spring.io/spring-boot/docs/2.7.3/reference/htmlsingle/

1 第一个springboot项目

我们在一个路径下面创建pom.xml文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>myproject</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
    </parent>

    <!-- Additional lines to be added here... -->

</project>

这个pom文件是maven的一个配置文件,里面涵盖了项目结构和依赖。

其中spring-boot-starter-parent中为我们提供了很多maven默认配置,比如所打包插件,或者可能用到的依赖等等。

然后,我们可以使用mvn package命令对项目进行打包。我们将会在项目根目录下生成target目录,且在target目录下会生成一个jar包。

 

 

 上面,我们还没有引入任何依赖。当我们运行mvn dependency:tree命令,我们可以看到项目的依赖关系

 

 

 如果我们需要创建的是一个web项目,则我们需要引入spring-boot-starter-web依赖。

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

注:springboot中为我们提供了很多starter,我们引入不同的starter会创建不同类型的应用。

我们再次查看依赖关系,此时依赖就和上面不一样了。

 

 

我们看到,我们引入了starter依赖后,项目会自动为我们加载springmvc、spring-autoconfigure、tomcat相关的jar包。通过这里我们可以体会一下starter的作用。

maven默认源码路径为:src/main/java,为什么?这属于maven的范畴,这里不做细究,只做一下说明:使用mvn help:effective-pom命令我们可以得到项目的一个整体pom,在这个pom中我们可以看到其源码路径:

 

 

我们在源码路径下面创建java启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableAutoConfiguration
public class MyApplication {

    @RequestMapping("/")
    String home() {
        return "Hello World!";
    }

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

}

然后,我们运行 mvn spring-boot:run 可以启动项目。

 

 

 然后,我么浏览器访问

 

 

至于为什么使用mvn spring-boot:run启动项目,可以参考https://blog.csdn.net/zzuhkp/article/details/123493071

接下来,我们希望使用mvn package命令打包,打成一个可运行的jar包(也就是fat jar),因此我们需要在pom文件中引入如下插件

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

这个插件在spring-boot-starter-parent中有引入,在pluginManagement中进行管理,所以我们在自己的pom中就不用写版本号和goal之类的标签了。

    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
          <executions>
            <execution>
              <id>repackage</id>
              <goals>
                <goal>repackage</goal>
              </goals>
            </execution>
          </executions>
          <configuration>
            <mainClass>${start-class}</mainClass>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>

注:<executions>标签规定了插件某些goal的执行方式。

下图是在自己项目pom中添加spring-boot-maven-plugin插件前后的对比,我们可以看到,添加这个打包插件后,jar包格式发生了很大变化,且包含了第三方jar包。

 

2 使用springboot

2.1 配置类

springboot建议使用基于java的配置来代替xml配置文件。通常main方法所在的类是首选 @Configuration 。

没有必要把所有 @Configuration 放到一个类上。我们可以使用 @Import 注解随时添加额外的配置类。我们也可以使用 @ComponentScan 自动扫描加载Component,包括 @Configuration 类。

如果确实需要加载xml格式的配置,建议仍然以 @Configuration 开始,然后使用 @ImportResource 加载xml配置。

2.2 Auto-configuration

Spring Boot自动配置会根据我们引入的依赖来配置我们的应用程序。例如,如果我们在classpath中引入了HSQLDB,那么Spring Boot会自动配置内存数据库

通过在任何一个@Configuration类上添加 @EnableAutoConfiguration 或 @SpringBootApplication 来开启自动配置。通常我们加在启动类上。

如果想知道哪些配置类生效了,可以使用如下方法打印自动配置列表

java -jar ./target/myproject-0.0.1-SNAPSHOT.jar --debug
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.3)
xxxbalabalaxxx...省略
============================ CONDITIONS EVALUATION REPORT ============================ Positive matches: //这些是自动配置识别到的配置类,通常是因为classpath下有特定的类(比如javax.servlet.Servlet)从而触发javabean的加载 ----------------- WebMvcAutoConfiguration matched: - @ConditionalOnClass found required classes 'javax.servlet.Servlet', 'org.springframework.web.servlet.DispatcherServlet', 'org.springframework.web.servlet.config.annotation.WebMvcConfigurer' (OnClassCondition) - found 'session' scope (OnWebApplicationCondition) - @ConditionalOnMissingBean (types: org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; SearchStrategy: all) did not find any beans (OnBeanCondition) ...省略 Negative matches: //这些是自动配置没有识别到的配置类,将不会加载到spring容器 ----------------- ActiveMQAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition) ...省略 Exclusions: ----------- None Unconditional classes: //这些是没有@Condition注解的类,也会注入到spring容器 ---------------------- org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration 2022-09-09 15:13:57.141 INFO 12352 --- [ main] MyApplication : Started MyApplication in 1.615 seconds (JVM running for 1.924) 2022-09-09 15:13:57.141 DEBUG 12352 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state LivenessState changed to CORRECT 2022-09-09 15:13:57.142 DEBUG 12352 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state ReadinessState changed to ACCEPTING_TRAFFIC 2022-09-09 15:14:13.433 DEBUG 12352 --- [ionShutdownHook] o.s.b.a.ApplicationAvailabilityBean : Application availability state ReadinessState changed from ACCEPTING_TRAFFIC to REFUSING_TRAFFIC 2022-09-09 15:14:13.433 DEBUG 12352 --- [ionShutdownHook] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@15975490, started on Fri Sep 09 15:13:55 CST 2022

如果我们发现,某一个配置类被注入到容器,而我们不希望它被自动注入,我们可以在 @SpringBootApplication 注解上使用exclude属性排除这个配置类

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApplication {

}

2.3 组件扫描和自动注入

我们使用 @ComponentScan 注解开启自动扫描,届时所有@Component@Service@Repository@Controller都将会注册到spring中

并且我们建议使用构造器注入的方式进行依赖注入,例子如下(如果存在多个构造器,使用@Autowired指定期望spring使用哪一个)

@Service
public class MyAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

    private final PrintStream out;

    @Autowired
    public MyAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
        this.out = System.out;
    }

    public MyAccountService(RiskAssessor riskAssessor, PrintStream out) {
        this.riskAssessor = riskAssessor;
        this.out = out;
    }

    // ...

}

2.4 @SpringBootApplication

大多数springboot开发者希望自己的项目都需要@EnableAutoConfiguration、@ComponentScan、@SpringBootConfiguration功能,我们使用 @SpringBootApplication 注解就可包含以上三个功能。

// Same as @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

此外,这个注解中还定义了一些别名

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication { @AliasFor(annotation = EnableAutoConfiguration.class) Class<?>[] exclude() default {}; @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; }

如果我们不想使用@ComponentScan功能,则,我们可以按如下方式

@SpringBootConfiguration(proxyBeanMethods = false)
@EnableAutoConfiguration
@Import({ SomeConfiguration.class, AnotherConfiguration.class })
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

这里,组件扫描不会起作用,因此我们使用@Import注解注入两个配置类到spring容器。

2.5 spring-boot-devtools插件

 该插件目的是为了提高开发效率。我们在pom中引入如下依赖就开启devtools支持。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

引入这个插件后,只要classpath路径下发生变化,项目就会自动重启。如下所示

 

在idea中,我们调试时,classpath指的是target目录(参考:https://www.cnblogs.com/zhenjingcool/p/16530567.html),项目跑起来,我们修改代码,发现springboot并不会重启。原因是,idea没有设置自动编译,target路径下的东西并没有发生变化。如果我们希望达到修改代码立即重启的目的,我们可以设置idea自动编译。(个人认为没有必要,如果想重新运行,手动重启就可以了)

当项目打包,我们直接运行jar包时,这个插件将被自动禁用。

3 核心特性

3.1 SpringApplication

SpringApplication是一个类,该类提供了启动spring应用的便捷方式,通常,我们使用它的静态方法启动spring容器,如下所示

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

SpringApplication的构造器如下

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

其参数是一个配置源,这个配置源是一个@Configuration对象。

3.1.1 Lazy Initialization

如果我们设置了Lazy Initialization,bean将会在首次使用的时候实例化。

Lazy Initialization可以缩短启动时间,但是也同时延后了异常的发生时间。

比如一个类实例化时可能会发生异常,从而导致应用程序的退出。

又比如说,lazy Initialiation还会导致jvm分配的内存的持续增加,甚至jvm内存溢出,所以我们要慎重指定jvm分配内存大小。

我么使用如下配合设置Lazy Initialization

spring.main.lazy-initialization=true

3.1.2 定制化SpringApplication

如果SpringApplication的默认使用方法不满足要求,我们可以使用如下方式来设置SpringApplication的属性

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MyApplication.class);
        application.setBannerMode(Banner.Mode.OFF);
        application.run(args);
    }
}

3.1.3 SpringApplicationBuilder

还有一种构建spring容器的方式是使用流式API,这种方式可以构建结构化的spring容器(各个容器之间有父子关系)。

new SpringApplicationBuilder()
        .sources(Parent.class)
        .child(Application.class)
        .bannerMode(Banner.Mode.OFF)
        .run(args);

3.1.4 Application Availability

 这部分内容与k8s相关,待后续补充

3.1.5 Events and Listeners

springboot启动过程中,会发送很多Event,对应有很多Listeners监听这些事件。

很多Event是在ApplicationContext创建之前触发的,所以我们不能通过@Bean来注册listener来监听这些Event。正确的做法是,我们可以通过如下方式在spring容器创建之前注册listener

SpringApplication.addListeners(…​)

或者

SpringApplicationBuilder.listeners(…​)

或者在如下文件中配置

META-INF/spring.factories
例如
org.springframework.context.ApplicationListener=com.example.project.MyListener

events是通过spring框架的事件发布机制发布的。该机制对有些事件会向当前容器的listener发布,同时也会向其父容器中的listener发布。为了区别事件是从哪里来的,必须将产生事件的上下文注入到容器中。比如可以通过实现ApplicationContextAware接口。

public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

3.1.6 Web Environment

如果classpath下提供了spring MVC,则AnnotationConfigServletWebServerApplicationContext类型的web上下文将会被初始化

如果classpath下没有提供spring MVC,但是提供了Spring WebFlux,则AnnotationConfigReactiveWebServerApplicationContext类型的web上下文将会被初始化

否则,AnnotationConfigApplicationContext类型的上下文将会被初始化

我们也可以使用 springApplication.setWebApplicationType(WebApplicationType) 显式设置web类型。

3.1.7 ApplicationRunner 和 CommandLineRunner

这两个的作用类似,如果需要在SpringApplication.run()执行后,在正式接收请求前,执行一些额外的操作,可以使用这两个类。

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
        // Do something...
    }
}

3.2 配置参数

springboot允许你采用多种方式进行参数配置,比如properties,yml,环境变量,命令行等方式。

参数值可以通过@Value注解进行使用。

配置参数的优先级顺序(后面的配置会覆盖前面的配置):

1 SpringApplication的defaultProperties属性

public class SpringApplication {
    ...省略...
    private Map<String, Object> defaultProperties;
    ...省略...
    
    public void setDefaultProperties(Map<String, Object> defaultProperties) {
        this.defaultProperties = defaultProperties;
    }

    public void setDefaultProperties(Properties defaultProperties) {
        this.defaultProperties = new HashMap<>();
        for (Object key : Collections.list(defaultProperties.propertyNames())) {
            this.defaultProperties.put((String) key, defaultProperties.get(key));
        }
    }
}

2 @Configuration类上的@PropertySource注解

3 配置文件(比如application.properties或者application.yml)

  配置文件的使用顺序是

  jar包内的application.properties或者application.yml。
  jar包内的application-{profile}.properties或者application-{profile}.yml
  jar包外的application.properties或者application.yml
  jar包外的application-{profile}.properties或者application-{profile}.yml

4 操作系统环境变量

5 java系统变量(System.getProperties())

6 来自java:comp/env的JNDI属性

7 ServletContext初始化参数

8 ServletConfig初始化参数

9 来自SPRING_APPLICATION_JSON中的属性

注:比如我们在命令行中首先定义了一个这个变量,然后再使用

 SPRING_APPLICATION_JSON='{"server":{"port":"9999"}}' java -jar aaa.jar 

或者作为java的系统变量提供

 java -Dspring.application.json='{"server":{"port":"9999"}}' -jar xxx.jar 

10 命令行参数

 java -jar app.jar --name="Spring" 

总结:建议在整个应用程序中使用一种格式的配置文件

3.2.1 命令行参数

SpringApplication把命令行参数转化为spring中的属性并且添加到Spring Environment。命令行参数优先级最高

如果我们想禁用命令行参数,使用如下方式 SpringApplication.setAddCommandLineProperties(false) 

3.2.2 SPRING_APPLICATION_JSON

通常环境变量和System变量有很多限制,因此,springboot允许我们在json中配置变量并使用。

例如我们配置my.name=test为一个环境变量

 $ SPRING_APPLICATION_JSON='{"my":{"name":"test"}}' java -jar myapp.jar 

或者,配置到系统属性

 $ java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar 

或者,直接放在命令行参数中

 $ java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}' 

3.2.3 配置文件

当应用启动时SpringBoot将在按照如下顺序自动查找并加载application.properties和application.yaml。后面的会覆盖前面的配置

classpath
classpath /config
当前路径
当前路径 /config

也就是说当启动一个jar包时,springboot默认读取jar包所在路径下的/config/application.properties

如果不想使用application.properties(.yml)作为前缀,可以设置,方法如下:

 $ java -jar myproject.jar --spring.config.name=myproject 

 

 

 

 

 

 

 

 

 

后续内容持续更新中...

 

Application Availability

posted @ 2022-09-07 00:14  zhenjingcool  阅读(1039)  评论(2编辑  收藏  举报