1.需求:通過JSON parse成具體對象,對象中有@Autowired,@Resource註解的屬性如何注入?
Spring Bean管理的Spring註解的@Autowired或者@Resource屬性在項目啓動時會交由Spring自動注入具體的屬性值,如果我不將Bean交由Spring管理,正常情況下@Autowired,@Resource註解也不會起作用,如何在運行時手動注入被加上@Autowired或者@Resource的屬性呢?
2.方案探討
(1)創建一個被Spring管理的bean,bean中有很多@Autowire的屬性,在JSON.parseObject後通過BeanUtils.copyProperties()將屬性值copy過來
(2)在構造方法中加入通過applicationContext.getBean(“beanName”)獲取到Spring Bean給當前註解屬性賦值
(3)拿到當前類的所有屬性,再拿到用@Autowired或者@Resource註解的屬性,再拿到屬性的類型通過applicationContext.getBean(beanType)獲得到Spring Bean給當前註解屬性賦值
3.方案實行
(1)方案1比較簡單,略過
(2)方案2:
SpringContextUtil :
/**
* Created by Kowalski on 2017/7/27
* Updated by Kowalski on 2017/7/27
*/
public class SpringContextUtil implements ApplicationContextAware{
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
public static Object getBean(Class requiredType) throws BeansException {
return applicationContext.getBean(requiredType);
}
}
TestBean :
public class TestBean {
@Autowired
private TestInterface testInterface;
TestBean() {
this.testInterface= (TestInterface) SpringContextUtil.getBean("testInterface");
}
}
(3)方案3:
最終 我們採用了方案3,因爲維護起來比較方便
Utils:簡易版
/**
* Created by Kowalski on 2017/7/27
* Updated by Kowalski on 2017/7/27
*/
@Slf4j
public class Utils {
public static void initServce(Object object){
/**獲得所有屬性(包括私有不包括父類)*/
Field[] fields = object.getClass().getDeclaredFields();
for(Field field:fields){
if(field.getAnnotation(Autowired.class) != null || field.getAnnotation(Resources.class) != null){
/**可設置私有屬性*/
field.setAccessible(true);
/**拿到單例Service 放入對象屬性中*/
try {
field.set(object, SpringContextsUtil.getApplicationContext().getBean(field.getType()));
}catch (IllegalAccessException e){
log.error("Utils initServce IllegalAccessException:{}", e);
}catch (Exception e){
log.error("Utils initServce set filed:{} failed:{}", field.getType(), e);
}
}
}
}
}
Utils:增加本地緩存版
/**
* Created by Kowalski on 2017/7/27
* Updated by Kowalski on 2017/7/27
* 活動引擎工具類
*/
@Slf4j
public class Utils {
/**靜態緩存*/
private static final ConcurrentMap<Class<?>, ConcurrentMap<Field, Object>> map = new ConcurrentHashMap<Class<?>, ConcurrentMap<Field, Object>>();
/**
* 初始化bean時(如json parse)注入Service屬性
* 放在構造方法中初始化(Utils.initServce(this);)
* @param object
*/
public static void initServce(Object object) {
Map<Field, Object> filedsBeansFromMap = map.get(object.getClass());
if (filedsBeansFromMap != null) {
/**遍歷Filed與Spring Bean對應關係*/
for (Map.Entry<Field, Object> filedsBeans : filedsBeansFromMap.entrySet()) {
try {
filedsBeans.getKey().set(object, filedsBeans.getValue());
} catch (IllegalAccessException e) {
log.error("Utils initServce IllegalAccessException:{}", e);
}
}
return;
}
/**獲得所有屬性(包括私有不包括父類)*/
Field[] fields = object.getClass().getDeclaredFields();
/**Filed與Spring Bean對應關係*/
ConcurrentMap<Field, Object> tofiledsBeansMap = new ConcurrentHashMap<Field, Object>();
for (Field field : fields) {
/**只針對Autowired 與 Resources註解屬性使用*/
if (field.getAnnotation(Autowired.class) != null || field.getAnnotation(Resources.class) != null) {
try {
/**設置私有屬性可寫*/
field.setAccessible(true);
/**拿到單例Service 放入對象屬性中*/
Object bean = SpringContextsUtil.getApplicationContext().getBean(field.getType());
/**給屬性賦值*/
field.set(object, bean);
tofiledsBeansMap.putIfAbsent(field, bean);
} catch (IllegalAccessException e) {
log.error("Utils initServce IllegalAccessException:{}", e);
} catch (Exception e) {
log.error("Utils initServce set filed failed:{}", e);
}
}
}
map.putIfAbsent(object.getClass(), tofiledsBeansMap);
}
}
TestBean :
public class TestBean {
@Autowired
private TestInterface testInterface;
TestBean() {
Utils.initServce(this);
}
}
有更好方案的小夥伴歡迎探討~~