Spring-boot技术

轻量级的开源框架。

SpringBoot和Spring之间有什么联系? SpringBoot本质上就是一个Spring框架,只不过它是站在Spring的肩膀上。简化了Spring的配置。

Spring 配置魔鬼

Java → SpringBoot

  • 轻量级的开源框架,可以非常方便的整合其他框架
  • 内置了JavaEE容器,不需要依赖于外部的JavaEE容器
  • SpringBoot的应用不需要打成war,而是jar包,以jar包的方式来运行
    • java -jar xxx.jar → 执行的是里面的main方法 → 作为SpringBoot应用程序的入口
  • 约定大于配置(自动配置)

在你没有给你一个具体的配置之前,SpringBoot会给你一个默认的配置(约定);如果你给到一个具体的配置,才采用具体的配置。→ 给到亿些默认值

在这里插入图片描述

搭建SpringBoot应用

Maven工程

start.spring.io

packageName:包名 → 启动类(包含main方法的类,也是应用程序的入口)所在的包目录,这个包目录也是SpringBoot的扫描包目录

在这里插入图片描述在这里插入图片描述
.mvn、mvnw、mvnw.cmd → maven的功能

.gitignore:要放在工作区的根目录才会生效 → 和.git文件夹放在同一级目录

在idea中创建

其实也是在start.spring.io下载应用程序,然后idea帮你解压
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

也可以从Maven工程改造为SpringBoot

只要包含pom.xml和启动类就行

如果你连接不到start.spring.io的时候可以采用

pom.xml → 父工程、dependencies

启动类

// 该注解就是SpringBoot应用启动类上的注解 → 会配置扫描包目录就是该类所处的包目录
@SpringBootApplication
public class Demo1FirstSbApplication {

    // 启动类中一定会包含main方法 → 就是启动SpringBoot应用程序的入口
    public static void main(String[] args) {
        SpringApplication.run(Demo1FirstSbApplication.class, args);
    }

}

pom.xml

parent标签

只要是SpringBoot应用一定会有这样的parent标签

  • 项目构建的配置
  • 依赖的配置
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <!-- version标签里的值就是SpringBoot应用程序的版本 -->
    <version>2.7.1</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

依赖

SpringBoot应用程序中引入的依赖中没有写版本号

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

在依赖中没有版本号,仍然能够引入对应的版本的依赖, 约定大于配置

因为父工程里管理了依赖的版本信息

父工程里还有一个父工程

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.1.5.RELEASE</version>
  <relativePath>../../spring-boot-dependencies</relativePath>
</parent>
<dependencyManagement>
  <dependencies>
  <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.1.5.RELEASE</version>
      </dependency>
   </dependencies>
</dependencyManagement>
      

因为父工程的父工程里管理了依赖的版本信息,在你SpringBoot应用没有写依赖的版本号时,会引入默认的版本信息,同时兼容性也更好

spring-boot-starter

要使用SpringBoot框架,就需要引入这个依赖spring-boot-starter

starter依赖

还有一类依赖

  • spring-boot-starter-xxx → SpringBoot官方提供的,比如spring-boot-starter-web
  • xxx-spring-boot-starter → 第三方框架对SpringBoot支持的依赖,比如mybatis-spring-boot-starter

当你需要引入新的框架的时候,通常引入该框架的starter依赖即可

  • 引入该框架所必须的依赖
  • 会引入autoconfigure依赖

SpringBoot的配置文件

properties格式的

application*.properties

application*.yml

application*.yaml

yml配置文件的语法,含义仍然配置的是键值对

cs.file.path=d:/spring/
cs.size=5
cs.file.size=1024
songge.name=yuanzhi

用yml文件来改造

  • 点 变为 冒号、换行、空格缩进
  • 等于 变为 冒号、一个空格
  • 同一级对齐,缩进几个空格都行
cs:
  file:
    path: d:/spring/
    size: 1024
  size: 5
songge:
  name: yuanzhi

SpringBoot对web的支持

tomcat的配置

server:
  port: 8083  #Tomcat的端口号配置
  servlet:
    context-path: /demo1   # 应用程序的上下文配置(应用名)

