为什么Spring Boot 项目打包成的 jar ,被其他项目依赖之后,总是报找不到类的错误?
大伙有这样的疑问,就是因为还没搞清楚可执行 jar 和普通 jar 到底有什么区别?
Spring Boot 中默认打包成的 jar 叫做 可执行 jar,这种 jar 不同于普通的 jar
普通的 jar 不可以通过 java -jar xxx.jar
命令执行,普通的 jar
主要是被其他应用依赖,Spring Boot
打成的 jar
可以执行,但是不可以被其他的应用所依赖,即使强制依赖,也无法获取里边的类。
所以,如果要打成一个可以被其他项目依赖的jar包,pom文件里的build模块就不能写成:
org.springframework.boot
spring-boot-maven-plugin
以下两种写法都是可以的:
方法一:直接使用传统maven打包插件
org.apache.maven.plugins
maven-compiler-plugin
1.8
方法二:直接使用传统maven打包插件
org.springframework.boot
spring-boot-maven-plugin
exec
配置的 classifier
表示可执行 jar
的名字,配置了这个之后,在插件执行 repackage
命令时,就不会给 mvn package
所打成的 jar
重命名了,所以,打包后的 jar 如下:
第一个 jar 表示可以被其他项目依赖的 jar ,第二个 jar 则表示一个可执行 jar。
------------------------------------ springboot 引入第三方jar包中定义的bean -------------------------------
springboot工程引入第三方jar包中定义的bean,只需要2步即可:
1、引入的jar包,必须是可以被依赖的包,如果是springboot框架打的jar包,不能使用默认的打包插件直接打包
2、如何把已经引入的依赖中的bean载入容器中呢?
方法一:比如在jar包定义的一个拦截器,在新的项目中重新载入
@Configurationpublic class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
}
}
这里存在一个问题:做了2次bean的载入 (不推荐这个方法)
方法二:
SpringBoot项目的Bean装配默认规则是根据Application类所在的包位置从上往下扫描!Application类是指SpringBoot项目入口类。
这个类的位置很关键: 如果Application类所在的包为:com.openplat,则只会扫描com.openplat包及其所有子包,如果mapper、service所在包不在com.openplat及其子包下,则不会被扫描。
即, 把Application类放到mapper、service所在包的上级,com.openplat.OpenPlatApplication
知道这一点非常关键,不知道Spring文档里有没有给出说明,如果不知道还真是无从解决
所以这里可以使用@SpringBootApplication(scanBasePackages = {"com.ccb","com.example"}),使用其中com.ccb是本地多模块的包的统一前缀,com.example是引用的第三方jar包bean所在的路径,这样springboot就可以扫描到第三方的bean,进行加载,不用在针对第三方jar包中定义的bean重新进行操作,就可以直接使用了
实例:引入第三方jar包中定义的一个拦截器 interceptor
1、新建一个maven项目,定义一个拦截器
/**
* @Description: 新建一个拦截器
* @Author: Top
* @Version: V1.0
* @Date: 2020/6/11 9:34 上午
*/
@Slf4j
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler)
throws Exception {
log.info("preHandle:请求前调用");
//返回 false 则请求中断
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("postHandle:请求后调用");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
log.info("afterCompletion:请求调用完成后回调方法,即在视图渲染完成后回调");
}
}
2、注册拦截器到Spring容器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
}
}
3、打包该maven工程为一个可以依赖的jar包
4、在新的项目中引入依赖
com.example
demo
0.0.9-SNAPSHOT
5、修改新项目的启动类的注解SpringBootApplication,添加红色部分,使该项目可以扫描到第三方引入jar包中的bean,
@SpringBootApplication(scanBasePackages = {"com.ccb","com.example"})
6、到这里,在新的项目中,引入第三方jar包中的拦截器已经注入到容器中生效,可以进行拦截了。这里有一个要注意的点,如果被引用的jar包中已经做了注册操作(也就是做了第2步的操作),那这里第5步就可以了;如果在原项目中,只是定义了拦截器,没有注册操作(没有进行步骤2的操作),那么在新的系统引入该jar包之后,除了第5步添加扫描,还要进行注册该拦截器,才可以生效。
参考资料:
https://segmentfault.com/a/1190000019706787