1 使用场景分析
项目中部分bean需要手动去创建,注入到spring容器中。通常我们可以直接手动new创建后通过@Bean注解注入进去。但是如果这个注入的bean中依赖spring容器中的对象,直接new无法注入。
当然,也可以在创建的时候先用@Autowire先获取到,然后通过setter赋值实现。该方案需要调用注入方法所在的bean被spring管理,不然无法通过@AutoWire注入依赖的成员变量
为了更加优雅并且满足更多的使用场景(注入bean的调用对象不一定需要spring管理),查阅资料后,整理了如下的方案。
2 实现思路
判断对象是否存在,存在则删除(可以根据实际场景进行取舍,也可以存在直接抛出异常)
获取实例对象的所有属性
判断属性是否为普通变量(非对象)
如果是,则从传入的初始化map中获取对应的值,进行赋值(没有则不赋值)
如果不是,则从spring容器中获取对应名称的实例化对象,并进行赋值
3 代码实现
核心方法为injectBean
package com.hz.bean.utils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Map;
/**
* @author pp_lan
* @description
*/
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext context = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
/**
* 获取spring容器中的bean
*
* @param beanName
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(String beanName, Class<T> clazz) {
if (context != null && context.containsBean(beanName)) {
return (T) context.getBean(beanName);
}
return null;
}
/**
* 获取容器中的参数
*
* @param key
* @return
*/
public static String getProperty(String key) {
return context == null ? null : context.getEnvironment().getProperty(key);
}
/**
* 注入bean
*
* @param clazz
*/
public static void injectBean(Class<?> clazz, Map<String, Object> initValueMap) {
initValueMap = (initValueMap == null ? Collections.EMPTY_MAP : initValueMap);
// 获取实例默认名称
String defaultInstanceName = getDefaultInstanceName(clazz);
ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) context;
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
// 移除已注册bean
if (context.containsBean(defaultInstanceName)) {
beanFactory.removeBeanDefinition(defaultInstanceName);
}
// 成员变量赋值
for (Field declaredField : clazz.getDeclaredFields()) {
String fieldName = declaredField.getName();
Class<?> type = declaredField.getType();
boolean isSimpleProperty = BeanUtils.isSimpleProperty(type);
if (!isSimpleProperty) {
Object value = SpringUtils.getBean(getCamelCase(type.getSimpleName()), type);
beanDefinitionBuilder.addPropertyValue(fieldName, value);
} else {
if (initValueMap.containsKey(fieldName)) {
Object value = initValueMap.get(fieldName);
if (value == null) {
continue;
}
beanDefinitionBuilder.addPropertyValue(fieldName, value);
}
}
}
// 注册bean
beanFactory.registerBeanDefinition(defaultInstanceName, beanDefinitionBuilder.getRawBeanDefinition());
}
/**
* 获取默认实例名称
*
* @param clazz
* @return
*/
private static String getDefaultInstanceName(Class<?> clazz) {
String simpleName = clazz.getSimpleName();
return getCamelCase(simpleName);
}
private static String getCamelCase(String simpleName) {
return simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
}
public static void main(String[] args) {
String user = getCamelCase("User");
System.out.println(user);
}
}
4 调用示例
@RequestMapping("/createBean")
@ResponseBody
public Response createBean() {
Map<String, Object> initValue = new HashMap<>();
initValue.put("id", "1234");
initValue.put("username", "zhangsan");
SpringUtils.injectBean(NewUser.class, initValue);
NewUser user = SpringUtils.getBean("newUser", NewUser.class);
Assert.notNull(user, "初始化失败");
return Response.ok(user);
}