经验总结:jar包路径 以及 冲突问题

1、问题背景

    springcloud项目,在某个Module中,java对应mysql某个表的实体类

    随着项目的Module越来越多。每个Module都复制一遍这些实体类,就非常麻烦。因此将此实体类单独做成一个Module(Common-Entities),以后该工程下的任何Module,直接依赖即可

2、问题:

    springboot配置文件中的mybatis部分需要写实体类所在的包,以便扫描(application.yml文件)

(1)实体类和MyBatis相关业务 在一个Module中的时候,是这样写的: 

mybatis:
  mapper-locations: classpath:mybatis/mapper/*.xml #sql映射文件所在位置
  type-aliases-package: com.taoji666.entities #实体类所在的位置,这个项目是引用Common-Entities子工程的jar包

(2)现在将实体类独立成Module后,type-aliases-package 依然这样写,还是不报错。

结论:jar包不存在名称空间。你自己编写的路径和类名有一定几率和外部引入的jar包完全重名、

3、关于 import 关键字

由于IDE的强大,import一直都是IDEA帮你写,所以也很容易忽略import的具体内容。带着以上问题再去看import标签(注意看备注)

package com.taoji666.service;

import com.taoji666.entities.CommonResult; //本Module包
import com.taoji666.entities.Payment; //lib中的外部jar
import feign.Param; //lib中的外部jar
import org.springframework.cloud.openfeign.FeignClient; //lib中的外部jar
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService
{
    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);

    @GetMapping(value = "/payment/feign/timeout")
    public String paymentFeignTimeout();
}

再次确认:jar包没给名称空间

隐患:你自己编写的路径和类名有一定几率和外部引入的jar包完全重名。更可怕的是,你引入的外部jar包,也有几率出现包名类名完全一致。特别是同一资源的不同版本,比如同一项目引入了mysql的几个版本,junit的几个版本,,这些不同版本之间,很可能就出现包名,类名完全重复。

4、解决办法

(1)好好学习 Maven的 exclude(引入某个jar但是排除掉这个jar涉及的重复依赖),scope(依赖的作用范围,是否连续传递),optional(可选择的),这几个标签

https://blog.csdn.net/chengqingshihuishui/article/details/110453732(由于自己当时学习这个的时候,没得应用场景,因此笔记不全,需要各位自行百度补充)

举例:有 A、B(我的项目)、C 三个项目,已知,C依赖了DE,简写为C(DE)。我正在写B项目的Pom.xml

前提:这里的项目,就是纯粹指项目本身,不包含他们的依赖

(1.1)我在本项目B的pom中,写了C的dependency。 这是默认情况,B也会间接引用了D,以后A来引用我这个B时,也会间接引用了C和D

(1.2)我在本项目B的pom中,写了C的dependency,但是加上exclude D,这样B就不会引用D,但是还是会引用E,以后A来引用B时,也没有D,这时A中就有B、C、E

(1.3)我在本项目B的pom中,写了C的dependency,但是scope给一个provided

一旦使用provided,就意味着B项目肯定会被某个项目引用,假装是A项目。相当于B项目从从A中借了 一个C(DE)的依赖给你暂时用用,保证你写代码的时候有提示且不报错。,其实编译B项目,是不会编译这个C依赖的。

(1.4)我在本项目B的pom中,写了C的dependency,但是加了一个optional 为true。编译时,系统会判定,本项目B中到底用没用这个C,如果用了,就依赖。没用,就不依赖。传递给上级项目的时候,没有依赖的自动丢弃。

说明:比如本项目B要引入了三个数据库的依赖(mysql依赖,redis依赖,Oracle依赖),如果三个数据库都不写optional为true的标签(默认情况),那么三个数据库都会依赖了。但是如果写了这个标签,系统就会判定项目中没用到的数据库,就不依赖了,节约空间。B项目实际用的mysql依赖,那么系统就会加载mysql依赖,另外两个就丢弃。

当A项目要引用B的时候,就会有B的依赖+mysql依赖,其他没用optional丢弃。

(2)如果非同包名,同类名不可的话,通过改变编译器加载顺序来加载自己想要的类。编译器只会加载相同包名类名第一个类

因此:只有改变编译器优先选择的jar顺序(这个顺序是可以改变的),将想加载的类提前:

(2.1)在IDEA中,打开IDEA–>File–>ProjeofsoOTct Structure–>Modules

找到Dependencies,下面有一堆jar包,用 鼠标上下拖动即可将自己想提前编译的jar包排在前面

(2.2)在Eclipse中是在Java Build Path-》Order and Export里面,通过"up"/"down"按钮改变顺序,把jaxws-api.jar放在jdk的下面就可以了。