springboot中 利用java反射調用Service,注入Dao接口爲null

1、反射簡介
反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;
對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及
動態調用對象的方法的功能稱爲java語言的反射機制。
2、問題:
在項目中打算做一個通用的導出方法,但是這個方法是寫在一個普通的工具類中的,這個工具類中我們通過使用反射的方法去調用其他的service層,通過service層插入數據庫實體對象,但是serviceImpl中的dao接口對象卻爲空。經過調查由於使用反射,導致dao注入失敗。原因是自動裝配是在 spring環境下當使用該類的實例時由spring容器完成了類的實例化過程,當然包括對依賴對象的實例化過程而通過反射創建實例時,是根據你調用的構造函數完成的實例化過程,沒有 容器的自動化創建實例了,所以需要自己對依賴對象進行注入。所以依賴spring容器實例化
和自己用反射實例化是兩種獨立的方式,不能相互滲透的。
3、代碼解析
a:原本我們使用反射調用service層錯誤的方式

         Class<?> classType = Class.forName(serviceClass);
         Method m = classType.getDeclaredMethod("method名稱",new Class[]{parameters.class});
         List<?> list = m.invoke(classType.newInstance(),parameters);

注意:這裏我們就是使用classType.newInstance()方法纔會使service中的dao注入失敗。

b:正確的方法,通過spring容器取得對象

          WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
          Class<?> classType = Class.forName(serviceClass);
          Method m = classType.getDeclaredMethod("method名稱",new Class[]{parameters.class});
          List<?> list = m.invoke(wac.getBean("service的id對象名稱"),parameters);

4、以上的代碼是別人spring的代碼,由於本人是用springboot,所以重新寫了下代碼。
(1)、工具類:SpringBootBeanUtil.java


import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * SpringBoot 普通類獲取Spring容器中的bean工具類
 * @author lvgang
 */
@Component
public class SpringBootBeanUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringBootBeanUtil.applicationContext == null) {
            SpringBootBeanUtil.applicationContext = applicationContext;
        }
        System.out.println("========ApplicationContext配置成功========");
        System.out.println("========在普通類可以通過調用SpringBootBeanUtil.getApplicationContext()獲取applicationContext對象========");
        System.out.println("========applicationContext="+ SpringBootBeanUtil.applicationContext +"========");
    }

    /**
     * 獲取applicationContext
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 通過name獲取 Bean.
     * @param 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);
    }

}

(2)調用:forName中的爲自己獲取並拼接的類地址

try {
            //從ApplicationContext中取出已創建好的的對象
            //不可直接反射創建serviceimpi對象,因爲反射創建出來的對象無法實例化dao接口
            ApplicationContext applicationContext = SpringBootBeanUtil.getApplicationContext();
            //反射創建serviceimpi實體對象,和實體類
            Class<?> ServiceImplType = Class.forName(GlobalParams.REF_SERVICE+className+"ServiceImpl");
            Class<?> entityType = Class.forName(GlobalParams.REF_ENTITY+className);
            //反射設置方法參數。
            Method method = ServiceImplType.getDeclaredMethod("Insert",entityType);
            //在ApplicationContext中根據class取出已實例化的bean
            method.invoke(applicationContext.getBean(ServiceImplType),className);

            } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                e.printStackTrace();
                return GlobalResult.resOk("個性化表單數據插入失敗");
            }
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章