サードパーティのJarパッケージを使用したSpringbootプロジェクトで発生した問題と解決策

1.背景紹介

複数のプロジェクトで共通のコードを抽出し、それをサードパーティのJarパッケージの形式で他のプロジェクトに提供して、メンテナンスコストを削減し、コードの冗長性を減らしたいと考えています。

抽出されたパブリックコードはSpringbootプロジェクトであり、パブリックJarパッケージを使用するものもSpringbootプロジェクトです。

Mybatisを使用して、データベース関連の操作を実装します。

2.質問の概要

2.1 Springboot自動スキャンは、jarパッケージ内のアノテーションBeanをスキャンできません

(1)jar内のクラスを使用し、このクラスに@Autowiredアノテーションが挿入されたbaseRedisDaoという名前のBeanがあり、jar内のクラスオブジェクトがjarを使用するプロジェクトで新しく作成され、baseRedisDaoがnullであることが判明しました。

サードパーティのJarパッケージのSingleCaseDebugAPIクラス

public class SingleCaseDebugAPI {
    @Autowired
    BaseRedisDao baseRedisDao;

    @Autowired
    GatewayCasePbService gatewayCasePbService;

    @Autowired
    GatewayCaseModuleService gatewayCaseModuleService;

    @Autowired
    GatewayCaseUserService gatewayCaseUserService;

サードパーティのJarパッケージで提供されている方法を使用します

@RequestMapping(value = "debugCase", method = RequestMethod.POST)
public ResMsg debugCase(@RequestBody JSONObject requestBodyParameters) {
    ResMsg resMsg = new ResMsg();
    System.out.println("前端传过来的用例内容:" + requestBodyParameters);
    boolean isShowDev = requestBodyParameters.getBooleanValue("isShowDev");

    if(isShowDev){
       System.out.println("开发人员调试接口:"  +isShowDev);
       DebugAPI debugAPI = new DebugAPI();
       resMsg = debugAPI.debugAPIForDev(requestBodyParameters);
     }else {
       System.out.println("测试人员调试用例:" + isShowDev);
       // 错误写法,不应该new对象
       SingleCaseDebugAPI singleCaseDebugAPI = new SingleCaseDebugAPI();
          resMsg = singleCaseDebugAPI.singleCaseDebug(requestBodyParameters);
        }
       System.out.println("resMsg status:" + (resMsg.getStatus()));
       System.out.println("resMsg data:" + (resMsg.getData()));
       System.out.println("222222222" + JSONObject.toJSONString(resMsg));
       return resMsg;
}

理由:
@Autowiredアノテーションを使用してBeanインスタンスをコンテナーに注入すると、管理のためにSpringbootに渡されます。また、新しいインスタンスはSpringbootの管理外であり、2つは同じマネージャーの管理下にないため、できません。一緒にリンクされます。したがって、@ AutowiredインジェクションBeanを使用するとnullになります

解決策:
新しい方法でオブジェクトをインスタンス化しないでください。また、注釈も使用してください。newが必要なインスタンスクラスに@Componentアノテーションを追加し、依存性注入を通じてインスタンス化されたクラスを使用します

変更されたSingleCaseDebugAPIクラス

@Component
public class SingleCaseDebugAPI {
    @Autowired
    BaseRedisDao baseRedisDao;

    @Autowired
    GatewayCasePbService gatewayCasePbService;

    @Autowired
    GatewayCaseModuleService gatewayCaseModuleService;

    @Autowired
    GatewayCaseUserService gatewayCaseUserService;

サードパーティのJarパッケージのコードを正しく使用して、インターフェースを提供します

@RestController
@RequestMapping(value = "api/umeapiplus/action")
@Component
public class ActionController {
    private final static Gson gson = new Gson();
    private final Logger logger = LoggerFactory.getLogger(ActionController.class);

// 以@Autowired注解方式拿到 singleCaseDebugAPI bean
    @Autowired
    public SingleCaseDebugAPI singleCaseDebugAPI;

    @RequestMapping(value = "debugCase", method = RequestMethod.POST)
    public ResMsg debugCase(@RequestBody JSONObject requestBodyParameters) {
        ResMsg resMsg = new ResMsg();
        System.out.println("前端传过来的用例内容:" + requestBodyParameters);
        boolean isShowDev = requestBodyParameters.getBooleanValue("isShowDev");

        if(isShowDev){
            System.out.println("开发人员调试接口:"  +isShowDev);
            DebugAPI debugAPI = new DebugAPI();
            resMsg = debugAPI.debugAPIForDev(requestBodyParameters);
        }else {
            System.out.println("测试人员调试用例:" + isShowDev);
            resMsg = singleCaseDebugAPI.singleCaseDebug(requestBodyParameters);
        }

        System.out.println("resMsg status:" + (resMsg.getStatus()));
        System.out.println("resMsg data:" + (resMsg.getData()));
        System.out.println("222222222" + JSONObject.toJSONString(resMsg));
        return resMsg;
    }
}

(2)上記の問題を解決した後、@ Autowireアノテーションが付けられたBeanはまだ使用できず、値はまだnullであることがわかりました。その後、SpringbootがスキャンしなかったのはサードパーティのJarのBeanの問題が原因であることが判明しました。

解決策:
@SpringBootApplicationアノテーションのscanBasePackages属性を使用して、サードパーティのjarパッケージと独自のプロジェクトパッケージのパスを含む、Springbootによってスキャンされるパッケージパスを指定します。指定しない場合、デフォルトでは、スタートアップクラスとその子の下にある@ Component、@ Service、およびその他のアノテーションのみがスキャンされます。

@SpringBootApplication(scanBasePackages = {"com.umetrip.qa","com.taobao.rigel.rap"}, exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, SecurityAutoConfiguration.class })
public class UmeApiPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(UmeApiPlusApplication.class, args);
    }
}

(3)手順2での変更後、アノテーションBeanがnullになる問題は最終的に解決されましたが、サードパーティのjarパッケージでデータベース関連のメソッドを使用すると、次のエラーが報告されます。
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.umetrip.qa.mapper.GatewayCaseModuleMapper.findGatewayCaseModuleByrpid
このエラーは通常、次の原因によるものです。マッパーインターフェイスクラスとマッパーxmlファイルが原因に対応していません。コードを注意深くチェックし、間違った場所を見つけられなかったため、マッパーxmlファイルをプロジェクトにロードしていないことが原因であると感じています。 jarパッケージ

解決:

プロジェクトのスタートアップクラスで@MapperScanアノテーションを使用して、サードパーティのjarパッケージとこのプロジェクトのマッパーインターフェイスクラスのパッケージアドレスを指定します

@SpringBootApplication(scanBasePackages = {"com.umetrip.qa","com.taobao.rigel.rap"}, exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, SecurityAutoConfiguration.class })
@ServletComponentScan
@MapperScan(basePackages = {"com.umetrip.qa.mapper", "com.taobao.rigel.rap.mapper"})
public class UmeApiPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(UmeApiPlusApplication.class, args);
    }
}

application.properties構成ファイルを変更します

  • classpath *は、jarパッケージにインポートされたマッパーxmlファイルをロードすることを意味します
  • サードパーティのjarに保存されているxmlファイルのパッケージ名には、認識できない特殊文字を含む「mybatis-mapper」という名前を付けないでください。
mybatis.mapper-locations=classpath*:/mapper/**/*.xml

おすすめ

転載: blog.csdn.net/sinat_34241861/article/details/112844954