1. SpringBoot概念
1.1. 什么是SpringBoot1.2. SpringBoot优点1.3. 微服务 2. SpringBoot基础入门
2.1. maven设置2.2. 入门案例
2.2.1. 导入依赖2.2.2. 创建主程序2.2.3. 编写业务2.2.4. 测试和简化配置2.2.5. 简化部署 3. Spring Boot的自动配置原理
3.1. 依赖管理3.2. 自动配置3.3. 容器功能
3.1.1. Configuration注解进行组件添加3.1.2. Bean、Controller、Service、Repository、Component3.1.3. ComponentScan、import3.1.4. Conditional 3.4. 原生配置文件引入
3.4.1. importResource注解3.4.2. 配置绑定 3.5. 自动配置原理入门
3.5.1. 引导加载自动配置类SpringBootApplication3.5.2. 按需开启自动配置项3.5.3. 修改默认配置3.5.4. 实践3.5.5. Spring boot开发技巧
1. SpringBoot概念 1.1. 什么是SpringBoot整合Spring技术栈的一站式框架,是简化Spring技术栈的快速开发框架,能快速创建生产级别的Spring应用
1.2. SpringBoot优点可以创建独立的Spring应用内嵌web服务器自动starter(启动器)依赖,简化构建配置提供生产级别的监控,检查以及外部化配置无代码生成,无需编写xml自动配置Spring以及第三方功能(如Spring整合Mybatis,Spring整合Spring MVC) 1.3. 微服务
是一种架构风格,一个应用拆分成一组小型服务,每个服务运行在自己的进程内也就是可独立部署和升级,服务之间使用轻量级的HTTP交互,服务围绕业务功能拆分;去中心化,不同服务可以使用不用的存储技术或者语言。
2. SpringBoot基础入门 2.1. maven设置nexus-aliyun central Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public jdk-1.8 true 1.8 1.8 1.8 1.8
在maven -> conf -> settings.xml中增加上面两个配置,第一个为阿里的镜像,以后下载依赖的速度更快;第二个配置的是java的编译版本,设置为1.8
2.2. 入门案例需求:浏览器发送Hello请求,响应Hello,Spring Boot2
2.2.1. 导入依赖org.springframework.boot spring-boot-starter-parent 2.3.4.RELEASE org.springframework.boot spring-boot-starter-web
引入Spring boot2的父项目依赖,想要开发web,就必须引入web场景
2.2.2. 创建主程序在java包下创建com.hz.boot包,在boot包下创建主程序类
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}
2.2.3. 编写业务
在boot2包新建一个包为controller,创建具体的Controller类。只需要RestController注解即可替代以前在Spring MVC中的Controller和ResponseBody两个注解
//@Controller
//@ResponseBody
// Spring boot2新注解RestController包含了Controller注解和ResponseBody注解
@RestController
public class HelloController {
@RequestMapping("/hello")
public String Hello(){
return "Hello, Spring Boot2";
}
}
优点:不再需要配置SpringMVC.xml以及web.xml,甚至Tomcat都不需要配置,直接运行主程序的main方法,Spring boot2会帮助启动服务器,直接通过URL访问即可。另外,SpringBoot准备了一个统一的配置文件,可以在resources下创建一个application.properties
2.2.4. 测试和简化配置直接运行main方法即主程序方法即可启动,只需要在application.properties中配置所需要的即可完成配置。
2.2.5. 简化部署直接将项目打成jar包,直接在目标服务器执行即可
org.springframework.boot spring-boot-maven-plugin
注意点:
取消掉cmd中的快速编辑模式初始下载SpringBoot2的依赖比较慢,可以点击maven的刷新 3. Spring Boot的自动配置原理 3.1. 依赖管理
org.springframework.boot spring-boot-starter-parent 2.3.4.RELEASE
点进去依旧存在一个父项目:spring-boot-dependencies。在spring-boot-dependencies.pom中做了许多依赖的导入,甚至版本都进行了统一,几乎声明了所有开发中常用的版本号,无需手动写版本号。====
开发导入starter场景启动器:存在许多spring-boot-starter-*, *为某种场景。只需要引入starter,这个场景的所有常规需要的依赖都可以自动引入。见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。所有的场景启动器最底层的依赖为:
org.springframework.boot spring-boot-starter 2.3.4.RELEASE compile
无需关注版本号,自动版本仲裁:引入依赖默认都可以不写版本;引入非版本仲裁的jar,要写版本号可以修改默认版本号
修改的方法:
查看spring-boot-dependencies里面规定当前依赖的版本所使用的key,如mysql.version, aspectj.version在当前项目的pom文件中使用properties属性来自定义需要的版本
3.2. 自动配置5.1.43
自动配置Tomcat
引入Tomcat依赖
配置Tomcat
自动配置Spring MVC
- 引入Spring MVC全套组件,starter-web场景中也配值了SpringMVC的导入
自动配制好SpringMVC常用功能(组件):如,dispatcherServlet核心控制器,characterEncodingFilter字符编码过滤器,ViewResolver视图解析器和multipartResolver文件上传解析器等等
自动配置web常见功能,如:字符编码问题
默认的包结构:
主程序所在包以及下面的所有子包里面的组件都会被默认扫描出来,可以通过查看官方文档来看,Spring boot使用的是默认包扫描。无需以前的包扫描配置
想要改变扫描路径:在主程序中的@SpringBootApplication注解中加入scanbasePackages"com.example"将包扫描的范围变大;或者使用@ComponentScan注解指定扫描路径。
@SpringBootApplication 该注解默认的扫描路径为主程序所在的包即com.example.boot2
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example.boot2")
按需加载所有自动配置项:
- 非常多的starter引入了哪些场景,场景的自动配置才会开启SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
配置的默认值:在application.properties中的默认配置最终都是映射到某一个类上的,如:spring.servlet.multipart.max-file-size最终映射到MultpartProperties类上;配置文件的值最终会绑定到对应的类上,这个类会在容器中创建对象
3.3. 容器功能 3.1.1. Configuration注解进行组件添加自定义配置类MyConfig,使用注解Configuration
@Configuration(proxyBeanMethods = true) // 告诉Spring这是一个配置类 == 配置文件
public class MyConfig {
@Bean
public User user_1(){
User user = new User("大司马", 36);
// User组件依赖Pet组件
user.setPet(tomcat());
return user;
}
@Bean("Tom")
public Pet tomcat(){
return new Pet("Tomcat");
}
}
给容器添加组件,方法名作为组件的id ,返回类型即为组件类型 ,返回的值即为容器中的实例。也可以通过Bean注解指定组件的id配置类中使用Bean注解给容器中注入组件,默认是单实例的配置类本身也是一个组件在Spring Boot2之后,Configuration注解引入一个新的属性proxyBeanMethods代理bean的方法(默认为true)
在主程序中进行测试:
@SpringBootApplication(scanbasePackages = "com.hz")
public class MainApp {
public static void main(String[] args) {
// 返回的是IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApp.class, args);
// 查看容器中的组件
String[] names = run.getBeanDefinitionNames();
for(String name: names){
System.out.println(name);
}
// 从容器中获取组件
Pet tom_1 = run.getBean("Tom", Pet.class);
Pet tom_2 = run.getBean("Tom", Pet.class);
System.out.println("单实例:" + (tom_1 == tom_2));
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
User user1 = bean.user_1();
User user2 = bean.user_1();
System.out.println(user1 == user2);
User user_1 = run.getBean("user_1", User.class);
Pet tom = run.getBean("Tom", Pet.class);
System.out.println("user组件依赖pet组件:" + (user_1.getPet() == tom));
}
}
打印结果:
外部无论对配置类中的这个组件注册方法调用多少次,获取的都是之前注册在容器中的单实例。指定Configuration注解中的proxyBeanMethods为true则表示代理对象调用方法,自定义的config实例是基于SpringCGLIB方法进行代理的(通过继承来代理)。 Spring总会检查这个组件是否在容器中存在,如果有则不会新创建,保证是单实例的当proxyBeanMethods=true时才会成立: 由于容器中已经存在pet组件,再次通过方法获取该组件依旧是同一个对象
User组件依赖Pet组件,也就是主程序中的user组件依赖pet组件Full(proxyBeanMethods=true) Spring总会检查某个组件是否在容器中存在;Lite(proxyBeanMethods=false) 解决组件依赖,如果不依赖容器中注册的组件,可以使用Lite模式,不需要每次都让Spring来检查某个组件是否存在容器中,每次使用都是新的实例。
3.1.2. Bean、Controller、Service、Repository、Component
之前这些注解都能使用,只需要保证主程序能扫描到这些包所在的位置
3.1.3. ComponentScan、import@import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
...
}
给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名, 可以在主程序中测试容器中是否存在这两个组件
3.1.4. Conditional条件装配:满足Conditional指定的条件则进行组件注入
ConditionalOnBean(name=“Tom”)作用在类上,如果容器中不存在Tom组件,则配置类以及配置类中的所有组件都不会进行注册
ConditionalOnMissingBean(naem=“Tom”)作用与之相反
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
//@ConditionalOnBean(name = "tom")
@ConditionalOnMissingBean(name = "tom")
public class MyConfig {
@Bean
public User user01(){
User zhangsan = new User("zhangsan", 18);
//user组件依赖了Pet组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom22")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
//2、查看容器里面的组件
String[] names = run.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
boolean tom = run.containsBean("tom");
System.out.println("容器中Tom组件:"+tom);
boolean user01 = run.containsBean("user01");
System.out.println("容器中user01组件:"+user01);
boolean tom22 = run.containsBean("tom22");
System.out.println("容器中tom22组件:"+tom22);
}
3.4. 原生配置文件引入
3.4.1. importResource注解
配置beans.xml文件:
在配置类中使用注解importResource,并且指明beans.xml文件的类路径,即可完成注册。在主程序中进行测试:
// 导入beans.xml的组件测试
boolean bean1 = run.containsBean("Faker");
boolean bean2 = run.containsBean("Lion");
System.out.println("bean1:"+ bean1);
System.out.println("bean2:"+ bean2);
3.4.2. 配置绑定
如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用
定义一个实体类car:
public class Car {
private String brand;
private Double price;
...
在application.prtperties中配置car的两个属性:
mycar.brand = AUDI mycar.price = 500000.00
两种方式可以得到实现封装:
使用注解==@Component + @ConfigurationProperties==:在实体类car中@ConfigurationProperties注解中设置prefix为mycar,并且加上Component注解(只有在容器中的组件 才会拥有SpringBoot提供的强大功能)@EnableConfigurationProperties + @ConfigurationProperties: 在配置类中加上注解EnableConfigurationProperties 并且指定Car.class, 开启Car属性配置功能,将Car组件自动注册到容器中
编写CarController用来测试:
@RestController
public class CarController {
@Autowired
private Car car;
@RequestMapping("/car")
public Car car(){
return car;
}
}
启动服务器通过URL访问可以得到:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{
...
}
SpringBootConfiguration注解:继承了Configuration注解,表示当前是一个配置类ComponentScan注解:告诉Spring需要扫描的包EnableAutoConfiguration注解:该注解又继承了两个注解AutoConfigurationPackage和import
@AutoConfigurationPackage
@import({AutoConfigurationimportSelector.class})
public @interface EnableAutoConfiguration {
AutoConfigurationPackage:自动配置包,指定了默认的包规则
@import({Registrar.class})
public @interface AutoConfigurationPackage {
点击Register类中,并且在register方法处打断点调试,可以看到:
metadata为注解的一些元信息,包括注解作用在的类名:com.hz.boot.MainApp; 利用Register将指定的一个包下的所有组件导入进来(MainApp主程序 所在的包下)
import(AutoConfigurationimportSelector.class):
在AutoConfigurationimportSelector类的源码中,在getAutoConfigurationEntry方法中打断点进行调试,可以看到configurations有127个组件,该方法在容器中批量导入了一些组件;
调用List
在SpringFactoriesLoader类中利用工厂加载Map
这里的URL为meta-INF/spring.factories位置来加载文件,默认扫描的是系统中所有meta-INF/spring.factories位置的文件;
在spring-boot-autoconfigure-2.3.4.RELEASE.jar中有meta-INF/spring.factories,如下:
文件里面写死了SpringBoot一启动就需要加载的配置类,总共127个
虽然我们127个场景的所有自动配置启动的时候默认全部加载。但是xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置
在DispatcherServletAutoConfiguration类中,首先会进行判断:是SpringMVC原生web开发还是响应式web开发,是否注册了DispatcherServlet这个组件,由于在pom文件中已经导入了spring-boot-starter-web启动器,所以容器中一定存在这个组件,因此可以进行该类下的注册组件方法
@AutoConfigureOrder(-2147483648)
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({DispatcherServlet.class})
@AutoConfigureAfter({ServletWebServerFactoryAutoConfiguration.class})
public class DispatcherServletAutoConfiguration {
可以看到:底层已经创建了DispatcherServlet控制器对象,所以不再需要手动去配置
@Bean(
name = {"dispatcherServlet"}
)
public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
return dispatcherServlet;
}
3.5.3. 修改默认配置
@Bean
@ConditionalOnBean({MultipartResolver.class})
@ConditionalOnMissingBean(
name = {"multipartResolver"}
)
public MultipartResolver multipartResolver(MultipartResolver resolver) {
return resolver;
}
如果容器中有MultipartResolver这个类型组件,但是组件名不是multipartResolver,给Bean注解传入对象参数,这个参数的值就会从容器中寻找。防止自定义的文件上传解析器的name不是底层所规范的,底层也会将这个文件解析器对象进行返回,由于在Bean注解中没有指定name,则默认返回的组件名即为方法名multipart
由于底层使用的是ConditionalOnMissingBean注解,如果用户没有配置该组件则Spring Boot会默认配置好该组件;反之用户配置了该组件则以用户配置优先
总结:
SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration, 共127个在每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值即从xxxxProperties里面拿,xxxProperties和总配置文件application.properties进行了绑定生效的配置类就会给容器中装配很多组件,只要容器中有这些组件,相当于这些功能就有了;如果用户自己配置了某些组件则以用户配置的优先定制化配置:1.用户直接使用@Bean来替换底层的组件名;2.用户可以查看组件获取的配置文件是什么值即可修改
xxxxAutoConfiguration --> 组件 --> xxxxProperties 里面获取需要修改的key --> application.properties设置对应的属性值
3.5.4. 实践引入需要的场景依赖查看自动配置了哪些类和组件是否需要修改:判断引入场景的自动配置都生效了哪些;在application.properties中开启debug调试参照文档修改配置项:xxxxProperties中绑定了配置文件中的哪些属性,如修改spring boot开启的banner涂
spring.banner.image.location=classpath:1.jpg
自定义加入或者替换组件:@Bean、@Component;自定义器xxxxCustomizer 3.5.5. Spring boot开发技巧
Lombok: 简化javaBean(实体类)的开发
导入lombok的依赖
org.projectlombok lombok
在File -> settings -> plugins下载lombok插件
在实体类上使用注解:
@Data表示该类的getter和setter方法;
@ToString表示该类的toString方法;
@AllArgsConstructor 表示生成该类的全参构造器;
@NoAllArgsConstructor 表示生成该类的 无参构造器;
@Slf4j简化日志开发
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Double price;
}
@RestController
@Slf4j
public class HelloController {
@RequestMapping("/hello")
public String Hello(@RequestParam("username") String username){
log.info("使用lombok的Slf4j注解直接进行日志信息的编写...");
return "Hello, Spring Boot2 你好:" + username;
}
}
dev-tools: 项目或者页面修改以后:Ctrl+F9即可重新加载(Restart)
org.springframework.boot spring-boot-devtools true
Spring Initializer: 项目初始化向导
在new -> Project中选择Spring initializr;选择需要的开发场景,如下:
生成的pom文件中自动导入需要的依赖并且自动创建项目结构:
自动编写好主程序类:



