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