SpringBoot自動(dòng)配置的原理詳解
一、構(gòu)建系統(tǒng)
1.1 依賴管理
Spring Boot 的每個(gè)版本都提供了它支持的依賴項(xiàng)的精選列表。實(shí)際上,您不需要在構(gòu)建配置中為任何這些依賴項(xiàng)提供版本,因?yàn)?Spring Boot 會(huì)為您管理。當(dāng)您升級(jí) Spring Boot 本身時(shí),這些依賴項(xiàng)也會(huì)以一致的方式升級(jí)。
如果需要,您仍然可以指定版本并覆蓋 Spring Boot 的建議。
依賴管理 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> </parent> 他的父項(xiàng)目 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.4.RELEASE</version> </parent> 幾乎聲明了所有開(kāi)發(fā)中常用的依賴的版本號(hào),自動(dòng)版本仲裁機(jī)制
1.2 Starters 啟動(dòng)器
Starters 是一組方便的依賴描述符,您可以將其包含在您的應(yīng)用程序中。您可以獲得所需的所有 Spring 和相關(guān)技術(shù)的一站式商店,而無(wú)需搜索示例代碼和復(fù)制粘貼加載的依賴描述符。例如,如果您想開(kāi)始使用 Spring 和 JPA 進(jìn)行數(shù)據(jù)庫(kù)訪問(wèn),請(qǐng)將spring-boot-starter-data-jpa依賴項(xiàng)包含在您的項(xiàng)目中。
啟動(dòng)器包含許多依賴項(xiàng),您需要這些依賴項(xiàng)使項(xiàng)目快速啟動(dòng)并運(yùn)行,并具有一致的、受支持的托管傳遞依賴項(xiàng)集。
1、見(jiàn)到很多 spring-boot-starter-* : *就某種場(chǎng)景
2、只要引入starter,這個(gè)場(chǎng)景的所有常規(guī)需要的依賴我們都自動(dòng)引入
3、SpringBoot所有支持的場(chǎng)景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、見(jiàn)到的 *-spring-boot-starter: 第三方為我們提供的簡(jiǎn)化開(kāi)發(fā)的場(chǎng)景啟動(dòng)器。
5、所有場(chǎng)景啟動(dòng)器最底層的依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.3.4.RELEASE</version> <scope>compile</scope> </dependency>
1、引入依賴默認(rèn)都可以不寫(xiě)版本
2、引入非版本仲裁的jar,要寫(xiě)版本號(hào)
查看spring-boot-dependencies里面規(guī)定當(dāng)前依賴的版本用的key. 在當(dāng)前項(xiàng)目里面重寫(xiě)配置
<properties> <mysql.version>5.1.43</mysql.version> </properties>
以下應(yīng)用程序啟動(dòng)器由該org.springframework.boot組下的 Spring Boot 提供:
1.3 自動(dòng)配置
1、 ctrl+點(diǎn)擊pom.xml文件中的spring-boot-starter-web可以打開(kāi)starter-web的配置信息
在這個(gè)文件中,我們可以看到又自動(dòng)配置了
1、自動(dòng)配好SpringMVC
○ 自動(dòng)配好SpringMVC
○ 自動(dòng)配好SpringMVC常用組件(功能)
2、自動(dòng)配好Web常見(jiàn)功能,如:字符編碼問(wèn)題
○ SpringBoot幫我們配置好了所有web開(kāi)發(fā)的常見(jiàn)場(chǎng)景
3、默認(rèn)的包結(jié)構(gòu)
○ 主程序所在包及其下面的所有子包里面的組件都會(huì)被默認(rèn)掃描進(jìn)來(lái),無(wú)需以前的包掃描配置
○ 想要改變掃描路徑,在服務(wù)啟動(dòng)類(lèi)上面加上注解@ComponentScan
如下:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")
4、按需加載所有自動(dòng)配置項(xiàng)
○ 非常多的starter
○ 引入了哪些場(chǎng)景這個(gè)場(chǎng)景的自動(dòng)配置才會(huì)開(kāi)啟
○ SpringBoot所有的自動(dòng)配置功能都在 spring-boot-autoconfigure 包里面
二、容器功能
2.1 組件添加
2.1.1 @Configuration
Full模式與Lite模式
- 類(lèi)組件之間無(wú)依賴關(guān)系用Lite模式加速容器啟動(dòng)過(guò)程,減少判斷
- 配置類(lèi)組件之間有依賴關(guān)系,方法會(huì)被調(diào)用得到之前單實(shí)例組件,用Full模式
1、配置類(lèi)里面使用@Bean標(biāo)注在方法上給容器注冊(cè)組件,默認(rèn)也是單實(shí)例的
2、配置類(lèi)本身也是組件
3、proxyBeanMethods:代理bean的方法
Full(proxyBeanMethods = true)、【保證每個(gè)@Bean方法被調(diào)用多少次返回的組件都是單實(shí)例的】
Lite(proxyBeanMethods = false)【每個(gè)@Bean方法被調(diào)用多少次返回的組件都是新創(chuàng)建的】
組件依賴必須使用Full模式默認(rèn)。其他默認(rèn)是否Lite模式
@Configuration(proxyBeanMethods = false) //告訴SpringBoot這是一個(gè)配置類(lèi) == 配置文件 public class MyConfig { /** * Full:外部無(wú)論對(duì)配置類(lèi)中的這個(gè)組件注冊(cè)方法調(diào)用多少次獲取的都是之前注冊(cè)容器中的單實(shí)例對(duì)象 * @return */ @Bean //給容器中添加組件。以方法名作為組件的id。返回類(lèi)型就是組件類(lèi)型。返回的值,就是組件在容器中的實(shí)例 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"); } } ################################@Configuration測(cè)試代碼如下######################################## @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)代理對(duì)象調(diào)用方法。SpringBoot總會(huì)檢查這個(gè)組件是否在容器中有。 //保持組件單實(shí)例 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.1.2 @Import
@Import({User.class, DBHelper.class}) 給容器中自動(dòng)創(chuàng)建出這兩個(gè)類(lèi)型的組件、默認(rèn)組件的名字就是全類(lèi)名
@Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false) //告訴SpringBoot這是一個(gè)配置類(lèi) == 配置文件 public class MyConfig { }
2.1.3 @Conditional (條件裝配)
條件裝配:滿足Conditional指定的條件,則進(jìn)行組件注入
- @ConditionalOnProperty 注解
- @ConditionalOnMissingBean注解
@ConditionalOnMissingBean,它是修飾bean的一個(gè)注解,主要實(shí)現(xiàn)的是,當(dāng)你的bean被注冊(cè)之后,如果而注冊(cè)相同類(lèi)型的bean,就不會(huì)成功,它會(huì)保證你的bean只有一個(gè),即你的實(shí)例只有一個(gè),當(dāng)你注冊(cè)多個(gè)相同的bean時(shí),會(huì)出現(xiàn)異常,以此來(lái)告訴開(kāi)發(fā)人員。
@Component public class AutoConfig { @Bean public AConfig aConfig() { return new AConfig("lind"); } @Bean @ConditionalOnMissingBean(AMapper.class) public AMapper aMapper1(AConfig aConfig) { return new AMapperImpl1(aConfig); } @Bean public AMapper aMapper2(AConfig aConfig) { return new AMapperImpl2(aConfig); } }
因?yàn)樵赼Mapper1上面標(biāo)識(shí)了AMapper類(lèi)型的bean只能有一個(gè)實(shí)現(xiàn) @ConditionalOnMissingBean(AMapper.class),所以在進(jìn)行aMapper2注冊(cè)時(shí),系統(tǒng)會(huì)出現(xiàn)上面圖上的異常,這是正常的。 當(dāng)我們把 @ConditionalOnMissingBean(AMapper.class) 去掉之后,你的bean可以注冊(cè)多次,這時(shí)需要用的@Primary來(lái)確定你要哪個(gè)實(shí)現(xiàn);一般來(lái)說(shuō),對(duì)于自定義的配置類(lèi),我們應(yīng)該加上@ConditionalOnMissingBean注解,以避免多個(gè)配置同時(shí)注入的風(fēng)險(xiǎn)。
@Primary標(biāo)識(shí)哪個(gè)是默認(rèn)的bean
@Bean public AMapper aMapper1(AConfig aConfig) { return new AMapperImpl1(aConfig); } @Bean @Primary public AMapper aMapper2(AConfig aConfig) { return new AMapperImpl2(aConfig); }
@ConditionalOnProperty 通過(guò)其三個(gè)屬性prefix,name以及havingValue來(lái)實(shí)現(xiàn)的,其中prefix表示配置文件里節(jié)點(diǎn)前綴,name用來(lái)從application.properties中讀取某個(gè)屬性值,havingValue表示目標(biāo)值。
如果該值為空,則返回false; 如果值不為空,則將該值與havingValue指定的值進(jìn)行比較,如果一樣則返回true;否則返回false。 返回值為false,則該configuration不生效;為true則生效。 下面代碼演示為配置文件lind.redis.enable為true時(shí)才會(huì)注冊(cè)RedisFactory這個(gè)bean
@Configuration @ConditionalOnProperty(prefix="lind.redis",name = "enable", havingValue = "true") public class RedisConfig { @Bean public RedisMap redisMap(){ return new RedisMapImpl(); } }
- @ConditionalOnBean // 當(dāng)給定的在bean存在時(shí),則實(shí)例化當(dāng)前Bean
- @ConditionalOnMissingBean // 當(dāng)給定的在bean不存在時(shí),則實(shí)例化當(dāng)前Bean
- @ConditionalOnClass // 當(dāng)給定的類(lèi)名在類(lèi)路徑上存在,則實(shí)例化當(dāng)前Bean
- @ConditionalOnMissingClass // 當(dāng)給定的類(lèi)名在類(lèi)路徑上不存在,則實(shí)例化當(dāng)前Bean
2.2 原生配置文件引入
2.2.1 @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" 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="stu01.com.bean.User"> <property name="name" value="zhangsan"></property> <property name="id" value="18"></property> </bean> <bean id="hehe" class="stu01.com.bean.User"> <property name="name" value="lisi"></property> <property name="id" value="20"></property> </bean> </beans>
測(cè)試
package stu01.com.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportResource; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import stu01.com.bean.User; @Configuration @ImportResource("classpath:beans.xml") public class Myconfig { @Autowired ApplicationContext applicationContext; @Bean public User getUser(){ applicationContext.getBean("myconfig"); boolean haha = applicationContext.containsBean("haha"); boolean hehe = applicationContext.containsBean("hehe"); System.out.println("haha:"+haha);//true System.out.println("hehe:"+hehe);//true User user=(User) applicationContext.getBean("haha"); System.out.println(user.toString()); return user; } }
2.3 配置綁定
如何使用Java讀取到properties文件中的內(nèi)容,并且把它封裝到JavaBean中,以供隨時(shí)使用;
package stu01.com.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportResource; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import stu01.com.bean.User; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Enumeration; import java.util.Properties; @Configuration @ImportResource("classpath:beans.xml") public class Myconfig { @Autowired ApplicationContext applicationContext; @Bean public User getUser() throws IOException { Properties pps = new Properties(); pps.load(new FileInputStream("E:\\IdealWork\\SpringBootStu\\Stu01\\src\\main\\resources\\a.properties")); Enumeration enum1 = pps.propertyNames();//得到配置文件的名字 User user = new User(); while(enum1.hasMoreElements()) { String strKey = (String) enum1.nextElement(); String strValue = pps.getProperty(strKey); System.out.println(strKey + "=" + strValue); //封裝到JavaBean。 if(strKey.equals("name")){ user.setName(strValue); } if(strKey.equals("id")){ user.setId(strValue); } } System.out.println(user.toString()); return user; } }
結(jié)果:
2.3.1 使用注解獲取配置文件中的配置信息
@ConfigurationProperties(prefix = “mycar”) 在需要被注入值的類(lèi)上添加注解,prefix的值,與配置文件中的前綴一一對(duì)應(yīng)。
package stu01.com.bean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix = "user-info") public class User { String name; String id; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", id='" + id + '\'' + '}'; } }
application.properties配置文件
userInfo.name="lisi" userInfo.id=88888
@Configuration
@ConfigurationProperties(prefix = “user-info”)
@EnableConfigurationProperties(User.class)
在配置類(lèi)上添加以上注解測(cè)試
package stu01.com.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportResource; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import stu01.com.bean.User; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Enumeration; import java.util.Properties; @Configuration @ConfigurationProperties(prefix = "user-info") @EnableConfigurationProperties(User.class) public class Myconfig { @Autowired ApplicationContext applicationContext; @Bean public User getUser() throws IOException { applicationContext.getBean("myconfig"); boolean haha = applicationContext.containsBean("user"); boolean hehe = applicationContext.containsBean("hehe"); System.out.println("haha:" + haha);//true System.out.println("hehe:" + hehe);//true User user = (User) applicationContext.getBean("user"); System.out.println(user.toString()); return user; } }
三、自動(dòng)配置原理入門(mén)
3.1 引導(dǎo)加載自動(dòng)配置類(lèi)
點(diǎn)擊程序的啟動(dòng)類(lèi)上的@SpringBootApplication注解,會(huì)出現(xiàn)下面的類(lèi),上面被加上了幾個(gè)注解
@SpringBootConfiguration:代表當(dāng)前是一個(gè)配置類(lèi); @ComponentScan:指定掃描哪些,Spring注解;
@EnableAutoConfiguration:自動(dòng)配置的注解
3.1.1 @AutoConfigurationPackage
點(diǎn)擊注解@EnableAutoConfiguration,直到看到AutoConfigurationPackage自動(dòng)配置包:指定了默認(rèn)的包規(guī)則
@Import(AutoConfigurationPackages.Registrar.class) //給容器中導(dǎo)入一個(gè)組件 public @interface AutoConfigurationPackage {} //利用Registrar給容器中導(dǎo)入一系列組件 //將指定的一個(gè)包下的所有組件導(dǎo)入進(jìn)來(lái)?MainApplication 所在包下。
3.1.2 @Import(AutoConfigurationImportSelector.class)
1、利用getAutoConfigurationEntry(annotationMetadata);給容器中批量導(dǎo)入一些組件
2、調(diào)用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)獲取到所有需要導(dǎo)入到容器中的配置類(lèi)
3、利用工廠加載 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的組件
4、從META-INF/spring.factories位置來(lái)加載一個(gè)文件。
默認(rèn)掃描我們當(dāng)前系統(tǒng)里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
文件里面寫(xiě)死了spring-boot一啟動(dòng)就要給容器中加載的所有配置類(lèi)
3.2 按需開(kāi)啟自動(dòng)配置項(xiàng)
雖然我們127個(gè)場(chǎng)景的所有自動(dòng)配置啟動(dòng)的時(shí)候默認(rèn)全部加載。xxxxAutoConfiguration 按照條件裝配規(guī)則(@Conditional),最終會(huì)按需配置。
自動(dòng)配置是非侵入性的。在任何時(shí)候,您都可以開(kāi)啟定義自己的配置來(lái)替換自動(dòng)配置的特定部分。例如你想添加自己的DataSourceBean,則默認(rèn)的嵌入式數(shù)據(jù)庫(kù)支持會(huì)默認(rèn)退出。
如果您需要了解當(dāng)前正在應(yīng)用哪些自動(dòng)配置以及原因,請(qǐng)使用–debug開(kāi)關(guān)啟動(dòng)您的應(yīng)用程序。這樣做可以為選擇的核心記錄器啟用調(diào)試日志,并將條件報(bào)告記錄到控制臺(tái)。
3.2.1 禁用特定的自動(dòng)配置類(lèi)
如果您發(fā)現(xiàn)正在應(yīng)用您不想要的特定自動(dòng)配置類(lèi),您可以使用 exclude 屬性@SpringBootApplication來(lái)禁用它們,如下例所示:
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) public class MyApplication { }
3.3 修改默認(rèn)配置
@Bean @ConditionalOnBean(MultipartResolver.class) //容器中有這個(gè)類(lèi)型組件 @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中沒(méi)有這個(gè)名字 multipartResolver 的組件 public MultipartResolver multipartResolver(MultipartResolver resolver) { //給@Bean標(biāo)注的方法傳入了對(duì)象參數(shù),這個(gè)參數(shù)的值就會(huì)從容器中找。 //SpringMVC multipartResolver。防止有些用戶配置的文件上傳解析器不符合規(guī)范 // Detect if the user has created a MultipartResolver but named it incorrectly return resolver; } 給容器中加入了文件上傳解析器;
SpringBoot默認(rèn)會(huì)在底層配好所有的組件。但是如果用戶自己配置了以用戶的優(yōu)先
@Bean @ConditionalOnMissingBean public CharacterEncodingFilter characterEncodingFilter() { }
3.3.1 總結(jié):
- SpringBoot先加載所有的自動(dòng)配置類(lèi) xxxxxAutoConfiguration
- 每個(gè)自動(dòng)配置類(lèi)按照條件進(jìn)行生效,默認(rèn)都會(huì)綁定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件進(jìn)行了綁定
- 生效的配置類(lèi)就會(huì)給容器中裝配很多組件
- 只要容器中有這些組件,相當(dāng)于這些功能就有了
- 定制化配置
- 用戶直接自己@Bean替換底層的組件
- 用戶去看這個(gè)組件是獲取的配置文件什么值就去修改。
四、最佳實(shí)踐&開(kāi)發(fā)技巧
4.1 Lombok
簡(jiǎn)化JavaBean開(kāi)發(fā)
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
idea中搜索安裝lombok插件
===============================簡(jiǎn)化JavaBean開(kāi)發(fā)=================================== @NoArgsConstructor //@AllArgsConstructor @Data @ToString @EqualsAndHashCode public class User { private String name; private Integer age; private Pet pet; public User(String name,Integer age){ this.name = name; this.age = age; } } ================================簡(jiǎn)化日志開(kāi)發(fā)=================================== @Slf4j @RestController public class HelloController { @RequestMapping("/hello") public String handle01(@RequestParam("name") String name){ log.info("請(qǐng)求進(jìn)來(lái)了...."); return "Hello, Spring Boot 2!"+"你好:"+name; } }
4.2 dev-tools 無(wú)須重啟部署項(xiàng)目
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
項(xiàng)目或者頁(yè)面修改以后:Ctrl+F9;
到此這篇關(guān)于SpringBoot自動(dòng)配置的原理詳解的文章就介紹到這了,更多相關(guān)SpringBoot自動(dòng)配置內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)統(tǒng)計(jì)文件夾下所有文件的字?jǐn)?shù)
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)統(tǒng)計(jì)文件夾下所有文件的字?jǐn)?shù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03Spring動(dòng)態(tài)數(shù)據(jù)源實(shí)現(xiàn)讀寫(xiě)分離詳解
這篇文章主要為大家詳細(xì)介紹了Spring動(dòng)態(tài)數(shù)據(jù)源實(shí)現(xiàn)讀寫(xiě)分離,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07Springboot項(xiàng)目平滑關(guān)閉及自動(dòng)化關(guān)閉腳本
這篇文章主要為大家詳細(xì)介紹了Springboot項(xiàng)目平滑關(guān)閉及自動(dòng)化關(guān)閉腳本,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05關(guān)于SpringCloud整合RabbitMQ的實(shí)例
這篇文章主要介紹了關(guān)于SpringCloud整合RabbitMQ的實(shí)例,消息隊(duì)列是指利用高效可靠的消息傳遞機(jī)制進(jìn)行與平臺(tái)無(wú)關(guān)的數(shù)據(jù)交流,并基于數(shù)據(jù)通信來(lái)進(jìn)行分布式系統(tǒng)的集成,是在消息的傳輸過(guò)程中保存消息的容器,需要的朋友可以參考下2023-07-07java 中的static關(guān)鍵字和final關(guān)鍵字的不同之處
java 中的static關(guān)鍵字和final關(guān)鍵字的不同之處,需要的朋友可以參考一下2013-03-03Java Runnable線程傳參,實(shí)現(xiàn)讓run訪問(wèn)參數(shù)
這篇文章主要介紹了Java Runnable線程傳參,實(shí)現(xiàn)讓run訪問(wèn)參數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09一篇文章帶你理解Java Spring三級(jí)緩存和循環(huán)依賴
這篇文章主要介紹了淺談Spring 解決循環(huán)依賴必須要三級(jí)緩存嗎,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-09-09SocketIo+SpringMvc實(shí)現(xiàn)文件的上傳下載功能
這篇文章主要介紹了SocketIo+SpringMvc實(shí)現(xiàn)文件的上傳下載功能,socketIo不僅可以用來(lái)做聊天工具,也可以實(shí)現(xiàn)局域網(wǎng)。文中給出了實(shí)現(xiàn)代碼,需要的朋友可以參考下2018-08-08