静态资源映射

SpringBoot帮我们做了默认的静态资源映射的配置

mapping=/** location=classpath:/static/

其实我们并不用这个配置,因为他配置的这几个location并不是我们最终放静态资源的location,我们现在放静态资源放在文件路径下

所以需要我们自己来指定一些配置

这些配置SpringBoot仍然可以帮我们做,只不过你让SpringBoot帮你做你指定值的配置,在properties或yml文件中提供对应的值

# mapping
spring:
  mvc:
    static-path-pattern: /pic/**
#  spring.resources  或  spring.web.resources
  resources:
    static-locations: file:d:/spring/

SpringMVC的配置类

SpringMVC的配置类仍然是可以使用的,把配置类放在启动类所在的扫描包范围就可以了。

配置类上可以使用@EnableWebMvc,也可以使用@Configuration;这两个注解都会让这个配置类生效,但是我们建议大家使用@Configuration

@EnableWebMvc → 意味着全面接管SpringMVC的相关配置

@Configuration → 意味着做的是配置项的补充

//@EnableWebMvc
@Configuration
//@ComponentScan("com.cs.controller")
public class MvcConfiguration implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pic/**").addResourceLocations("file:d:/spring/");
    }
    // HandlerInterceptor → addInterceptors
    
    // Converter → addFormatters
}

SpringMVC的一些配置

有一些配置可以通过配置文件来进行配置

spring.mvc作为前缀的配置

spring.web或spring.resources作为前缀的配置

MVC中配置起来更方便的配置项

Converter

请求参数接收过程中的类型转换器

在WebMvcConfigurer接口中的addFormatters方法使用registry调用addConverter方法就可以了

在SpringBoot阶段更简单,只需要把Converter注册到容器中就可以生效(等会儿会看源码,为啥这样就行了)

Filter

在SpringBoot应用中,使用Filter(extends OncePerRequestFilter)只需要注册到容器中就会生效

@Component
public class CustomFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest,
                                    HttpServletResponse httpServletResponse,
                                    FilterChain filterChain) throws ServletException, IOException {
        System.out.println("hello 情歌王");
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }
}

如果想要指定Filter的作用范围,也是可以的;但是配置方式有所区别,需要你向容器中注册一个组件FilterRegistrationBean

@Bean
public FilterRegistrationBean filterRegistrationBean() {
    FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
    filterRegistrationBean.setFilter(new CustomFilter());
    filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
    return filterRegistrationBean;
}

SpringBoot对MyBatis的支持

mybatis-spring-boot-starter

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

配置

  • 数据源DataSource需要的参数
  • Mapper的扫描包 👉 @MapperScan
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/cs_db?useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456
@SpringBootApplication
@MapperScan("com.cs.mapper")
public class Demo1FirstSbApplication {

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

}

需要引入一个什么框架的时候,再去引入对应的starter依赖

如果想要修改数据源(DataSource)的类型,使用spring.datasource.type就可以修改

其他配置

在配置文件中使用mybatis作为前缀的配置项

★约定大于配置

容器中的组件获得配置文件中的值

做的事情,就是打通配置文件和容器中的组件之间的联系

我们手动向容器中注册一个组件 → DruidDataSource

@Configuration
public class DataSourceConfiguration1 {

    @Bean
    public DataSource dataSource1() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/cs_db?useUnicode=true&characterEncoding=utf-8");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }
}

上面的代码,我们向容器中注册了DataSource组件,但是组件注册过程中,我们提供的值,是在配置类里写死的 → 魔法值

我们下面要做的事情,就是在配置文件中提供对应的配置项,组件注册过程中的值来源于配置文件

@Value

通过@Value注解来引用配置文件中key,获得配置文件中的值,赋给@Value对应的成员变量

@Configuration
public class DataSourceConfiguration2 {

    // 直接赋值,魔法值
    //String driverClass = "com.mysql.jdbc.Driver";
    //String jdbcUrl = "jdbc:mysql://localhost:3306/cs_db?useUnicode=true&characterEncoding=utf-8";
    //String username = "root";
    //String password = "123456";

    //@Value("com.mysql.jdbc.Driver")
    //String driverClass;
    //@Value("jdbc:mysql://localhost:3306/cs_db?useUnicode=true&characterEncoding=utf-8")
    //String jdbcUrl;
    //@Value("root")
    //String username;
    //@Value("123456")
    //String password;

    @Value("${cs.datasource.driverClass}")
    String driverClass;
    @Value("${cs.datasource.url}")
    String jdbcUrl;
    @Value("${cs.datasource.username}")
    String username;
    @Value("${cs.datasource.password}")
    String password;

    @Bean
    public DataSource dataSource2() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(jdbcUrl);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
}

这种方式还不够方便,也不够优美

@ConfigurationProperties

使用的是set方法来赋值

@ConfigurationProperties注解中有一个prefix属性,prefix属性值(前缀) + 成员变量名=配置文件中的key,就会通过set方法给对应的成员变量做赋值

@Configuration
@Data // 主要是为了提供set方法
@ConfigurationProperties(prefix = "cs.datasource")
public class DataSourceConfiguration3 {

    //cs.datasource.driverClass
    String driverClass;
    //cs.datasource.url
    String url;
    //cs.datasource.username
    String username;
    //cs.datasource.password
    String password;


    @Bean
    public DataSource dataSource3() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
}

还不是最终的方式

@EnableConfigurationProperties

做的事情就是将上面的案例的成员变量单独在提取到单独的类中,这个类专门做参数的接收,参数类。

参数类要注册为容器中的组件,可以在参数类上直接增加@Component,也可以通过@EnableConfigurationProperties引入参数类的方式把参数类注册为容器中的组件

@Configuration
@EnableConfigurationProperties(csDatasourceProperties.class)
// 该注解可以把其value属性对应的类注册为容器中的组件
public class DataSourceConfiguration4 {

    // 把成员变量提取到参数类中之后,我们想要获得之前的值,就需要通过参数类的实例来获得
/*
    @Autowired
    CsDatasourceProperties properties;
*/
    CsDatasourceProperties properties;

    public DataSourceConfiguration4(csDatasourceProperties properties) {
        this.properties = properties;
    }

    @Bean
    public DataSource dataSource4() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(properties.getDriverClass());
        dataSource.setUrl(properties.getUrl());
        dataSource.setUsername(properties.getUsername());
        dataSource.setPassword(properties.getPassword());
        return dataSource;
    }
}
@Data
@ConfigurationProperties(prefix = "cs.datasource4")
//@Component
public class CsDatasourceProperties {
    //cs.datasource.driverClass
    String driverClass;
    //cs.datasource.url
    String url;
    //cs.datasource.username
    String username;
    //cs.datasource.password
    String password;
}

