クラスを取得して呼び出す方法を反射することで@Autowired注入が無効になるソリューション

3567 ワード

引用する
最近、同社のプラットフォームプロジェクトを最適化しているが、このプラットフォームはto Bの性質であるため、コードを向上させ、より柔軟にするためにカスタマイズ開発する必要があるため、反射が用いられているが、使用中に@Autowiredの失効問題に遭遇した.
問題解決:
実際にこの問題が発生した原因は簡単ですが、取得したクラスがspringコンテナ管理に組み込まれていないため、エラーコードを見てみましょう.
反射コードは次のとおりです.
                 //       
                String className ="M1CallBackService";
                Class c = Class.forName(packagePath + className);
               
                Method m = c.getMethod("callBack", new Class[]{Integer.class});
                //    
                Object[] arguments = new Object[]{new Integer(robotServiceInfo.getRobotId())};
                m.invoke(c.newInstance(), arguments);

反射によってクラスを取得する方法の一部のコード:
 @Autowired
    private NativeSqlMapper nativeSqlMapper;
    @Autowired
    private EmailService emailService;

    /**
     * @Description: 
     * @author: zhenghao
     * @date: 2019/12/13 14:56
     */
    public void callBack(Integer robotId) {

        String dateStr = DateUtils.getToDayYYYYMMDD();
        List excelSheetModelList = new ArrayList<>();

        //       
        List> callbackDaily = this.getDailyCallbackData(robotId);
        if (callbackDaily == null || callbackDaily.isEmpty()) {
            log.info("          ...");
        } else {

。。。。。。。。

上記のコードを実行すると、クラス内のcallBackメソッドは正常に取得できますが、debugがこのメソッドに入ると、@Autowiredで注入されたクラスが空であることがわかります.
反射中のコードを見ると、クラスを得る方法はclassです.新InstanceではSpringコンテナに関連付けられてbeanを取得する書き方はありませんが、クラスに@Autowiredというように注入されたオブジェクトがあれば空になります.
ソリューション:
エラーの原因を知っていれば、解決は簡単です.classを通過しないでください.新Instance方式で取得するのではなく、手動でspringコンテキストで取得すればこの問題を解決できます.修正後の反射コード
 String className ="M1CallBackService";
                Class c = Class.forName(packagePath + className);
                Object obj = ApplicationContextHelper.popBean(c);
                Method m = c.getMethod("callBack", new Class[]{Integer.class});
                //    
                Object[] arguments = new Object[]{new Integer(robotServiceInfo.getRobotId())};
                m.invoke(obj, arguments);

springコンテキストからクラスを手動で取得するコードが追加されました.
ツールクラスコードは次のとおりです.
package com.jack.common.utils.service;

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

/**
 * @Description:   bean
 * @author: zhenghao
 * @date: 2019/12/14 12:04
*/
@Service
public  class ApplicationContextHelper implements ApplicationContextAware {
 
    private static ApplicationContext applicationContext;
 
    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
 
        applicationContext = context;
    }
 
    /**
     *   bean
     * @param clazz
     * @param 
     * @return
     */
    public static  T popBean(Class clazz) {
        //       
        if (applicationContext == null) {
            return null;
        }
        return applicationContext.getBean(clazz);
    }
 
 
    public static  T popBean(String name, Class clazz) {
        if (applicationContext == null) {
            return null;
        }
 
        return applicationContext.getBean(name, clazz);
 
    }
}

小結
これで、この問題を解決しました.問題に遭遇したら、まず問題の原因を分析して、それから病状に応じて薬を飲んで、すぐに解決することができます.