学习要求

良好的java基础, 熟悉Spring框架,熟悉Mybatis框架,属性SpringMVC框架

教程目标

  • 了解SpringBoot的作用
  • 掌握JavaConfig的配置方式
  • 掌握SpringBoot常用注解
  • 了解SpringBoot自动配置原理
  • 掌握@SpringBootApplication及其上面的元注解的作用
  • 掌握SpringBoot属性绑定
  • 了解日志的作用

SpringBoot介绍

参考百度百科: https://baike.baidu.com/item/Spring%20Boot/20249767?fr=aladdin

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者

一个问题:Springboot怎么做到快速开发,怎么做到风靡全球,成为快速应用开发领域领导者呢?

得益于:JavaConfig技术的出现

JavaConfig入门

我们通常使用Spring都会使用xml对Spring进行配置,随着功能以及业务逻辑的日益复杂,应用伴随着大量的XML配置文件以及复杂的Bean依赖关系,使用起来很不方便。

在Spring3.0开始,Spring官方就已经开始推荐使用java配置来代替传统的xml配置了,它允许开发者将bean的定义和Spring的配置编写到到Java类中,不过似乎在国内并未推广盛行。当SpringBoot来临,人们才慢慢认识到java配置的优雅,但是,也仍然允许使用经典的XML方式来定义bean和配置spring。

大白话:JavaConfig就是使用java注解替换原先xml配置

所以在学习springboot之前, 我们得先学习JavaConfig相关知识点。后面的案例使用JavaConfig的方式将传统的Spring xml配置转换成JavaConfig方式。

项目准备

1>创建maven项目-javaconfig

2>导入依赖

<properties>
        <spring.version>5.0.8.RELEASE</spring.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.22</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>

3>配置文件-applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd  ">


</beans>

我们来对比项使用xml配置与使用javaconfig方式区别

XML配置版

springboot jar config 文件夹_spring

1>定义一个Bean-SomeBean

public class SomeBean {
}

2>在applicationContext.xml配置bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd  ">

    <bean name="someBean" class="com.langfeiyes._01_ioc_xml.SomeBean" ></bean>

</beans>

3>测试-App

@RunWith(SpringRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {
    @Autowired
    private ApplicationContext ctx;
    @Test
    public void testApp(){
        SomeBean someBean = ctx.getBean("someBean", SomeBean.class);
        System.out.println(someBean);
    }
}

JavaConfig版

springboot jar config 文件夹_spring_02

1>定义一个Bean-SomeBean

public class SomeBean {
}

2>定义一个配置类-AppConfig

@Configuration
public class AppConfig {
    @Bean
    public SomeBean someBean(){
        return new SomeBean();
    }
}

@Configuration : spring配置类注解,贴有这个注解的类功能等价于:applicationContext.xml

@Bean: spring Bean实例注解,贴有该注解的方法为实例方法, 功能等价于:

<bean name="someBean" class="com.langfeiyes._02_ioc_config.SomeBean" ></bean>

注意:实例方法返回的对象会交给spring容器管理起来

3>测试-App

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)  //引用的是配置类而不是配置文件
public class App {
    @Autowired
    private ApplicationContext ctx;
    @Test
    public void testApp(){
        SomeBean someBean = ctx.getBean("someBean", SomeBean.class);
        System.out.println(someBean);
    }
}

Bean组件扫描

学习spring框架时, 我们知道spring有4个版型标签

@Controller  //标记控制层
public class EmployeeController{
}
@Service    //标记服务层
public class EmployeeServiceImpl{
}
@Repository  //标记持久层
public class EmployeeDAOImpl{
}
@Component   //其他类
public class EmployeeListener{
}

4个版型标签功能都是一样:当spring容器扫描器扫描到贴有版型标签的类,会自动创建这些类的实例对象,并交给容器管理。

spring容器扫描器配置:

<context:component-scan base-package="指定扫描的包路径"></context:component-scan>

那在JavaConfig中,是怎么这个扫描器配置呢?

springboot jar config 文件夹_java_03