约定大于配置

为啥我们只需要做很少的配置?

SpringBoot给我们提供了巨量的自动配置类

starter依赖 → autoconfigure依赖 → /META-INF/spring.factories → EnableAutoConfiguration → List → 自动配置类

@Configuration
public class DataSourceConfiguration1 {

@Bean
public DataSource dataSource1() {
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/cs_db?useUnicode=true&characterEncoding=utf-8");
    dataSource.setUsername("root");
    dataSource.setPassword("123456");
    return dataSource;
}

}

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
等等

这些自动配置类是全部都生效吗?这些配置类中的配置全部都生效吗?

不是,生效是有条件的,满足一定的条件才会生效。

@ConditionalOnXXX:满足对应的条件时会生效,指的是和它写在一起的其他注解生效

@ConditionalOnMissingXXX:满足缺少XXX的条件时会生效

找一个具有代表性的自动配置类DataSourceTransactionManagerAutoConfiguration

// 配置类
@Configuration
// 当包含对应的Class的时候才会生效 → 引入对应的依赖的时候
@ConditionalOnClass({JdbcTemplate.class, PlatformTransactionManager.class})
@AutoConfigureOrder(2147483647)
//datasource4的方式,通过引入参数类,来引入对应的值
@EnableConfigurationProperties({DataSourceProperties.class})
//该参数类的前缀是spring.datasource我们前面配置mybatis的时候使用过
public class DataSourceTransactionManagerAutoConfiguration {
    public DataSourceTransactionManagerAutoConfiguration() {
    }

