学习要求
良好的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配置版
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版
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中,是怎么这个扫描器配置呢?
定义类-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实例属性了解
定义一个新的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实例依赖注入
定义新类
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>标签
该标签用于配置类与配置类间的导入。
验证
操作流程
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表达式
例子:
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加载配置文件之后,解析出数据缓存到该类。