springboot-introduce.md

335 阅读5分钟

springboot简介

springboot之前

  1. 要集成一个spring框架,开启spring的特性需要进行一系列的显示配置比如:事务管理、MVC、基于Thymeleaf的WEB视图,配置Servlet和过滤器(比如Spring的DispatcherServlet)同样需要在web.xml或Servlet初始化代码里进行显式配置

  2. 项目的依赖管理也是件吃力不讨好的事情。决定项目里要用哪些库就已经够让人头痛的了,你还要知道这些库的哪个版本和其他库不会有冲突,这难题实在太棘手

以上这些无论业务代码是多少,这些都是不可缺少,springboot的出现让这一切变得简单

springboot精要

  1. 起步依赖,告诉springboot需要什么功能,他就能引入需要的库
  2. 自动配置,针对很多spring应用程序常见的应用功能,springboot能自动提供相关配置
  3. 命令行界面(springboot CGI),很少使用
  4. Actuator,提供在运行时检视应用程序内部情况的能力,很少使用

起步依赖分析

springboot通过提供众多起步依赖降低项目依赖的复杂度,起步依赖本质上是一个Maven项目对象依赖,定义了对其他库的传递依赖,比如springboot常用的依赖:

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

可以通过mvn dependency:tree查看依赖树

- org.springframework.boot:spring-boot-starter-web:jar:2.1.2.RELEASE:compile
   +- org.springframework.boot:spring-boot-starter:jar:2.1.2.RELEASE:compile
   |  +- org.springframework.boot:spring-boot:jar:2.1.2.RELEASE:compile
   |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.2.RELEASE:compile
   |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.1.2.RELEASE:compile
   |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
   |  |  |  +- ch.qos.logback:logback-core:jar:1.2.3:compile
   |  |  |  \- org.slf4j:slf4j-api:jar:1.7.25:compile
   |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.11.1:compile
   |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.11.1:compile
   |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
   |  +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
   |  +- org.springframework:spring-core:jar:5.1.4.RELEASE:compile
   |  |  \- org.springframework:spring-jcl:jar:5.1.4.RELEASE:compile
   |  \- org.yaml:snakeyaml:jar:1.23:runtime
   +- org.springframework.boot:spring-boot-starter-json:jar:2.1.2.RELEASE:compile
   |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile
   |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
   |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile
   |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.8:compile
   |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.8:compile
   |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.8:compile
   +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.2.RELEASE:compile
   |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.14:compile
   |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.14:compile
   |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.14:compile
   +- org.hibernate.validator:hibernate-validator:jar:6.0.14.Final:compile
   |  +- javax.validation:validation-api:jar:2.0.1.Final:compile
   |  +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
   |  \- com.fasterxml:classmate:jar:1.4.0:compile
   +- org.springframework:spring-web:jar:5.1.4.RELEASE:compile
   |  \- org.springframework:spring-beans:jar:5.1.4.RELEASE:compile
   \- org.springframework:spring-webmvc:jar:5.1.4.RELEASE:compile
      +- org.springframework:spring-aop:jar:5.1.4.RELEASE:compile
      +- org.springframework:spring-context:jar:5.1.4.RELEASE:compile
      \- org.springframework:spring-expression:jar:5.1.4.RELEASE:compile

排除起步依赖中的某一项直接加入exclusions标签

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.fasterxml.jackson.core</groupId>
        </exclusion>
    </exclusions>
</dependency>

也可以不使用起步依赖中的版本,使用其他版本。MAVEN总会使用最近的依赖,在项目的构建说明文件里增加的这个依赖,会覆盖传递依赖引入的另外一个依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.4.3</version>
</dependency>

自动配置分析

Condition

  1. 实现Condition接口,实现其抽象方法
    //true满足条件,false不满足条件
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
    
  2. 在声明配置中判断是否生效,如下判断是否加载为一个Bean的代码片段
    @Bean
    //matches接口返回true则加载为bean
    @Conditional({PetCondition.class})
    public Dog dog(){
        return new Dog();
    }
    

类Condition注解