    @Configuration
    //容器中的某个类型的组件只有一个的时候生效
    @ConditionalOnSingleCandidate(DataSource.class)
    static class DataSourceTransactionManagerConfiguration {
        private final DataSource dataSource;
        private final TransactionManagerCustomizers transactionManagerCustomizers;

        // 有参构造方法从容器中按照类型取出组件
        DataSourceTransactionManagerConfiguration(DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
            this.dataSource = dataSource;
            this.transactionManagerCustomizers = (TransactionManagerCustomizers)transactionManagerCustomizers.getIfAvailable();
        }

        // 非常典型的组件的约定大于配置
        // 注册组件,对应的方法的返回值注册为容器中的组件
        @Bean
        // 容器中没有PlatformTransactionManager组件的时候生效
        @ConditionalOnMissingBean({PlatformTransactionManager.class})
        public DataSourceTransactionManager transactionManager(DataSourceProperties properties) {
            DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource);
            if (this.transactionManagerCustomizers != null) {
                this.transactionManagerCustomizers.customize(transactionManager);
            }

            return transactionManager;
        }
    }
}

ConditionalOnMissingBean

再来看一下自动配置类MyBatis的自动配置类

mybatis-spring-boot-autoconfigure

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {
    
    private final MybatisProperties properties;
    // 这里有一个关于properties的有参构造方法
    
    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        if (this.properties.getTypeAliasesSuperType() != null) {
            factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
        }
        return factory.getObject();
    }
}

再来看一个,Mvc的自动配置类

  • 为啥Converter只需要注册到容器中就会生效
  • 静态资源映射
public void addFormatters(FormatterRegistry registry) {
    Iterator var2 = this.getBeansOfType(Converter.class).iterator();

    while(var2.hasNext()) {
        Converter<?, ?> converter = (Converter)var2.next();
        registry.addConverter(converter);
    }

    var2 = this.getBeansOfType(GenericConverter.class).iterator();

    while(var2.hasNext()) {
        GenericConverter converter = (GenericConverter)var2.next();
        registry.addConverter(converter);
    }

    var2 = this.getBeansOfType(Formatter.class).iterator();

    while(var2.hasNext()) {
        Formatter<?> formatter = (Formatter)var2.next();
        registry.addFormatter(formatter);
    }

}

private <T> Collection<T> getBeansOfType(Class<T> type) {
    return this.beanFactory.getBeansOfType(type).values();
}
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
		//spring.mvc.static-path-pattern
        String staticPathPattern = this.mvcProperties.getStaticPathPattern();
        if (!registry.hasMappingForPattern(staticPathPattern)) {
            //this.resourceProperties.getStaticLocations → spring.resources.static-locations
            this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
        }

}

staticPathPattern → static-path-pattern 配置文件中驼峰命名的大写字母,可以改成短横线+小写字母

配置文件中的提示

在SpringBoot的配置文件中写一些内容的时候有提示;而我们自己写的却没有提示。

有提示的原因是引入我们有关于提示的文件 → json

/META-INF/(additional-)spring-configuration-metadata.json

如果你的配置项也想要提示 → 在classpath路径下提供/META-INF/spring-configuration-metadata.json

  • 手动新增
  • 使用插件 configuration processor

如果没有生效,则在resources目录下新增一个文件夹/META-INF/spring-configuration-metadata.json

{
  "name": "cs.datasource4.password",
  "type": "java.lang.String",
  "sourceType": "com.cs.config4.csDatasourceProperties",
  "defaultValue": 123456
}

新增defaultValue,现在就多了默认值的提示

问题是,在使用这个值的时候,是否有获得默认值?并不会,这里只是做提示的

如果说我们想要给它赋默认值 →

@Data
@ConfigurationProperties(prefix = "cs.datasource4")
//@Component
public class csDatasourceProperties {
    //cs.datasource.driverClass
    String driverClass;
    //cs.datasource.url
    String url;
    //cs.datasource.username
    String username;
    //cs.datasource.password
    String password = "123456";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值