定义类-SomeBean

@Component  //版型标签
public class SomeBean {
}

配置类-AppConfig

@Configuration
@ComponentScan(basePackages ="com.langfeiyes._03_scan" )  //组件扫描标签
public class AppConfig {
}

@ComponentScan : spring组件扫描注解, 扫描basePackages属性指定包及其子包下所有的贴有版型标签类,并创建对象交给Spring容器管理。

注意:如果不指定basePackages属性,表示扫描当前类所有包及其子包

测试-App

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class App {
    @Autowired
    private ApplicationContext ctx;
    @Test
    public void testApp(){
        SomeBean someBean = ctx.getBean("someBean", SomeBean.class);
        System.out.println(someBean);
    }
}

@Bean注解详解

Bean实例属性了解

springboot jar config 文件夹_spring_04

定义一个新的SomeBean类

@Setter
@Getter
public class SomeBean {
    public SomeBean() {
        System.out.println("SomeBean被创建");
    }
    public void init() {
        System.out.println("SomeBean被初始化");
    }
    public void destroy() {
        System.out.println("SomeBean被销毁");
    }
}

Xml版完整的Bean实例配置

<bean name="someBean" class="com.langfeiyes._04_bean_attr.SomeBean"
      id="sbId"
      scope="singleton"   
      init-method="init" 
      destroy-method="destroy">

</bean>

JavaConfig配置方式

@Scope("singleton")
@Bean(value = "sb",initMethod = "init", destroyMethod = "destroy")
public SomeBean someBean(){
    return new SomeBean();
}

xml中bean标签与@Bean实例方法配置方式比较

* 1>bean标签中name属性等价于@Bean注解中name/value属性
* 2>bean标签中id属性等价于实例方法的方法名
* 3>bean标签中init-method属性等价于@Bean注解中initMethod属性
* 4>bean标签中destroy-method属性等价于@Bean注解中destroyMethod属性
* 5>bean标签中scope属性等价于实例方法中的@Scope注解

@Bean实例依赖注入

springboot jar config 文件夹_maven_05

定义新类

public class OtherBean {
}
@Setter
@Getter
public class SomeBean {
    private OtherBean otherBean;
}

Xml版Bean实例配置

<bean name="otherBean" class="com.langfeiyes._05_bean_di.OtherBean"></bean>

<bean name="someBean" class="com.langfeiyes._05_bean_di.SomeBean">
    <property name="otherBean" ref="otherBean"></property>
</bean>

JavaConfig配置方式

分析:

JavaConfig实现传统依赖注意需要注意:

1>someBean对象可以从容器中获取

2>otherBean可以从容器中获取

3>someBean对象通过getOtherBean()方法获得的bean应该==从容器获取的otherBean对象。

方式1:调用实例方法

@Configuration
public class AppConfig {
    @Bean
    public SomeBean someBean(){
        SomeBean someBean = new SomeBean();
        someBean.setOtherBean(otherBean());
        return someBean;
    }
    @Bean
    public OtherBean otherBean(){
        return new OtherBean();
    }
}

注意:

1>此处要注意,是调用otherBean() 方法, 不是直接new

2>多次调用otherBean()方法, spring容器只会执行一次otherBean对象的构建,原因:otherBean()方法被spring容器代理了,每次调用前都会执行容器bean检查,当发现容器中已经有了,直接从容器中拿。如果没有,则执行方法,并将返回值放置到容器中。

 

方式2:注入实例对象

@Configuration
public class AppConfig {
    @Bean
    public SomeBean someBean(OtherBean otherBean){
        SomeBean someBean = new SomeBean();
        someBean.setOtherBean(otherBean);
        return someBean;
    }
    @Bean
    public OtherBean otherBean(){
        return new OtherBean();
    }
}

分析:方式2的操作有点类似请求映射方法注入请求对象

@RequestMapping("/xxx")
public String xxx(HttpServletRequest req){....}

配置类相互导入

Javaconfig 提供2种注解实现配置类,配置文件间的导入:

@Import

