参考:https://www.yuque.com/leifengyang/springboot2
参考:https://www.bilibili.com/video/BV19K4y1L7MT?p=1&vd_source=0c3c1f43c75954a15fba4e42c1d7883e
项目结构
1. pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>springboot-test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>springboot-01-hello</module>
</modules>
<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>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. MainApplication
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 主程序类
* @SpringBootApplication:这是一个springboot应用
*/
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
3. HelloController
package com.example.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String home() {
return "Hello world";
}
}
4. 启动服务,浏览器访问
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
点进spring-boot-starter-parent看到:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
点进spring-boot-dependencies看到:
几乎声明了所有开发中常用的依赖的版本号
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
SpringBoot帮我们配置好了所有web开发的常见场景
@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example")
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example")
等价于@SpringBootApplication(scanBasePackages="com.example")
默认扫描主程序所在的包
*/
@SpringBootApplication
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);
}
}
}
package com.example.bean;
public class User {
private String name;
private int age;
private Pet pet;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", pet=" + pet +
'}';
}
}
package com.example.bean;
public class Pet {
private String name;
public Pet() {
}
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
}
package com.example.config;
import com.example.bean.Pet;
import com.example.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods=true) // 告诉springboot这是一个配置类
public class MainConfig {
@Bean
public User userBean(){
User u = new User("zhangsan", 18);
u.setPet(petBean());
return u;
}
@Bean
public Pet petBean(){
Pet p = new Pet("cat");
return p;
}
}
package com.example;
import com.example.bean.Pet;
import com.example.bean.User;
import com.example.config.MainConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example")
等价于@SpringBootApplication(scanBasePackages="com.example")
默认扫描主程序所在的包
*/
@SpringBootApplication
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. 从容器中获取组件
User user = (User) run.getBean("userBean");
User user2 = (User) run.getBean("userBean");
System.out.println("组件默认是单例的:" + (user==user2));
// 4. 配置类也是组件
MainConfig bean = run.getBean(MainConfig.class);
System.out.println("配置类本身也是组件:" + bean);
// 5. proxyBeanMethods = true, mainConfig就是被增强的代理对象
// springboot总会检查组件是否在容器中存在
// 保持组件单实例
// 外部无论对配置类中的这个组件注册方法调用多少次,获取的都是之前注册容器中的单实例对象
User user3 = bean.userBean();
User user4 = bean.userBean();
System.out.println("主配置是否为代理对象: "+(user3==user4));
// full: proxyBeanMethods=true => 应用场景: 解决组件依赖
// lite: proxyBeanMethods=false => 配置类在容器中不会保存代理对象,在外边调用方法,每次都会产生一个新对象
// Full: 保证每个@Bean方法被调用多少次返回的组件都是单实例的。类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
// Lite: 每个@Bean方法被调用多少次返回的组件都是新创建的。类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
// 组件依赖必须使用Full模式默认。其他默认是否Lite模式
Pet pet = (Pet) run.getBean("petBean");
System.out.println("proxyBeanMethods组件依赖" + (user.getPet()==pet));
}
}
package com.example.config;
import com.example.bean.Pet;
import com.example.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MainConfig {
}
package com.example.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component("userBean")
public class User {
private String name;
private int age;
@Autowired
private Pet pet;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", pet=" + pet +
'}';
}
}
package com.example.bean;
import org.springframework.stereotype.Component;
@Component("petBean")
public class Pet {
private String name;
public Pet() {
}
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
}
package com.example;
import com.example.bean.Pet;
import com.example.bean.User;
import com.example.config.MainConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
* @SpringBootConfiguration
* @EnableAutoConfiguration
* @ComponentScan("com.example") 等价于@SpringBootApplication(scanBasePackages="com.example")
* 默认扫描主程序所在的包
*/
@SpringBootApplication
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. 从容器中获取组件
User user = (User) run.getBean("userBean");
User user2 = (User) run.getBean("userBean");
System.out.println("组件默认是单例的:" + (user == user2));
// 4. 配置类也是组件
MainConfig bean = run.getBean(MainConfig.class);
System.out.println("配置类本身也是组件:" + bean);
// 5. 组件依赖
Pet pet = (Pet) run.getBean("petBean");
System.out.println("组件依赖" + (user.getPet() == pet));
}
}
@Import:给容器中自动创建出指定类型的组件、默认组件的名字就是全类名
@Conditional:条件装配,满足Conditional指定的条件,则进行组件注入
@ImportResource:原生配置文件引入
@ConfigurationProperties:配置文件中的配置项绑定给组件的属性
package com.example;
import ch.qos.logback.core.db.DBHelper;
import com.example.bean.Pet;
import com.example.bean.User;
import com.example.config.MainConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import java.util.Arrays;
/**
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example")
等价于@SpringBootApplication(scanBasePackages="com.example")
默认扫描主程序所在的包
*/
/**
* @Import:给容器中自动创建出指定类型的组件、默认组件的名字就是全类名
* @Conditional:条件装配,满足Conditional指定的条件,则进行组件注入
* @ImportResource:原生配置文件引入
* @ConfigurationProperties:配置文件中的配置项绑定给组件的属性
*/
@SpringBootApplication
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. 获取组件
Boolean flag = run.containsBean("petBean");
System.out.println("容器中是否存在petBean组件:" + flag);
Boolean flag2 = run.containsBean("userBean");
System.out.println("容器中是否存在userBean组件:" + flag2);
// 4. 容器中组件数量
System.out.println("组件数量:" + run.getBeanDefinitionCount()); // 167
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="petBeanXml" class="com.example.bean.Pet">
<property name="name" value="cat"></property>
</bean>
<bean id="userBeanXml" class="com.example.bean.User">
<property name="pet" ref="petBeanXml"></property>
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
</beans>
package com.example.bean;
public class User {
private String name;
private int age;
private Pet pet;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", pet=" + pet +
'}';
}
}
package com.example.bean;
public class Pet {
private String name;
public Pet() {
}
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
}
package com.example.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
// @Component
// MainConfig中使用了@EnableConfigurationProperties(Car.class),则不用@Component
@ConfigurationProperties(prefix = "car")
public class Car {
private String brand;
private double price;
public Car() {
}
public Car(String brand, double price) {
this.brand = brand;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
package com.example.config;
import ch.qos.logback.core.db.DBHelper;
import com.example.bean.Car;
import com.example.bean.Pet;
import com.example.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.*;
// @ConditionalOnBean(name="petBean") // 有petBean类里的组件注册才生效,否则都不生效
@EnableConfigurationProperties(Car.class)
// @EnableConfigurationProperties(Car.class)的作用:
// 1. 开启Car配置绑定功能
// 2. 把这个Car这个组件自动注册到容器中
@ImportResource("classpath:mainApplication.xml")
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods=true) // 告诉springboot这是一个配置类
public class MainConfig {
@ConditionalOnBean(name="petBean") // 容器中存在petBean才执行userBean的组件注册
@Bean
public User userBean(){
User u = new User("zhangsan", 18);
u.setPet(petBean());
return u;
}
// @Bean
public Pet petBean(){
Pet p = new Pet("cat");
return p;
}
}
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
// SpringBootConfiguration用来注解 配置类 => MainApplication是一个配置类(核心配置类)
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}
@Import({AutoConfigurationPackages.Registrar.class})
// 给容器中导入一个组件
// 指定了默认的包规则
public @interface AutoConfigurationPackage {}
// 利用Registrar给容器中导入一系列组件
// 将指定的MainApplication所在包下的所有组件导入进来
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
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
1. 虽然我们127个场景的所有自动配置启动的时候默认全部加载。
META-INF/spring.factories文件中:xxxxAutoConfiguration
2. 按照条件装配规则(@Conditional),最终会按需配置。
eg. @ConditionalOnClass({Gson.class})
@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() {}
总结:
xxxxxAutoConfiguration ---> 组件 ---> xxxxProperties里面拿值 ----> application.properties
spring.banner.image.location=classpath:timg.jpg
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
@ToString // toString
@Data // getter、setter
@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
@Slf4j // 日志
package com.example.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@ToString // toString
@Data // getter、setter
@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
public class LombokBean {
private String str;
private int i;
}
import com.example.bean.LombokBean;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
@Slf4j
public class LombokBeanTest {
@Test
public void testLombokBean(){
LombokBean o = new LombokBean();
o.setStr("abc");
o.setI(10);
System.out.println(o);
log.info(o.toString());
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
server.port=9999
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=redis
spring.redis.database=0
k: v
行内写法: k: {k1:v1,k2:v2,k3:v3}
#或
k:
k1: v1
k2: v2
k3: v3
行内写法: k: [v1,v2,v3]
#或者
k:
- v1
- v2
- v3
<!-- 配置提示 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
package com.example;
import com.example.bean.Person;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
* yaml
*/
@SpringBootApplication
@EnableConfigurationProperties(Person.class)
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
package com.example.bean;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Set;
import java.util.Date;
import java.util.Map;
@Data
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List<String> animal;
private Map<String, Object> score;
private Set<Double> salarys;
private Map<String, List<Pet>> allPets;
}
package com.example.bean;
import lombok.Data;
@Data
public class Pet {
private String name;
private Double weight;
}
package com.example.controller;
import com.example.bean.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PersonController {
@Autowired
Person person;
@RequestMapping("person")
public String getPerson(){
return person.toString();
}
}
server.port=9991
server:
port: 9999
# yaml表示以上对象
person:
userName: zhangsan
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
interests: [篮球,游泳]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148] # { 0 = 131, 1 = 140, 2 = 148 }
chinese: {first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom,weight: 10.1}
- {name: jerry,weight: 47.0}
health: [{name: mario,weight: 47.1}]
/static
(or /public
or /resources
or /META-INF/resources
spring:
mvc:
static-path-pattern: /res/**
spring:
resources:
static-locations: [classpath:/haha/]
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
spring:
# mvc:
# static-path-pattern: /res/** 这个会导致welcome page功能失效
resources:
static-locations: [classpath:/haha/]
spring:
# mvc:
# static-path-pattern: /res/** 这个会导致 Favicon 功能失效
重启服务,浏览器
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。