Spring BeanPostProcessor(后置處理器)的用法
為了弄清楚Spring框架,我們需要分別弄清楚相關(guān)核心接口的作用,本文來介紹下BeanPostProcessor接口
BeanPostProcessor
該接口我們也叫后置處理器,作用是在Bean對(duì)象在實(shí)例化和依賴注入完畢后,在顯示調(diào)用初始化方法的前后添加我們自己的邏輯。注意是Bean實(shí)例化完畢后及依賴注入完成后觸發(fā)的。接口的源碼如下
public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
方法 | 說明 |
---|---|
postProcessBeforeInitialization | 實(shí)例化、依賴注入完畢, 在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù) |
postProcessAfterInitialization | 實(shí)例化、依賴注入、初始化完畢時(shí)執(zhí)行 |
一、自定義后置處理器演示
1.自定義處理器
package com.dpb.processor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; /** * 自定義BeanPostProcessor實(shí)現(xiàn)類 * BeanPostProcessor接口的作用是: * 我們可以通過該接口中的方法在bean實(shí)例化、配置以及其他初始化方法前后添加一些我們自己的邏輯 * @author dengp * */ public class MyBeanPostProcessor implements BeanPostProcessor{ /** * 實(shí)例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù) * 注意:方法返回值不能為null * 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實(shí)例對(duì)象 * 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中 */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("初始化 before--實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName); // 可以根據(jù)beanName不同執(zhí)行不同的處理操作 return bean; } /** * 實(shí)例化、依賴注入、初始化完畢時(shí)執(zhí)行 * 注意:方法返回值不能為null * 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實(shí)例對(duì)象 * 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中 */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("初始化 after...實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName); // 可以根據(jù)beanName不同執(zhí)行不同的處理操作 return bean; } }
注意:接口中兩個(gè)方法不能返回null,如果返回null那么在后續(xù)初始化方法將報(bào)空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實(shí)例對(duì)象,因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
2.Pojo類
public class User { private int id; private String name; private String beanName; public User(){ System.out.println("User 被實(shí)例化"); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { System.out.println("設(shè)置:"+name); this.name = name; } public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } /** * 自定義的初始化方法 */ public void start(){ System.out.println("User 中自定義的初始化方法"); } }
3.配置文件注冊(cè)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="com.dpb.pojo.User" id="user" init-method="start"> <property name="name" value="波波烤鴨" /> </bean> <!-- 注冊(cè)處理器 --> <bean class="com.dpb.processor.MyBeanPostProcessor"></bean> </beans>
4.測(cè)試
@Test public void test() { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); User user = ac.getBean(User.class); System.out.println(user); }
輸出結(jié)果
User 被實(shí)例化
設(shè)置:波波烤鴨
初始化 before--實(shí)例化的bean對(duì)象:com.dpb.pojo.User@65e2dbf3 user
User 中自定義的初始化方法
初始化 after...實(shí)例化的bean對(duì)象:com.dpb.pojo.User@65e2dbf3 user
com.dpb.pojo.User@65e2dbf3
通過輸出語句我們也能看到postProcessBeforeInitialization方法的輸出語句是在Bean實(shí)例化及屬性注入后執(zhí)行的,且在自定義的初始化方法之前執(zhí)行(通過init-method指定)。而postProcessAfterInitialization方法是在自定義初始化方法執(zhí)行之后執(zhí)行的。
注意?。?!
BeanFactory和ApplicationContext兩個(gè)容器對(duì)待bean的后置處理器稍微有些不同。ApplicationContext容器會(huì)自動(dòng)檢測(cè)Spring配置文件中那些bean所對(duì)應(yīng)的Java類實(shí)現(xiàn)了BeanPostProcessor接口,并自動(dòng)把它們注冊(cè)為后置處理器。在創(chuàng)建bean過程中調(diào)用它們,所以部署一個(gè)后置處理器跟普通的bean沒有什么太大區(qū)別。
BeanFactory容器注冊(cè)bean后置處理器時(shí)必須通過代碼顯示的注冊(cè),在IoC容器繼承體系中的ConfigurableBeanFactory接口中定義了注冊(cè)方法
/** * Add a new BeanPostProcessor that will get applied to beans created * by this factory. To be invoked during factory configuration. * <p>Note: Post-processors submitted here will be applied in the order of * registration; any ordering semantics expressed through implementing the * {@link org.springframework.core.Ordered} interface will be ignored. Note * that autodetected post-processors (e.g. as beans in an ApplicationContext) * will always be applied after programmatically registered ones. * @param beanPostProcessor the post-processor to register */ void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
測(cè)試代碼如下
@Test public void test2() { //ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); // 顯示添加后置處理器 bf.addBeanPostProcessor(bf.getBean(MyBeanPostProcessor.class)); User user = bf.getBean(User.class); System.out.println(user); }
二、多個(gè)后置處理器
我們可以在Spring配置文件中添加多個(gè)BeanPostProcessor(后置處理器)接口實(shí)現(xiàn)類,在默認(rèn)情況下Spring容器會(huì)根據(jù)后置處理器的定義順序來依次調(diào)用。
public class MyBeanPostProcessor implements BeanPostProcessor{ /** * 實(shí)例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù) * 注意:方法返回值不能為null * 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實(shí)例對(duì)象 * 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中 */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("A before--實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName); // 可以根據(jù)beanName不同執(zhí)行不同的處理操作 return bean; } /** * 實(shí)例化、依賴注入、初始化完畢時(shí)執(zhí)行 * 注意:方法返回值不能為null * 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實(shí)例對(duì)象 * 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中 */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("A after...實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName); // 可以根據(jù)beanName不同執(zhí)行不同的處理操作 return bean; } }
public class MyBeanPostProcessor2 implements BeanPostProcessor{ /** * 實(shí)例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù) * 注意:方法返回值不能為null * 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象 * 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中 */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("B before--實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName); // 可以根據(jù)beanName不同執(zhí)行不同的處理操作 return bean; } /** * 實(shí)例化、依賴注入、初始化完畢時(shí)執(zhí)行 * 注意:方法返回值不能為null * 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實(shí)例對(duì)象 * 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中 */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("B after...實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName); // 可以根據(jù)beanName不同執(zhí)行不同的處理操作 return bean; } }
配置文件注冊(cè)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="com.dpb.pojo.User" id="user" init-method="start"> <property name="name" value="波波烤鴨" /> </bean> <!-- 注冊(cè)處理器 --> <bean class="com.dpb.processor.MyBeanPostProcessor"/> <bean class="com.dpb.processor.MyBeanPostProcessor2"/> </beans>
測(cè)試結(jié)果
User 被實(shí)例化
設(shè)置:波波烤鴨
A before--實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
B before--實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
User 中自定義的初始化方法
A after...實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
B after...實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
com.dpb.pojo.User@7fac631b
三、顯示指定順序
在Spring機(jī)制中可以指定后置處理器調(diào)用順序,通過讓BeanPostProcessor接口實(shí)現(xiàn)類實(shí)現(xiàn)Ordered接口getOrder方法,該方法返回一整數(shù),默認(rèn)值為 0,優(yōu)先級(jí)最高,值越大優(yōu)先級(jí)越低
public class MyBeanPostProcessor implements BeanPostProcessor,Ordered{ /** * 實(shí)例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù) * 注意:方法返回值不能為null * 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象 * 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中 */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("A before--實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName); // 可以根據(jù)beanName不同執(zhí)行不同的處理操作 return bean; } /** * 實(shí)例化、依賴注入、初始化完畢時(shí)執(zhí)行 * 注意:方法返回值不能為null * 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象 * 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中 */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("A after...實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName); // 可以根據(jù)beanName不同執(zhí)行不同的處理操作 return bean; } @Override public int getOrder() { // TODO Auto-generated method stub return 10; } }
public class MyBeanPostProcessor2 implements BeanPostProcessor,Ordered{ /** * 實(shí)例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù) * 注意:方法返回值不能為null * 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象 * 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中 */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("B before--實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName); // 可以根據(jù)beanName不同執(zhí)行不同的處理操作 return bean; } /** * 實(shí)例化、依賴注入、初始化完畢時(shí)執(zhí)行 * 注意:方法返回值不能為null * 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象 * 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中 */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("B after...實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName); // 可以根據(jù)beanName不同執(zhí)行不同的處理操作 return bean; } @Override public int getOrder() { // TODO Auto-generated method stub return 2; } }
測(cè)試輸出結(jié)果
User 被實(shí)例化
設(shè)置:波波烤鴨
B before--實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
A before--實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
User 中自定義的初始化方法
B after...實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
A after...實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
com.dpb.pojo.User@7fac631b
數(shù)值越大的優(yōu)先級(jí)越低,所以A的輸出就在后面了。
對(duì)BeanPostProcessor接口的理解
今天想起來寫一篇,是因?yàn)樽约杭m正了對(duì)BeanPostProcessor接口的理解誤區(qū),寫文章往往都是源于這種豁然開朗的靈感。不過今天又是孤陋寡聞的一天呢,一個(gè)知識(shí)點(diǎn)理解錯(cuò)了這么長(zhǎng)時(shí)間居然都不自知。
Bean的生命周期應(yīng)該都很清楚,先貼這張圖
這張Bean生命周期順序圖里大部分環(huán)節(jié)都是比較好理解的,比如setBeanName和setBeanFactory包括setApplicationContext,都是實(shí)現(xiàn)了對(duì)應(yīng)的接口,就可以在實(shí)例化這個(gè)Bean的時(shí)候?yàn)檫@個(gè)Bean設(shè)置BeanName,或者注入BeanFactory和ApplicationContext,可以用于獲取IOC容器中的其他Bean等。但是實(shí)現(xiàn)了BeanPostProcessor接口不能按這個(gè)邏輯去理解,
先看一下實(shí)現(xiàn)BeanPostProcessor接口后的重寫哪兩個(gè)方法:
之前我一直是按這個(gè)理解邏輯去理解實(shí)現(xiàn)了BeanPostProcessor接口,理解誤區(qū)是:MyBeanPost這個(gè)類實(shí)現(xiàn)了BeanPostProcessor接口,實(shí)例化的MyBeanPost的時(shí)候就會(huì)去調(diào)用該類里重寫的postProcessBeforeInitialization()和postProcessAfterInitialization()方法,這兩個(gè)方法里拿到的beanName就是@Component里定義的"myBeanPost",Object類型的bean就是MyBeanPost對(duì)象,然后實(shí)例化MyBeanPost對(duì)象前后去在這兩個(gè)方法里做點(diǎn)什么。
之前一直是這么理解的,其實(shí)一直是有疑惑的,因?yàn)榘催@么理解,postProcessBeforeInitialization()方法能做的在自定義的@PostConstruct方法里也能做,那這兩個(gè)就區(qū)分不開了。雖然有疑惑但自己也沒有去試過,直到今天項(xiàng)目開發(fā)的時(shí)候真的想用postProcessAfterInitialization()方法去在初始化完一個(gè)Bean的時(shí)候注入點(diǎn)東西的時(shí)候,一試傻眼了。
直接貼上圖那種寫法時(shí)的啟動(dòng)日志:
如果按我之前那么理解,這里應(yīng)該只打印出"myBeanPost執(zhí)行了postProcessBeforeInitialization"和"myBeanPost執(zhí)行了postProcessAfterInitialization"才對(duì)啊,居然打印出了這么多,而且我全局搜了一下,偏偏沒有beanName是"myBeanPost"的日志記錄。這個(gè)時(shí)候我才知道之前我一直理解錯(cuò)了,于是重視起來開始找原因。
Spring的源碼一頓翻之后找到了Spring初始化Bean的一段代碼:
這里的invokeInitMethods()就是反射調(diào)用我們自定義的初始化方法,即順序圖中的第八步,可以清楚的看到applyBeanPostProcessorsBeforeInitialization()方法在前,applyBeanPostProcessorsAfterInitialization()方法在后,這似乎也和順序圖中執(zhí)行postProcessBeforeInitialization()在執(zhí)行自定義初始化方法前,執(zhí)行postProcessAfterInitialization()在后對(duì)應(yīng)上了,繼續(xù)點(diǎn)進(jìn)去看,
先看applyBeanPostProcessorsBeforeInitialization()方法
需要注意這里existingBean參數(shù)是正在實(shí)例化的Bean,這里的getBeanPostProcessors()方法是去拿所有實(shí)現(xiàn)了BeanPostProcessor接口的實(shí)現(xiàn)類的Bean,然后再調(diào)用BeanPostProcessor接口實(shí)現(xiàn)類的postProcessBeforeInitialization()方法。
看到這里就推翻了我之前的理解了,原來一個(gè)類實(shí)現(xiàn)了BeanPostProcessor接口,那重寫的兩個(gè)方法不是實(shí)例化該類的時(shí)候調(diào)用的,而是容器實(shí)例化其他Bean的時(shí)候調(diào)用的,容器會(huì)找出當(dāng)前容器中所有實(shí)現(xiàn)了BeanPostProcessor接口實(shí)現(xiàn)類對(duì)象,然后一個(gè)遍歷一個(gè)一個(gè)調(diào)用,這也是為什么上圖打印出來的日志會(huì)有這么多BeanName的日志記錄。也就是說如果容器需要實(shí)例化N個(gè)Bean,同時(shí)容器中已有M個(gè)BeanPostProcessor接口實(shí)現(xiàn)類對(duì)象,那BeanPostProcessor接口的那兩個(gè)方法就會(huì)被調(diào)用N*M次,雖然是在不同的實(shí)現(xiàn)類中調(diào)用的。
applyBeanPostProcessorsAfterInitialization()同理:
一樣的,總結(jié)一下,對(duì)于BeanPostProcessor接口的理解的理解應(yīng)該是這樣:
BeanPostProcessor接口有兩個(gè)方法,分別為Bean容器中每個(gè)對(duì)象被實(shí)例化前和實(shí)例化后調(diào)用,即交給Bean容器管理的所有對(duì)象,比如打了@Component,@RestController等注解的類,程序啟動(dòng)時(shí)就會(huì)去實(shí)例化并放到Bean容器中的這些類。每次實(shí)例化一個(gè)Bean都會(huì)調(diào)用BeanPostProcessor接口重寫方法,所有那兩個(gè)方法是被多次調(diào)用的。應(yīng)該在那兩個(gè)方法中很據(jù)BeanName拿到自己想處理的Bean實(shí)例,再去做對(duì)應(yīng)處理。
文章開頭也提到,日志打印了這么多,偏偏沒有beanName是"myBeanPost"的日志記錄,也就是說,BeanPostProcessor接口的實(shí)現(xiàn)類明明也打了@Component注解,可是為啥在自己的重寫方法中打印不出來beanName是自己的日志記錄呢?這是正常而且必然的。因?yàn)殡m然MyBeanPost也打了@Component,程序啟動(dòng)時(shí)也會(huì)去實(shí)例化這個(gè)Bean,但是實(shí)例化它的時(shí)候,getBeanPostProcessors()方法是拿不到MyBeanPost自己這個(gè)Bean的。還沒實(shí)例化完呢怎么放進(jìn)Bean容器中,沒放進(jìn)去當(dāng)然拿不到了,自然也不會(huì)去執(zhí)行這個(gè)Bean里重寫的方法了。
不過如果另外寫一個(gè)BeanPostProcessor接口的實(shí)現(xiàn)類就不一定了,如果實(shí)例化MyBeanPost的時(shí)候另一個(gè)BeanPostProcessor實(shí)現(xiàn)類已經(jīng)被實(shí)例化好了放進(jìn)Bean容器中了,getBeanPostProcessors()就能拿到,然后在另一個(gè)BeanPostProcessor實(shí)現(xiàn)類里重寫的方法里打印出beanName為"myBeanPost"的日志記錄。反正,BeanPostProcessor實(shí)現(xiàn)類不能在自己重寫的方法中不能拿到自己的Bean實(shí)例。
所以BeanPostProcessor接口的正確用法應(yīng)該是寫一個(gè)MyBeanPostProcessor實(shí)現(xiàn)類,意思是自定義的Bean處理類,然后在這個(gè)自定義的Bean處理類中根據(jù)beanName去篩選拿到Bean容器中的其他Bean,做一些實(shí)例化這些Bean之前之后的邏輯。例如這樣:
要注意重寫的方法默認(rèn)是返回null的,這里要返回處理后的bean,如果返回null就會(huì)是處理之前的bean,這個(gè)邏輯在applyBeanPostProcessorsBeforeInitialization()方法和applyBeanPostProcessorsAfterInitialization()方法里,
之前貼的圖里有,再貼一遍:
current即自定義處理之后的,如果是null,還是返回result。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Spring?BeanPostProcessor后處理器源碼解析
- 關(guān)于Spring BeanPostProcessor的執(zhí)行順序
- SpringBoot之通過BeanPostProcessor動(dòng)態(tài)注入ID生成器案例詳解
- Spring容器的創(chuàng)建過程之如何注冊(cè)BeanPostProcessor詳解
- 詳解使用Spring的BeanPostProcessor優(yōu)雅的實(shí)現(xiàn)工廠模式
- Spring中的后置處理器BeanPostProcessor詳解
- Spring BeanPostProcessor接口使用詳解
- 解析Java的Spring框架的BeanPostProcessor發(fā)布處理器
- spring中BeanPostProcessor的作用和使用注意事項(xiàng)
相關(guān)文章
詳解IntelliJ IDEA中TortoiseSVN修改服務(wù)器地址的方法
這篇文章主要介紹了詳解IntelliJ IDEA中TortoiseSVN修改服務(wù)器地址的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12解決spring mvc 多數(shù)據(jù)源切換,不支持事務(wù)控制的問題
下面小編就為大家?guī)硪黄鉀Qspring mvc 多數(shù)據(jù)源切換,不支持事務(wù)控制的問題。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09Mybatis中mapper.xml實(shí)現(xiàn)熱加載介紹
大家好,本篇文章主要講的是Mybatis中mapper.xml實(shí)現(xiàn)熱加載介紹,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01idea如何為java程序添加啟動(dòng)參數(shù)
文章介紹了如何在Java程序中添加啟動(dòng)參數(shù),包括program arguments、VM arguments和Environment variables,并解釋了如何在代碼中使用System類獲取這些參數(shù)2025-01-01