一、SpringBoot2 入门
HelloWorld
需求:浏览发送/hello请求,响应 Hello,Spring Boot 2
1.1、创建maven工程
1.2、引入依赖
引入两个依赖之后,所有的包都在了,不用担心导包问题
//导入父工程
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
1.3、创建主程序
/**
* 主程序类
* @SpringBootApplication:这是一个SpringBoot应用
*/
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class,args);
}
}
1.4、编写业务
package com.zhijia.boot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**业务
*/
//@ResponseBody //json
//@Controller
@RestController // @ResponseBody + @Controller
public class HelloController {
@RequestMapping("/hello")
public String handle01(){
return "Hello, Spring Boot 2!";
}
}
1.5、测试
直接运行main方法
1.6、简化配置
resources—new—file—application.properties
官网上的配置列表 Common Application Properties
1.7、简化部署
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
把项目打成jar包,直接在目标服务器执行即可。
注意点:取消掉cmd的快速编辑模式
第一步:导入插件
第二步:打个包
第三步:有我们的jar包了
第四步:target 右键 Open in Explorer
第五步:进入target,进入cmd,执行dir
第六步:把项目停了
第七步:执行 java -jar boot-01-helloworld-1.0-SNAPSHOT.jar
第八步:在页面打开
二、了解自动配置原理
2.1、依赖管理
1)父项目(继承依赖,声明了各种jar包依赖版本号)
几乎声明了所有开发中常用的依赖的版本号
<!--父工程-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
2)自定义依赖版本号(pom.xml)
1、查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
2、在当前项目里面重写配置
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>
3)Starters场景启动器
1、见到很多 spring-boot-starter-* : *就某种场景
2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
使用工具的分析依赖树 :Diagrams–>Show Dependencies…
2.2、自动配置
(1) 自动配好Tomcat(依赖/配置)
- 引入Tomcat依赖。
- 配置Tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
(2) 自动配好SpringMVC
- 引入SpringMVC全套组件
- 自动配好SpringMVC常用组件(功能)
(3) 自动配好Web常见功能,如字符编码问题
- SpringBoot帮我们配置好了所有web开发的常见场景
解决乱码问题:运用字符编码拦截器组件characterEncodingFilter
(4) 默认包结构
- 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
- 无需以前的包扫描配置
- 想要改变扫描路径
- @SpringBootApplication(scanBasePackages=“com.atguigu”)
- 或者@ComponentScan 指定扫描路径
@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.zhijia.boot")
(5) 各种配置都有默认值
- 默认配置最终都是映射到某个类上,如:MultipartProperties
- 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
(6) 按需加载所有自动配置项
- 非常多的starter
- 引入了哪些场景这个场景的自动配置才会开启
- 【自动配置,按需加载】SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面,有很多但是不一定全部都生效(提前配置好了,开发者不导入依赖就会爆红不生效,引入依赖后就不爆红且生效了)
三、容器功能
3.1、组件添加
写两个组件:用户和宠物
如果用以前原生的spring添加组件到容器中需要以下操作:
创建一个spring的配置文件beans.xml,然后使用bean标签进行创建,容器中会有user01、cat两个组件
(1)@Configuration
- 配置类(=配置文件)里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
- 配置类本身也是组件
- @
Configuration(proxyBeanMethods = true)
:代理bean的方法
Full(proxyBeanMethods = true)
:【保证每个@Bean方法被调用多少次返回的组件都是单实例的】外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象Lite(proxyBeanMethods = false)
:【每个@Bean方法被调用多少次返回的组件都是新创建的】
配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
@Bean (组件id):给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
//Configuration使用示例
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
@Bean
public User user01(){
User zhangsan = new User("zhangsan", 18);
//user组件依赖了Pet组件
zhangsan.setPet(tomPet());
return zhangsan;
}
@Bean("tom")
public Pet tomPet(){
return new Pet("tom");
}
}
@Configuration测试代码如下
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")
public class MainApplication {
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);
}
//3、从容器中获取组件
Pet tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
System.out.println("组件:"+(tom01 == tom02));
//4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
//如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
//保持组件单实例
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1);
User user01 = run.getBean("user01", User.class);
Pet tom = run.getBean("tom", Pet.class);
System.out.println("用户的宠物:"+(user01.getPet() == tom));
}
}
(2)@Bean、@Component、@Controller、@Service、@Repository
(3)@ComponentScan、@Import
@import 用于: 配置类里或者组件里
作用:给容器中自动创建出该类型的组件、默认组件的名字就是全类名
====================MyConfig.java==================
//作用:调用两个组件的无参构造器,给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
}
====================MainApplication.java==================
@SpringBootApplication(scanBasePackages="com.atguigu")
public class MainApplication {
public static void main(String[] args) {
//5、获取组件
String[] beanNamesForType = run.getBeanNamesForType(User.class);
for (String s : beanNamesForType){
System.out.println(s);
}
String[] bean1 = run.getBeanNamesForType(DBHelper.class);
System.out.println(bean1);
}
}
(4)@Conditional
条件装配:满足 Conditional 指定的条件,则进行组件注入
他也是一个根注解,里面派生了很多注解
=====================测试条件装配==========================
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
//@ConditionalOnBean(name = "tom")
@ConditionalOnMissingBean(name = "tom")
public class MyConfig {
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.2、原生文件引入
(1)@ImportResource
beans.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="haha" class="com.atguigu.boot.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="hehe" class="com.atguigu.boot.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
@ImportResource("classpath:beans.xml")
public class MyConfig {}
======================测试=================
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha:"+haha);//true
System.out.println("hehe:"+hehe);//true
3.3、配置绑定(从properties中读)
如何使用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。
}
}
}
(1)@Component + @ConfigurationProperties
- 只有在容器中的组件,才会拥有SpringBoot提供的强大功能
@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 +
'}';
}
}
(2)@EnableConfigurationProperties + @ConfigurationProperties
在配置类里写
@EnableConfigurationProperties(Car.class)
//1、开启Car配置绑定功能
//2、把这个Car这个组件自动注册到容器中
public class MyConfig {
}
四、自动配置原理入门
4.1、引导加载自动配置类
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}
(1)@SpringBootConfiguration
@Configuration。代表当前是一个配置类
(2)@ComponentScan(包扫描)
指定扫描哪些,Spring注解;
(3)@EnableAutoConfiguration
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
-
@AutoConfigurationPackage
自动配置包,指定了默认的包规则- 利用Registrar给容器中导入一系列组件
- 将指定的一个包下的所有组件导入进来?MainApplication 所在包下。
@Import(AutoConfigurationPackages.Registrar.class) //给容器中导入一个组件 public @interface AutoConfigurationPackage {}
-
@Import(AutoConfigurationImportSelector.class)
1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件 2、调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类 3、利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件 4、从META-INF/spring.factories位置来加载一个文件。 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件 spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
4.2、按需开启自动配置项
虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置。
4.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() {
}
4.4、最佳实践
- 引入场景依赖
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter - 查看自动配置了哪些(选做)
- 自己分析,引入场景对应的自动配置一般都生效了
- 配置文件中debug=true开启自动配置报告。Negative(不生效)\Positive(生效)
- 是否需要修改
- 参照文档修改配置项
- 自定义加入或者替换组件
- @Bean、@Component
五、开发小技巧
5.1、Lombok
简化JavaBean开发(idea中搜索安装lombok插件)
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
简化JavaBean开发
//无参构造
@NoArgsConstructor
//有参构造
@AllArgsConstructor
//get/set方法
@Data//get/set方法
@ToString
@EqualsAndHashCode
public class User {
private String name;
private Integer age;
private Pet pet;
}
//简化日志开发
@Slf4j
@RestController
public class HelloController {
@RequestMapping("/hello")
public String handle01(@RequestParam("name") String name){
log.info("请求进来了....");
return "Hello, Spring Boot 2!"+"你好:"+name;
}
}
5.2、dev-tools
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
项目或者页面修改以后:Ctrl+F9;
5.3、Spring Initailizr(项目初始化向导)
(0)选择我们需要的开发场景
(1)自动依赖引入
(2)自动创建项目结构
(3)自动编写好主配置类