配置类导入注解,贴在配置类上,作用等价于:<import resource="xxx配置.xml"></import>标签

该标签用于配置类与配置类间的导入。

验证

springboot jar config 文件夹_spring_06

操作流程

1>定义OtherBean跟SomeBean

public class OtherBean {
}
public class SomeBean {
}

2>OtherBean配置在OtherConfig中, SomeBean配置在AppConfig

@Configuration
public class OtherConfig {
    @Bean
    public OtherBean otherBean(){
        return new OtherBean();
    }
}

@Import(OtherConfig.class)
@Configuration
public class AppConfig {
    @Bean
    public SomeBean someBean(){
        return new SomeBean();
    }
}

3>App加载AppConfig进行测试, 打印someBean跟otherBean对象

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {AppConfig.class})
public class App {
    @Autowired
    private ApplicationContext ctx;
    @Test
    public void testApp(){
        SomeBean someBean = ctx.getBean("someBean", SomeBean.class);
        OtherBean otherBean = ctx.getBean("otherBean", OtherBean.class);
        System.out.println(someBean);
        System.out.println(otherBean);
    }
}

@ImportResource

配置文件导入注解,贴在配置类上,作用等价于:<import resource="xxx配置.xml"></import>标签

该标签用于配置类与配置文件间的导入

1>定义OtherBean跟SomeBean

2>OtherBean配置在applicationContext.xml中, SomeBean配置在AppConfig

<bean name="otherBean" class="com.langfeiyes._06_import.OtherBean"></bean>
@ImportResource("classpath:applicationContext.xml")
@Configuration
public class AppConfig {
    @Bean
    public SomeBean someBean(){
        return new SomeBean();
    }
}

3>App加载AppConfig进行测试, 打印someBean跟otherBean对象

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {AppConfig.class})
public class App {
    @Autowired
    private ApplicationContext ctx;
    @Test
    public void testApp(){
        SomeBean someBean = ctx.getBean("someBean", SomeBean.class);
        OtherBean otherBean = ctx.getBean("otherBean", OtherBean.class);
        System.out.println(someBean);
        System.out.println(otherBean);
    }
}

资源配置文件加载与取值

JavaConfig也提供类进行properties文件加载注解

@PropertySource

资源配置文件加载注解,贴在配置类上,用于将properties类型文件加载到spring容器中。等于:

<context:property-placeholder location="classpath:xxx.perperties"/>

@Value

资源文件取值注解,从properties配置中获取配置的数据,使用SpEL表达式

例子:

springboot jar config 文件夹_spring_07

1>创建一个db.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///xxx
jdbc.username=root
jdbc.password=admin

2>定义新类接收上面属性值

@Setter
@Getter
@ToString
public class MyDataSource {
    private String driverClassName;
    private String url;
    private String username;
    private String password;
}

3>配置类中加载db.properties

@PropertySource("classpath:db.properties")
@Configuration
public class AppConfig {


    @Value("${jdbc.driverClassName}")
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    public MyDataSource myDataSource(){
        MyDataSource source = new MyDataSource();
        source.setDriverClassName(driverClassName);
        source.setUrl(url);
        source.setUsername(username);
        source.setPassword(password);
        return source;
    }
}

4>测试打印

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {AppConfig.class})
public class App {
    @Autowired
    private ApplicationContext ctx;
    @Test
    public void testApp(){
        MyDataSource myDataSource = ctx.getBean("myDataSource", MyDataSource.class);
        System.out.println(myDataSource);
    }
}

一种简化操作

@PropertySource("classpath:db.properties")
@Configuration
public class AppConfig {
    @Autowired
    private Environment env;
    @Bean
    public MyDataSource myDataSource(){
        MyDataSource source = new MyDataSource();
        source.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        source.setUrl(env.getProperty("jdbc.url"));
        source.setUsername(env.getProperty("jdbc.username"));
        source.setPassword(env.getProperty("jdbc.password"));
        return source;
    }
}

分析: Environment 是spring提供用于管理properties类型工具类,spring加载配置文件之后,解析出数据缓存到该类。