SpringBoot中的自動裝配原理詳解
前言
通過兩個簡單的案例:在Spring中集成MyBatis、在SpringBoot中集成MyBatis
找出兩者的差異,初探Spring發(fā)展到SpringBoot的部分演化過程
以MyBatis為例,簡單梳理自動配置過程
一、Spring整合MyBatis
1.1pom文件
pom.xml
<!-- Spring JDBC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> ? <!-- MyBatis核心包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.10</version> </dependency> ? <!-- MyBatis-Spring 整合包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency> ? <!-- Druid數(shù)據(jù)庫連接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.23</version> </dependency> ? <!-- MySQL數(shù)據(jù)庫驅(qū)動 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency>
1.2配置類
MyBatisConfig
package com.lazy.snail; ? import com.alibaba.druid.pool.DruidDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; ? import javax.sql.DataSource; ? /** * @ClassName MyBatisConfig * @Description TODO * @Author lazysnail * @Date 2024/11/5 16:20 * @Version 1.0 */ @Configuration @PropertySource("classpath:db.properties") @MapperScan("com.lazy.snail.mapper") public class MyBatisConfig { @Value("${jdbc.url}") private String url; ? @Value("${jdbc.username}") private String username; ? @Value("${jdbc.password}") private String password; ? @Value("${jdbc.driverClassName}") private String driverClassName; ? @Bean public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); // 基本配置 dataSource.setDriverClassName(driverClassName); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); ? // Druid 高級配置 ? return dataSource; } ? @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); return factoryBean.getObject(); } }
1.3數(shù)據(jù)源屬性配置文件
# db.properties jdbc.url=jdbc:mysql://*.*.*.*:3306/snail_db jdbc.username=username jdbc.password=password jdbc.driverClassName=com.mysql.cj.jdbc.Driver
1.4mapper
UserMapper
package com.lazy.snail.mapper; ? import com.lazy.snail.domain.User; import org.apache.ibatis.annotations.Insert; import org.springframework.stereotype.Repository; ? /** * @ClassName UserMapper * @Description TODO * @Author lazysnail * @Date 2024/11/5 16:27 * @Version 1.0 */ @Repository public interface UserMapper { @Insert("insert into user_info(user_id, name, email) values(#{userId}, #{name}, #{email})") void insert(User user); }
1.5測試類
SpringTest
package com.lazy.snail; ? import com.lazy.snail.domain.User; import com.lazy.snail.service.UserService; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; ? @Slf4j public class SpringTest { ? @Test void test() { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean(UserService.class); userService.createUser(new User(1, "lazysnail", "lazy_snail@aliyun.com")); } }
二、SpringBoot整合MyBatis
2.1pom文件
pom.xml
<!-- springboot集成mybatis 自動為mybatis創(chuàng)建和配置所需的bean,簡化mybatis的使用 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency> ? <!-- 數(shù)據(jù)庫連接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency> ? <!-- 數(shù)據(jù)庫驅(qū)動 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency>
2.2配置文件
application.yml
spring: datasource: druid: url: jdbc:mysql://*.*.*.*:3306/snail_db username: username password: password driver-class-name: com.mysql.cj.jdbc.Driver
2.3mapper
UserMapper
package com.lazy.snail.mapper; ? import com.lazy.snail.domain.User; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; ? /** * @ClassName UserMapper * @Description TODO * @Author lazysnail * @Date 2024/10/10 14:03 * @Version 1.0 */ @Mapper public interface UserMapper { @Insert("insert into user_info(user_id, name, email) values(#{userId}, #{name}, #{email})") void insert(User user); }
2.4測試類
ApplicationTests
package com.lazy.snail; import com.lazy.snail.domain.User; import com.lazy.snail.service.UserService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class ApplicationTests { @Autowired private UserService userService; @Test void contextLoads() { User user = new User(); user.setUserId(4); userService.createUser(user); } }
三、Spring與SpringBoot整合MyBatis區(qū)別
3.1pom文件差異
- Spring中單獨引入功能模塊的依賴,如mybatis、mybatis-spring
- SpringBoot中引入starter概念,需要整合mybatis,只需要引入mybatis-spring-boot-starter依賴
Starter POMs are a set of convenient dependency descriptors that you can include in your application. You get a one-stop-shop for all the Spring and related technology that you need, without having to hunt through sample code and copy paste loads of dependency descriptors. For example, if you want to get started using Spring and JPA for database access, just include the spring-boot-starter-data-jpa
dependency in your project, and you are good to go.
通過引入 Starter,無需手動查找和復制大量依賴,避免了我們?nèi)ヒ胍蕾囁鶐淼穆闊?/p>
3.2配置類及配置文件差異
Spring中我們需要自定義MyBatis的配置類,專門管理DataSource、SqlSessionFactory、MapperScannerConfigurer這些組件
SpringBoot集成MyBatis時沒有任何的相關配置類(基礎版),因為SpringBoot提供了自動配置功能,MyBatis 的大部分配置可以通過 mybatis-spring-boot-starter
自動完成,只需要引入相關的依賴,并在 application.properties
或 application.yml
中進行一些簡單配置即可,Spring Boot 會自動創(chuàng)建并配置所需的 Bean(如 SqlSessionFactory
、MapperScannerConfigurer
等)。
四、SpringBoot怎么自動配置MyBatis
4.1MyBatis自動配置信息位置
4.2讀取自動配置信息
4.3解析bean定義信息
4.3.1解析Application中@Import
/** * 激活Spring應用上下問的自動配置功能,嘗試猜測和配置需要的bean。 * 自動配置類通?;陬惵窂胶投x的bean來應用。 * 例如: * 類路徑下有tomcat-embedded.jar意味著可能想要一個TomcatServletWebServerFactory的bean *(除非自定義了ServletWebServerFactory的bean) * * 當使用@SpringBootApplication注解時,上下文的自動配置功能自動開啟。 * 添加這個注解沒有額外的作用。 * * 自動配置盡可能的智能,當你自定義了更多配置,自動配置會慢慢弱化。 * 如果不想用某些配置,你可以通過excludeName手動排除。 * 也可以通過exclude排除。 * 自動配置總是在用戶定義bean注冊之后應用。 * * 用@EnableAutoConfiguration注解的類包(通常通過@SpringBootApplication)具有特定的意義,通常是默認的。 * 例如: * 它將在掃描@Entity類時使用。 * 通常建議將@EnableAutoConfiguration(如果不使用@SpringBootApplication)放在根包中,以便可以搜索所有子包和類。 * * 自動配置類是常規(guī)的Spring @Configuration bean。 * 它們是使用importcandidate和springfactoresloader機制定位的(與這個類相關)。 * 通常自動配置bean是@Conditional注解的bean(最常使用@ConditionalOnClass和@ConditionalOnMissingBean注解)。 * */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; /** * 通過class排除不需要的自動配置類 */ Class<?>[] exclude() default {}; /** * 通過類名稱排除不需要的自動配置類 */ String[] excludeName() default {}; }
4.3.1.1獲取自動配置入口
// AutoConfigurationImportSelector protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } // exclude excludeName AnnotationAttributes attributes = getAttributes(annotationMetadata); // 所有META-INF/spring.factories中的自動配置類 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 去重 configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); // 去掉需要排除的 configurations.removeAll(exclusions); // 過濾器過濾 configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
4.3.1.2過濾器應用
OnClassCondition過濾器會對配置類中@ConditionalOnClass和@ConditionalOnMissingClass進行匹配過濾
// MybatisAutoConfiguration @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
如果classpath下沒有SqlSessionFactory或者SqlSessionFactoryBean,該配置類將被過濾
OnBeanCondition過濾器會對配置類中@ConditionalOnSingleCandidate進行匹配過濾
// MybatisAutoConfiguration @ConditionalOnSingleCandidate(DataSource.class)
應用上下文中是否存在DataSource類型的單個候選 bean。如果存在且只有一個這樣的 bean,則條件匹配。
4.3.1.3過濾結(jié)果
4.3.1.4遍歷處理自動配置類
后續(xù)就是將MybatisAutoConfiguration中涉及到的bean定義信息注冊到容器中。
五、總結(jié)
1. Spring Boot 啟動和自動配置的初始化
當 Spring Boot 啟動時,SpringApplication.run()
方法會被調(diào)用,Spring 容器會加載并處理配置類和自動配置類。在自動配置過程中,Spring Boot 會根據(jù) @EnableAutoConfiguration
注解和 @AutoConfiguration
注解掃描和加載符合條件的自動配置類。
2. 自動配置類的選擇
Spring Boot 自動配置是通過 spring.factories
文件來加載的。spring.factories
文件列出了所有自動配置類,在應用啟動時,這些自動配置類會被加載到 Spring 容器中。
spring.factories 文件
在 spring-boot-autoconfigure
模塊中,spring.factories
文件中會包含對 MyBatis 自動配置類 MybatisAutoConfiguration
的引用。該文件告訴 Spring Boot 當滿足特定條件時,加載 MybatisAutoConfiguration
類。
3. 處理 @EnableAutoConfiguration 和條件注解
Spring Boot 使用了許多條件注解(@Conditional
系列注解),來決定是否啟用某些配置類。
@ConditionalOnClass 和 @ConditionalOnMissingClass
MybatisAutoConfiguration
配置類上有 @ConditionalOnClass
注解,表示只有當 SqlSessionFactory
、SqlSessionFactoryBean
等 MyBatis 相關類在類路徑中時,才會啟用該自動配置類。@ConditionalOnClass
由 OnClassCondition
過濾器進行檢查,判斷類路徑中是否存在這些類。
MybatisAutoConfiguration
還會使用 @ConditionalOnSingleCandidate
注解來檢查 Spring 容器中是否存在且只有一個 DataSource
類型的 Bean。如果條件滿足,則加載 MybatisAutoConfiguration
。
4. 加載 MybatisAutoConfiguration 配置類
在滿足了 @ConditionalOnClass
和 @ConditionalOnSingleCandidate
等條件后,MybatisAutoConfiguration
類會被加載并注冊到 Spring 容器中。
5. 創(chuàng)建 DataSource 和 SqlSessionFactory
MybatisAutoConfiguration
配置類內(nèi)部有多個 @Bean
方法,其中主要的兩個是 DataSource
和 SqlSessionFactory
的配置。Spring Boot 會根據(jù)現(xiàn)有的條件自動配置這些 Bean。
DataSource
- 如果你沒有手動配置
DataSource
,Spring Boot 會使用默認的數(shù)據(jù)庫連接池(如 HikariCP)自動配置一個DataSource
Bean。 - 如果已經(jīng)在應用上下文中存在
DataSource
,則自動配置會跳過該步驟。
SqlSessionFactory
SqlSessionFactory
是 MyBatis 的核心對象,它需要 DataSource
來進行初始化。MybatisAutoConfiguration
類會檢查容器中是否已有 SqlSessionFactory
Bean,如果沒有,則會創(chuàng)建一個新的 SqlSessionFactory
。
@ConditionalOnMissingBean
注解表示只有當容器中沒有 SqlSessionFactory
時,才會創(chuàng)建這個 Bean。
6. 創(chuàng)建 SqlSessionTemplate
SqlSessionTemplate
是 MyBatis 與 Spring 整合的核心類,負責事務管理和會話的創(chuàng)建。MybatisAutoConfiguration
會根據(jù) SqlSessionFactory
創(chuàng)建一個 SqlSessionTemplate
:
如果容器中沒有 SqlSessionTemplate
Bean,MybatisAutoConfiguration
會創(chuàng)建并注冊一個 SqlSessionTemplate
Bean。
7. 配置 MapperScannerConfigurer 或 @MapperScan
Spring Boot 中的 MyBatis 自動配置已經(jīng)提供了自動掃描 Mapper 的功能,通常不需要手動配置 MapperScannerConfigurer
。@MapperScan
注解用于指定掃描 Mapper 接口的包:
Spring Boot 會自動掃描該包下的 Mapper 接口,并將其注冊為 Spring Bean。
以上就是SpringBoot中的自動裝配原理詳解的詳細內(nèi)容,更多關于SpringBoot自動裝配的資料請關注腳本之家其它相關文章!
相關文章
Java?嵌入數(shù)據(jù)引擎從?SQLite?到?SPL詳解
這篇文章主要介紹了Java?嵌入數(shù)據(jù)引擎:從?SQLite?到?SPL,SQLite架構(gòu)簡單,其核心雖然是C語言開發(fā)的,但封裝得比較好,對外呈現(xiàn)為一個小巧的Jar包,能方便地集成在Java應用中,本文給大家介紹的非常詳細,需要的朋友參考下2022-07-07Java中JSONObject與JSONArray的使用區(qū)別詳解
這篇文章主要介紹了Java中JSONObject與JSONArray的使用區(qū)別詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11Springboot?Mybatis使用pageHelper如何實現(xiàn)分頁查詢
這篇文章主要介紹了Springboot?Mybatis使用pageHelper如何實現(xiàn)分頁查詢問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05SpringBoot中@ConditionalOnProperty注解的使用方法詳解
這篇文章主要介紹了SpringBoot中@ConditionalOnProperty注解的使用方法詳解,在開發(fā)基于SpringBoot框架的項目時,會用到下面的條件注解,有時會有需要控制配置類是否生效或注入到Spring上下文中的場景,可以使用@ConditionalOnProperty注解來控制,需要的朋友可以參考下2024-01-01MyBatis 探秘之#{} 與 ${} 參傳差異解碼(數(shù)據(jù)庫連接池筑牢數(shù)據(jù)交互
本文詳細介紹了MyBatis中的`#{}`和`${}`的區(qū)別與使用場景,包括預編譯SQL和即時SQL的區(qū)別、安全性問題,以及如何正確使用數(shù)據(jù)庫連接池來提高性能,感興趣的朋友一起看看吧2024-12-12