Manually create an instance in Spring (the object contains injected member variables)

1 Usage scenario analysis

  • Some beans in the project need to be created manually and injected into the spring container. Usually we can directly create new manually and inject it through @Bean annotation. But if the injected bean depends on objects in the spring container, direct new cannot be injected.

  • Of course, you can also use @Autowire to get it first when creating, and then assign it through setter. This solution requires that the bean where the injection method is called is managed by spring, otherwise dependent member variables cannot be injected through @AutoWire.

In order to be more elegant and meet more usage scenarios (the calling object injected into the bean does not necessarily need spring management), after reviewing the information, the following solution was compiled.

2 Implementation ideas

  • Determine whether the object exists, and delete it if it exists ( you can choose based on the actual scenario, or you can directly throw an exception )

  • Get all properties of instance object

  • Determine whether the attribute is an ordinary variable (non-object)

  • If so, get the corresponding value from the incoming initialization map and assign it (if not, do not assign it)

  • If not, obtain the instantiated object of the corresponding name from the spring container and assign it

3 code implementation

The core method is 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 Call example

@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);
}

5 call results

Guess you like

Origin blog.csdn.net/pp_lan/article/details/128662143