SpringBoot2核心技术 — 基础入门
1、Spring与SpringBoot
1.1、Spring能做什么
1.1.1、Spring的能力
1.1.2、Spring的生态
https://spring.io/projects/spring-boot
web开发
数据访问
安全控制
分布式
消息服务
移动开发
批处理
1.1.3、Spring5重大升级
① 响应式编程
② 内部源码设计
基于Java8的一些新特性,如:接口默认实现。重新设计源码架构。
1.2、为什么使用SpringBoot
能快速创建出生产级别的Spring应用
1.2.1、SpringBoot的优点
创建独立Spring应用
内嵌web服务器
自动starter依赖,简化构建配置
自动装配Spring以及第三方功能
提供生产级别的监控、健康检查及外部化配置
无代码生产,无需编写XML
SpringBoot是整合Spring技术栈的一站式框架
SpringBoot是简化Spring技术栈的快速开发脚手架
1.2.2、SpringBoot缺点
迭代快,需要时刻关注变化
封装太深,内部原理复杂,不容易精通
1.3、时代背景
1.3.1、微服务
微服务是一种架构风格
一个应用拆分为一组小型服务
每个服务运行在自己的进程内,也就是可以独立部署和升级
服务之间使用轻量级HTTP交互
服务围绕业务功能拆分
可以由全自动部署机制独立部署
去中心化,服务自治。服务可以使用不同的语言、不同的存储技术
1.3.2、分布式
分布式的困难
远程调用
服务发现
负载均衡
服务容错
配置管理
服务监控
链路追踪
日志管理
任务调度
……
分布式的解决
SpringBoot + SpringCloud
1.3.3、云原生
原生应用如何上云。Cloud Native
上云的困难
服务自愈
弹性伸缩
服务隔离
自动化部署
灰度发布
流量治理
……
上云的解决
1.4、如何学习SpringBoot
官方文档
查看新版本特性
2、SpringBoot2入门
2.1、系统要求
Java 8 +
Maven 3.5 +
IDEA 2019.1.2
2.2、HelloWorld
2.2.1、创建Maven工程
2.2.2、引入依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.4</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
2.2.3、创建主程序
@SpringBootApplication public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }
2.2.4、编写业务
@RestController public class HelloController { @RequestMapping("/hello") public String handle01(){ return "Hello, SpringBoot!"; } }
2.2.5、测试
直接运行main方法
2.2.6、简化配置
application.properties
server.port=8888
2.2.7、简化部署
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
项目打包成 jar 包,直接在目标服务器执行即可。
3、了解自动配置原理
3.1、SpringBoot特点
3.1.1、依赖管理
依赖管理 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.4</version> </parent> 他的父项目 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.7.4</version> </parent> 几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制
开发导入starter场景启动器
见到很多 spring-boot-starter-* : *就某种场景
只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
SpringBoot所有支持的场景
见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
所有场景启动器最底层的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.7.4</version> <scope>compile</scope> </dependency>
无需关注版本号,自动版本号仲裁
引入依赖默认都可以不写版本
引入非版本仲裁的jar,要写版本号
可以修改默认版本号
查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
在当前 项目里面重写配置
<properties> <mysql.version>5.1.43</mysql.version> </properties>
3.1.2、自动配置
自动配置Tomcat
引入Tomcat依赖
配置Tomcat
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <version>2.7.4</version> <scope>compile</scope> </dependency>
自动配置好SpringMVC
引入SpringMVC全套组件
自动配置好SpringMVC常用组件
自动配置好Web常见功能,如:字符编码问题
SpringBoot帮助我们配置好了所有Web开发常见场景
默认的包结构
主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
无需以前的包扫描配置
想要改变扫描路径
@SpringBootApplication(scanBasePackages=“com.jignchao”)
或者 @ComponentScan指定扫描路径
@SpringBootApplication 等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(“com.jingchao.boot”)
各种配置拥有默认值
默认配置最终都是映射到每个类上,如MultipartProperties
配置文件的值最终会绑定到每个类上,这个类会在容器中创建对象
按需加载所有自动配置项
非常多的starter
引入了那些场景这个场景的自动配置才会开启
SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
……
3.2、容器功能
3.2.1、组件添加
① @Configuration
基本使用
Full模式与Lite模式
示例
最佳实战
配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
配置类里面使用@Bean标注在方法上面给容器注册组件,默认也是单实例的
配置类本身也是组件
proxyBeanMethods:代理bean的方法
Full(proxyBeanMethods = true)每个@Bean方法调用多少次返回的组件都是单实例的
Lite(proxyBeanMethods = false)每个@Bean方法被调用多少次返回的组件都是新创建的
注意:组件依赖必须使用Full模式(默认),其他情况Lite模式
@Configuration(proxyBeanMethods = false) public class MyConfig { @Bean public User user01(){ User zhangsan = new User("zhangsan", 18); // user 组件依赖 Pet 组件 zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean("tom") public Pet tomcatPet(){ return new Pet("tomcat"); } }
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.jingchao.boot") public class MainApplication { public static void main(String[] args) { // 返回我们的IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } // 从容器中获取组件 Pet tom01 = run.getBean("tom", Pet.class); Pet tom02 = run.getBean("tom", Pet.class); System.out.println(tom01 == tom02); // MyConfig bean = run.getBean(MyConfig.class); System.out.println(bean); User user01 = bean.user01(); User user02 = bean.user01(); System.out.println(user02 == user01); User user011 = run.getBean("user01", User.class); Pet tom = run.getBean("tom", Pet.class); System.out.println(user011.getPet() == tom); } }
② @Bean、@Component、@Controller、@Service、@Repository
③ @ComponentScan、@Import
@Import 给容器中自动创建组件,默认组件名字是全类名
@Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false) public class MyConfig(){ }
④ @Conditional
条件装配:满足Conditional指定的条件,则进行组件注入
eg:@ConditionalOnBean
@Configuration(proxyBeanMethods = false) public class MyConfig { @ConditionalOnBean(name = "tom") @Bean public User user01(){ User zhangsan = new User("zhangsan", 18); // user 组件依赖 Pet 组件 zhangsan.setPet(tomcatPet()); return zhangsan; } // @Bean("tom") public Pet tomcatPet(){ return new Pet("tomcat"); } }
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.jingchao.boot") public class MainApplication { public static void main(String[] args) { // 返回我们的IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } boolean tom = run.containsBean("tom"); System.out.println("tom = " + tom); // false boolean user01 = run.containsBean("user01"); System.out.println("user01 = " + user01); // false } }
3.2.2、原生配置文件引入
① @ImportResource
<?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 id="j" class="com.jingchao.boot.bean.User"> <property name="name" value="zhangsan"/> <property name="age" value="18"/> </bean> <bean id="c" class="com.jingchao.boot.bean.Pet"> <property name="name" value="tomcat"/> </bean> </beans>
直接将 xml 中的组件迁移成注解的方式
@ImportResource("classpath:bean.xml") public class MyConfig{}
boolean j = run.containsBean("j"); System.out.println(j); //true boolean c = run.containsBean("c"); System.out.println(c); //true
3.2.3、配置绑定
使用 Java 读取到properties文件中的内容,并且把它封装到 JavaBean中哦,以供随时使用
public class getProperties { public static void main(String[] args) throws FileNotFoundException, IOException { Properties pps = new Properties(); pps.load(new FileInputStream("a.properties")); Enumeration enum1 = pps.propertyNames();//得到配置文件的名字 while(enum1.hasMoreElements()) { String strKey = (String) enum1.nextElement(); String strValue = pps.getProperty(strKey); System.out.println(strKey + "=" + strValue); //封装到JavaBean } } }
① @ConfigurationProperties
② @EnableConfigurationProperties + @ConfigurationProperties
@EnableConfigurationProperties(Car.class) //1、开启Car配置绑定功能 //2、把这个Car这个组件自动注册到容器中 public class MyConfig { }
@ConfigurationProperties(prefix = "mycar") public class Car { ...... }
③ @Component + @ConfigurationProperties
@Component @ConfigurationProperties(prefix = "mycar") public class Car { private String brand; private Integer price; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } @Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", price=" + price + '}'; } }
3.3、自动配置原理入门
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { }
3.3.1、引导加载自动配置类
① @SpringBootConfiguration
@Configuration:代表当前是一个配置类
② @ComponentScan
指定扫描那些组件
③ @EnableConfiguration
@AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { }
@AutoConfigurationPackage
自动配置包:指定默认的包规则
@Import({AutoConfigurationPackages.Registrar.class}) public @interface AutoConfigurationPackage { } /** * 利用Registrar给容器中导入一系列组件 * 将MainApplication所在包下的所有组件导入进来, */
@Import({AutoConfigurationImportSelector.class})
利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
调用List configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
利用工厂加载 Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
从META-INF/spring.factories位置来加载一个文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
3.3.2、按需开启自动配置项
虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置。
3.3.3、修改默认配置
@Bean @ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件 @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件 public MultipartResolver multipartResolver(MultipartResolver resolver) { // 给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。 // SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范 // Detect if the user has created a MultipartResolver but named it incorrectly return resolver; } // 给容器中加入了文件上传解析器;
SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先
@Bean @ConditionalOnMissingBean public CharacterEncodingFilter characterEncodingFilter() { }
总结:
SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
生效的配置类就会给容器中装配很多组件
只要容器中有这些组件,相当于这些功能就有了
定制化配置
用户直接自己@Bean替换底层的组件
用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration --> 组件 --> xxxxProperties里面拿值 --> application.properties
3.3.4、最佳实战
引入场景依赖
查看自动配置了哪些(选做)
自己分析,引入场景对应的自动配置一般都生效了
配置文件中 debug=true 开启自动配置报告。Negative(不生效)\Positive(生效)
是否需要修改
参照文档修改配置项
自己分析。xxxxProperties绑定了配置文件的哪些。
自定义加入或者替换组件
@Bean、@Component、……
自定义器 XXXXXCustomizer;
…
4、开发小技巧
4.1、Lombok
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
简化JavaBean开发
4.2、dev-tools
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
项目或者页面修改以后:Ctrl+F9