在多線程下,會發現Spring的自動注入失效了,原因是,Spring認爲在多線程下這樣做是危險的,如果你習慣用框架了,那麼我們都知道默認是單例的,那在多線程下如何注入Mapper,供我們使用呢?
在多線程的項目中,我也遇到了這個問題,而且我mapper接口以上的類的實例化是我自己通過java反射實例化的,我只有在Mapper接口的時候才加了@Mapper註解,導致的直接問題是,如果我如果在業務類中寫平常的@Resouce注入Mapper的話,mapper爲Null,這完全可以理解,因爲我的業務類並沒有加任何註解,沒有交給spring管理,是自己實例化的,這樣導致mapper無法注入,那我該如何調用mapper呢?哦吼!可以在業務類中申明一個mapper變量,然後在反射初始化時添加一個初始化方法
注意: 我討論的情況是一般的業務類是自己實例化,而一部分類交由spring管理
你可能會說:樓主有病吧?一部分自己實例化,一部分人家spring管理,豈不是很亂
非也,java反射是動態獲取類,實例化類的最初方法;
其次是從前的普通的springmvc項目,我們記得會有很多的配置文件,一個bean配置可以在初始化時添加你想要的屬性配置,
我們演化出了配置文件的方法;
現在的很多框架,比如springboot,springcloud等等都將這些工作自己處理,我們不必關心,寫的更多的是業務;
歸根到底,他們都是基於java反射的。
java反射的好處:你可以在代碼的層面上實例化你的特定類,比如根據模糊類名的方式實例化等等,並且在實例化中你可以做任何事情。
話不多說,我的情況是:
我實例化了com.skxx.work.busi包下的匹配接口的類,同時注意此處我添加了一個initMapper()方法,這個方法就是爲了給我的業務類配置mapper的。
再看我的業務類中:
我的UserLogic並沒有添加任何註解,之前說過,這個類是我自己通過上面的反射實例化的,並沒有交由spring管理
但是我的Mapper接口交由spring管理了,那我我們接下來如何獲取它呢?通過spring上下文,此處有一個工具方法來獲取你的上下文中的任何bean,上面的代碼和諸位其實關係並不大,只是爲了大家理解情況,下面的工具代碼就不是圖片了
這是我的mapper,它交由spring管理了:
工具類:通過上下文獲取任何已經實例化的bean
package com.skxx.config.spring;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @program: coalpreparation
* @description: 解決在多線程情況下,非註解實例化類時,無法注入mapper的問題
* 因爲類的實例化並不沒有交給spring,所以要自己手動去獲取mapper
* @author: Mr.MYR(ClearLoveQ)
* @create: 2020-04-21 14:24
**/
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringContextUtil.applicationContext == null) {
SpringContextUtil.applicationContext = applicationContext;
}
}
/**
* 獲取applicationContext
*
* @return
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 通過name獲取 Bean.
*
* @param name
* Bean's name
* @return
*/
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
/**
* 通過class獲取Bean.
*
* @param clazz
* @return
*/
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
/**
* 通過name,以及Clazz返回指定的Bean
*
* @param name
* @param clazz
* @return
*/
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
至此,我相信你對spring的理解可能更深一點了,祝大家在代碼的路上不斷前進。