他们和Condition有类似的功能,算是对Condition的一个扩展,满足了条件就生效

  • @ConditionalOnBean——配置了某个特定的Bean
  • @ConditionalOnMissingBean——没有配置特定的Bean
  • @ConditionalOnClass——Classpath里有指定的类
  • @ConditionalOnMissingClass——Classpath里缺少指定的类
  • @ConditionalOnExpression——给定的SpEL表达式计算结果为true
  • @ConditionalOnJava——java的版本匹配特定值或者一个范围值
  • @ConditionalOnJndi——参数中给定的JNDI位置必须存在一个,如果没有参数则要JNDI InitialContext
  • @ConditionalOnProperty——指定配置属性要有一个明确的值
  • @ConditionalOnResource——Classpath里有指定的资源
  • @ConditionalOnWebApplication——这是一个Web应用程序
  • @ConditionalOnNotWebApplication——这不是一个Web应用程序

@SpringBootApplication

  1. 这是springboot的主类启动注解,一般如下

    @SpringBootApplication
    public class SpringBootDemoApplication extends SpringBootServletInitializer {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringBootDemoApplication.class, args);
        }
    }
    
  2. @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) })
    public @interface SpringBootApplication {
        //若干属性省略,来修改父注解的属性值
    }
    
  3. 父注解@SpringBootConfiguration等同于@Configuration注解,声明为一个配置类

  4. 父注解@ComponentScan配置额外的包扫描路径

  5. 父注解@EnableAutoConfiguration为主要的自动配置类注解,定义如下

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
        //省略若干属性 
    }
    
  6. @AutoConfigurationPackage注解主要是自动加载某些jar包的bean,定义如下

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import(AutoConfigurationPackages.Registrar.class)
    public @interface AutoConfigurationPackage {
    
    }
    
    
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {
        //它其实返回了当前主程序类的 同级以及子级 的包组件
        //也就是为什么我们一般会将主类放在最外面的原因
        register(registry, new PackageImport(metadata).getPackageName());
    }
    
  7. @Import(AutoConfigurationImportSelector.class)引入自动配置类包,相关的执行代码如下

    //加载spring.factories文件中的类
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
    		AnnotationAttributes attributes) {
    	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
    			getSpringFactoriesLoaderFactoryClass(), 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;
    }
    
  8. spring.factories中声明的类,都是遵循的Condition来决定是否加载成为bean,例如DataSourceAutoConfiguration类,部分定义如下

    @Configuration
    @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
    @EnableConfigurationProperties(DataSourceProperties.class)
    @Import({ DataSourcePoolMetadataProvidersConfiguration.class,
            DataSourceInitializationConfiguration.class })
    public class DataSourceAutoConfiguration {
    
        @Configuration
        @Conditional(EmbeddedDatabaseCondition.class)
        @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
        @Import(EmbeddedDataSourceConfiguration.class)
        protected static class EmbeddedDatabaseConfiguration {
    
        }
    
        @Configuration
        @Conditional(PooledDataSourceCondition.class)
        @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
        @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
                DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
                DataSourceJmxConfiguration.class })
        protected static class PooledDataSourceConfiguration {
    
        }
    }
    

自定义配置

覆盖自动配置

在自动配置中,有很多都是基于ConditionalOnMissingBean来判断的,当我们自定义的这个bean,他就不会采用自动配置,如DataSourceAutoConfiguration中的部分配置:

@Configuration
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedDatabaseConfiguration {

}

通过属性文件外置配置

Spring Boot应用程序有多种设置途径。Spring Boot能从多种属性源获得属性,高优先级可以覆盖低优先级的属性,优先级从高到低排序如下:

  1. 命令行参数
    java -jar readinglist-0.0.1-SNAPSHOT.jar --spring.main.show-banner=false
    
  2. java:comp/env里的JNDI属性
  3. JVM系统属性
  4. 操作系统环境变量
    export spring_main_show_banner=false
    
  5. 随机生成的带random.*前缀的属性(在设置其他属性时,可以引用它们,比如${random. long})
  6. 应用程序以外的application.properties或者appliaction.yml文件
    spring.main.show-banner=false
    
    spring:
        main:
        show-banner: false
    
  7. 打包在应用程序内的application.properties或者appliaction.yml文件
  8. 通过@PropertySource标注的属性源
  9. 默认属性

application.properties和application.yml文件能放在以下四个位置,优先级从高到低如下

  1. 外置,在相对于应用程序运行目录的/config子目录里
  2. 外置,在应用程序运行的目录里
  3. 内置,在config包内
  4. 内置,在Classpath根目录