SpringBoot基础
概述
SpringBoot是Spring提供的一个子项目,用于快速构建Spring应用程序。
SpringBoot特性
1.起步依赖
本质上就是一个Maven坐标,整合了完成一个功能需要的所有坐标。就是通过一个依赖,可以代替所有所需的依赖。
2.自动配置
遵循约定大于配置的原则,在boot程序启动后,一些bean对象会自动注入到ioc容器,不需要手动声明,简化开发。
3.其他特性
内嵌Tomcat、Jetty
外部化配置
不需要XML配置(properties/yml)
SpringBoot入门
案例需求:
使用SpringBoot开发一个web应用,浏览器发起请求/hello后,给浏览器返回字符串"hello world ~"
过程
-
创建Maven工程
-
导入spring-boot-stater-web起步依赖
-
编写Controller
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
System.out.println("Hello World ~");
return "Hello World ~";
}
}
-
提供启动类
手动创建SpringBoot工程
-
创建Maven工程
-
引入依赖
-
提供启动类
配置文件
properties配置文件 (application.properties)
springboot的所有配置文件的位置:https://docs.spring.io/spring-boot/appendix/application-properties/index.html
properties配置文件中内容的格式
spring.application.name=demo1
server.port=9090
server.servlet.context-path=/start1
yml配置文件(application.yml)
yml使用方式:
书写三方技术配置信息,书写自定义配置信息
yml的配置信息书写:
值前面必须有空格,作为分隔符
使用空格作为缩进表示层级关系,相同的层级左侧对齐
#发件人的相关信息
email:
user: "231@qq.com"
code: "afdas"
host: faff.com
auth: true
yml的配置信息获取:
使用@Value("${键名}")
public class EmailPerperties{
@Value("${email.user}")
public String user;
}
使用@ConfigrationPropperties(prefix="前缀"),但要保证实体类的成员变量名与配置文件中的键名保持一致。
整合MyBatis
导入MyBatis的起步依赖和mysql的依赖
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
编写application.yml配置信息
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis?useSSL=false&serverTimezone=UTC
username: root
password: 123456
业务代码的实现
Bean对象管理
1.Bean扫描
SpringBoot默认扫描启动类所在的包及其子包;
其他的Bean,可以用@ComponentScan(basePackages="org.example")即可将该包下及其子包所需的Bean注册到ioc容器中
2.Bean注册
相关注解
@Component 声明bean的基础注解
@Controller @Component的衍生注解,标注在控制器类上
@Serivce @Component的衍生注解,标注在业务类上
@Repository @Component的衍生注解,标注在数据访问类上 (由于与mybatis整合,用的少)
关于三方jar包中的类对应的Bean,使用@Bean和Import
@Bean
在启动类或者配置类(@Configuration)中创建一个方法,在该方法里创建一个对象。在该方法上注解一个@Bean就可以了。
如果方法内部需要使用到ioc容器中已经存在的bean对象,那么只需要在方法上声明即可,spring会自动的注入。
@Import
一般导入配置类或导入ImportSelector接口实现类
可以通过一个配置类,在配置类中创建方法,在方法内部创建多个类的多个Bean。之后在启动类上加一个@Import(配置类的class)
@Import(CommonConfig.class)
可以通过ImportSelector接口实现类,在重写的方法中加入多个配置类的全限定名,之后在启动类上加一个@Import(该类的class),之后就能导入配置类,导入配置类中的多个Bean。
@Import(CommonImportSelector.class)
public class CommonImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> imports = new ArrayList<>();
InputStream res = CommonImportSelector.class.getClassLoader().getResourceAsStream("common.imports");
/*````````*/
BufferedReader br = new BufferedReader(new InputStreamReader(res));
String line=null;
try {
while((line=br.readLine())!=null){
imports.add(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/*````````*/
return imports.toArray(new String[0]);
}
}
可以自定义注解,封装@Import注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(CommonImportSelector.class)
public @interface EnableCommonConfig {
}
3.注册条件
关于Bean注册后所有属性字段为null问题,不能写死的话,可以通过配置信息获取,在application.yml中配置。
@Configuration
public class CommonConfig {
@Bean
public Country country(@Value("${country.name}") String name, @Value("${country.system}") String system){
Country country = new Country();
country.setName(name);
country.setSystem(system);
return country;
}
}
问题:
如果application.yml中配置所需信息就注入,没有就不注入,但是不能报错。
SpringBoot提供了设置注册生效条件的注解@Conditional,但是使用起来复杂,所以使用它的衍生注解
@ConditionalOnProperty
配置文件中存在对应的属性,才注入该bean;不存在就不注入
@Configuration
public class CommonConfig {
@ConditionalOnProperty(prefix = "country",name = {"name","system"})
@Bean
public Country country(@Value("${country.name}") String name, @Value("${country.system}") String system){
Country country = new Country();
country.setName(name);
country.setSystem(system);
return country;
}
@Bean
public Province province(){
return new Province();
}
}
@ConditionalOnMissingGBean
当不存在当前类型的bean时,才注入该bean;如果不存在Country,就注入Province。
@ConditionalOnMissingBean(Country.class)
@Bean
public Province province(){
return new Province();
}
@ConditionalOnClass
当前环境存在指定的这个类时,才注入该bean
@ConditionalOnClass(name="org.springframework.web.servlet.DispatcherServlet")
@Bean
public Province province(){
return new Province();
}
自动配置
自动配置:
遵循约定大于配置的原则,在boot程序启动后,起步依赖中的一些bean对象会自动注入到ioc容器。
SpringBoot自动配置,提供一个自动配置类,把该类类名写到指定的配置文件中。
第三方jar包中的Bean自动配置
当Spring Boot应用程序启动时,Spring Boot会扫描并加载所有在.import文件中配置的自动配置类,而配置类被自动配置类用@Import导入,这样该配置类中的所有Bean对象根据条件都会被注入ioc容器中。
通过这种方式,Spring Boot在启动时会自动配置自动配置类,并通过@Import注解被动地导入配置类,从而将配置类中的Bean对象注入到Spring容器中。这种机制使得配置更加模块化和灵活,便于管理和复用。
-
有配置类CommonConfig,用来配置Bean对象
public class CommonConfig {
public CommonConfig() {
}
@ConditionalOnProperty(
prefix = "country",
name = {"name", "system"}
)
@Bean
public Country country(@Value("${country.name}") String name, @Value("${country.system}") String system) {
return new Country(name, system);
}
@Bean
public Province province() {
return new Province();
}
}
-
有自动配置类,带2个注解@AutoConguration用来标识该类是自动配置的,
@Import(CommonConfig.class)导入配置类
@AutoConfiguration
@Import({CommonConfig.class})
public class CommonAutoConfig {
public CommonAutoConfig() {
}
}
-
有.import配置文件,在该文件中写入自动配置类的全限定名。
cn.itcast.config.CommonAutoConfig
SpringBoot自动配置原理
-
在主启动类上添加了SpringBootApplication注解,这个注解组合了EableAutoConfiguration注解。
-
EnableAutoConfiguration注解又组合了AutoConfigurationImportSelector类
-
实现selectImports方法,这个方法经过层层调用,最终会读取META-INF目录下的后缀名为.import文件(boot2.7以前版本读取的是spring.factories文件)
-
读取到全类名了之后,就会解析注册条件,也就是@Conditional及其衍生注解把满足注册条件的Bean对象自动注册到ioc容器中。
自定义stater
在实际开发中,经常会定义一些组件,提供给各个项目团队使用。而在Spring Boot的项目中,一般会将这些公共组件封装为SpringBoot的starter。
起步依赖会由两个工程组成
xxx-autoconfigure:提供自动配置功能
xxx-starter:提供依赖管理功能
需求:自定义mybatis的starter
步骤:
1.创建 dmybatis-spring-boot-autoconfigure模块,提供自动配置功能,并自定义配置文件 META-INF/spring/xxx.imports
引入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>3.3.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.14</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
自动配置类Configure
@AutoConfiguration //表示当前类是一个自动配置类
public class MyBatisAutoConfig {
//SqlSessionFactoryBean
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
//MapperScannerConfigurer
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(BeanFactory beanFactory) {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
//扫描的包:启动类所在的包及其子包
List<String> packages = AutoConfigurationPackages.get(beanFactory);
String p = packages.get(0);
mapperScannerConfigurer.setBasePackage(p);
//扫描的注解:
mapperScannerConfigurer.setAnnotationClass(Mapper.class);
return mapperScannerConfigurer;
}
}
创建org.springframework.boot.autoconfigure.AutoConfiguration.imports文件
创建.imports文件导入自动配置类的全类名,文件所在位置META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
,不能变!!!
2.从创建dmybatis-spring-boot-starter 模块,在starter中引入自动配置模块
引入我们创建的autoconfigure
最好在引入dmybatis-spring-boot-autoconfigure所需的依赖
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>dmybatis-spring-boot-autoconfigure</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>3.3.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.14</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
取代mybatis-spring-boot-starter成功!!!
<!-- <dependency>-->
<!-- <groupId>org.mybatis.spring.boot</groupId>-->
<!-- <artifactId>mybatis-spring-boot-starter</artifactId>-->
<!-- <version>3.0.3</version>-->
<!-- </dependency>-->
<!-- 自定义的mybatis起步依赖 -->
<dependency>
<groupId>org.example</groupId>
<artifactId>dmybatis-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
注:
如果编译不成功,你的Maven工程可能默认是JDK5,太低不支持了,需要将所配置的dmybatis-spring-boot-autoconfigure和dmybatis-spring-boot-starter,这两个Maven项目中的pom文件中导入编译插件。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>