web項目運行時(如JSON parse)手動注入@Autowired等註解的屬性值-1

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

有更好方案的小夥伴歡迎探討~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章