Springboot工程使用第三方Jar包遇到的问题及解决办法

一、背景介绍

我想把多个项目中通用的代码抽离出来,以第三方Jar包形式提供给其他工程使用,减少维护成本,减少代码冗余。

抽离出来的公共代码是一个Springboot工程,使用该公共Jar包的也是Springboot工程。

使用Mybatis实现数据库相关操作。

二、问题汇总

2.1 Springboot自动扫描无法扫描jar包中的注解bean

(1)使用jar里的类,该类里存在使用了@Autowired注解注入的名为baseRedisDao的bean,在使用该jar的工程中new出来一个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管理;而new出来的实例脱离了Springboot的管理,二者不在一个管理者管理下,所以没法联系在一起。因此使用@Autowired注入的bean时就会为null

解决办法:
不要用new的方式实例化对象,也采用注解的方式。在需要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属性指定Springboot扫描的包路径,包括第三方jar包和自身工程包的路径。如果不指定的话,默认只会扫描启动类同级及其子级下的@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
这个错误一般都是由于mapper接口类与mapper xml文件对应不上导致的,我仔细检查了代码并未发现错误的地方,所以感觉还是由于使用jar包时没有将mapper的xml文件加载至工程中导致的

解决办法:

在工程启动类上使用@MapperScan注解,指定第三方jar包及本工程的mapper接口类所在包地址

@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包中的mapper xml文件
  • 注意第三方jar中存放xml文件的包名千万不要命名成“mybatis-mapper”这种含有特殊字符的名称,无法识别
mybatis.mapper-locations=classpath*:/mapper/**/*.xml

猜你喜欢

转载自blog.csdn.net/sinat_34241861/article/details/112844954