面试题and开发问题(1)

1、面试题:前置++ 和后置++的区别?

请添加图片描述

2、面试题一个XXX.java文件中可以有多个类吗

答:可以,但是只能有一个**公共**的类(使用public 修饰的类)

有多少个类就会生成几个class类

3、面试题:char类型能存储汉字吗?**

​ 能,因为一个汉字是两个字节
char字符变量可以存储两个字节 就是在内存中占用2个字节
任何字符在内存中都是以数字的形式存储的。

4、请问:下边的代码执行的结果是什么?

short  a=5;
a =a+5;
System.out.println(a)

a本身就是short类型 但是a+5这个5是默认int型的 就是d+5的结果也是int 类型 int类型赋值给short类型 大到小会爆错

请问:下边代码执行的结果是?

 short a=5;
    a+=5;//a=a+5;
    System.out.print(a); //a=(short)(a+5) 此时发生了数据类型强转  编译器自己进行的

5、什么是方法重载?

一个类中可以有很多个相同名字的方法,并且这些方法中参数列表不同(参数个数不同,顺序不同,类型不同),这就是方法重载。

6、字符串类

String str=“abc”;
问、这句代码创建了几个对象。
答:0个或一个;

String str=new String(“abc”);
问、这句代码创建;1几个对象?

答 : 一个或者两个。

7、问String StringBuffer StringBuilder 的区别是?

StringBuilder 是线程不安全的 如果不要求线程就使用StringBuilder

String 和StringBuffer是线程安全的

String的不可变,是指String的属性不可变。

速度:StringBuilder > StringBuffer > String。

  • 后台都是一个char数组放的 但是String的char 数组是 final修饰的,不可被继承,避免了子类覆盖父类重写的风险 这是String是不可变的一个条件 (其实被final修饰只是代表他不能指向新的数组没有保障本身的数据被改变
    StringBuffer在底层是同步的所以安全些但是同步会慢一点 ,而StringBuild没有锁所以 StringBuild快
    在这里插入图片描述

  • String是被private修饰的,没有暴露出去,也没有提供去修改数组的方法,操作字符串的方法都是返回一个新的对象 (条件二)

7.1、String为什么要不可变

java中有一个东西 ,叫字符串常量 String pool 在堆中开辟一块存储空间

  • SharedSecrets

8、给对象中的属性赋值有几种方式?

	1. set方法
	2. 构造方法
	3. 如果不是private修饰可以直接赋值
	4. 通过反射!(java高级特性,一切框架的灵魂!)
	5. 

8、jsp九大内置对象

  1. request 请求对象
  2. response 响应对象
  3. PageContext 页面上下文对象
  4. session 会话对象
  5. application 应用程序对象
  6. out 输出对象
  7. config配置对象
  8. page 页面对象
  9. Exception 异常对象

9、servlet生命周期

  1. init() 初始化
  2. service()调用service
  3. destroy() 销毁

10、spring默认连接池

HikariCP连接池(效率最高)Hikari只有130kb大小

11、==和equals的区别

==比较的是引用地址是否相同
equals比较的是内容(值)是否相同
equals底层也是双 等于 但是string重写啦equals方法

12、mybatis中 # 和 $的区别

#号可以避免SQL注入 使用#的 相对于是一个预编译的SQL语句
KaTeX parse error: Expected 'EOF', got '#' at position 13: 不是预编译的 一般能用#̲就别用

13、控制反转是?

吧创建对象的权利给容器控制
spring来负责控制对象的生命周期和对象间的关系

14、乐观锁和悲观锁++++++++

乐观锁:
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是 在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和 CAS 算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类 似于 write_conditio 机制,其实都是提供的乐观锁。在 Java 中 java.util.concurrent.atomic 包下面的原子变量类就是使用了乐观锁的一种实现方式 CAS 实现的。

悲观锁:
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时 候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使 用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了 很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java 中 synchronized 和 ReentrantLock 等独占锁就是悲观锁思想的实现。

同步锁:
当多个线程同时访问同一个数据时,很容易出现问题。为了避免这种情况出现,我们要 保证线程同步互斥,就是指并发执行的多个线程,在同一时间内只允许一个线程访问共享数 据。Java 中可以使用 synchronized 关键字来取得一个对象的同步锁。

死锁:
何为死锁,就是多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。

15、重载和重写的区别

重写就是子类吧父类的的方法重写写一遍 (方法名参数列表返回值必须一样)

重载是在一个类中可以同时有多个同名但参数列表不同的方法

16、ArrayList的扩容

优点: 底层数据结构是数组,查询快,增删慢。 缺点: 线程不安全,效率高

ArrayList的 扩容其实是把原来的数组复制到另一个内存空间更大的数组中
底层还是一个数组
一般扩容为 1.5倍

17、Spring默认提供的连接池

  • List item

18、悲观锁(行级锁 for update)和乐观锁的概念

for update 行级锁(悲观锁) 当前事务没有结束时 不能修改数据

悲观锁:事务必须排队执行。数据锁住了,不允许并发 (低并发)(在select 后面添加for update)

乐观锁:支持并发(高并发),事务不需要排队,只不过需要另一个版本号的 吧数据

19、 forward(转发)和redirect(重定向)的区别和对服务器请求的区别

参考文 章

1> 重定向 2 次请求,请求转发 1 次请求
2> 重定向地址栏会变,请求转发地址栏不变
3> 重定向是浏览器跳转,请求转发是服务器跳转
4> 重定向可以跳转到任意网址,请求转发只能跳转当前项目

转发
客户浏览器发送http请求——》web服务器接受此请求——》调用内部的一个方法在容器内部完成请求处理和转发动作——》将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。

重定向
客户浏览器发送http请求——》web服务器接受后发送302状态码响应及对应新的location给客户浏览器——》客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址——》服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。

重定向时浏览器上的网址改变
转发是浏览器上的网址不变

区别

  1. 从地址栏显示来说
    forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.
    redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
  2. 从数据共享来说
    forward:转发页面和转发到的页面可以共享request里面的数据.
    redirect:不能共享数据.
  3. 从运用地方来说
    forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
    redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等
  4. 效率
    forward:高.
    redirect:低.
    df

20、双亲委派机制

四种类加载器

  • bootstrapclassLoader 引导类加载器
  • extensionClassLoader 扩展类加载器
  • applicationClassLoader 应用加载器 或者 系统加载器
  • CustomClassLoader 自定义类加载器

概念 :
当某个类加载器 需要加载某个.class文件时 ,它先吧这个任务委托给他的上级类加载器 递归这个操作 如果上级类加载器没有加载 ,自己才会去加载这个类

作用

  1. 防止重复加载同一个 。class文件 通过委托去向上问 ,加载过了就不在加载 保证数据安全
  2. 保证核心, 。class不能篡改。 通过委托 方式 不会去篡改核心 即使篡改也不会去加载,即使加载也不会是同一个。class对象了。不同的加载器加载同一个。class 也不是同一个class对象,这样保证class执行安全

双亲委派机制是可以被打破的
注意他们不是继承关系

21、instanceof 关键字的作用

  • 对象是类的实例吗?
  • 对象是类的子类的实例吗?
  • 对象是实现特定接口的实例吗?

instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:

boolean result = obj instanceof Class

其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。

注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。

 i = 0; 
 System.out.println(i instanceof Integer);//编译不通过 i必须是引用类型,不能是基本类型 
 System.out.println(i instanceof Object);//编译不通过 
 Integer integer = new Integer(1); 
 System.out.println(integer instanceof Integer);//true

在这里插入图片描述

//false ,在 JavaSE规范 中对 instanceof 运算符的规定就是:如果 obj 为 null,那么将返回 false。 
System.out.println(null instanceof Object);

22、封装类和基本数据类型,使用场景

java有八大基本数据类型,为每个基本数据类型类型都提供了对应的封装类,是对基本数据类型的使用提供了一个增强性的类型,封装类型之间不能进行强转

在对象中可以定义更多的功能方法操作该数据;
编码过程中只接收对象的情况,例如集合中只能存入对象,不能存入基本数据类型;
泛型不支持基本数据类型。

基本数据类型和封装类型

基本数据类型:存放的是值,存放在栈中;但作为方法中的局部变量,存放在堆中;
对象类型(封装类型):Integer是对对象的引用,对象存放在堆中;

栈的存取速度比堆快,仅次于直接位于CPU的寄存器;

int和Integer
int 的默认值为 0,而 Integer 的默认值为 null,即 Integer 可以区分出未赋值和值为 0 的区别,int 则无法表达出未赋值的情况,
例如,要想表达出没有参加考试和考试成绩为 0 的区别,则只能使用 Integer。
在 JSP 开发中,Integer 的默认为 null,所以用 el 表达式在文本框中显示时,值为空白字符串,而 int 默认的默认值 为 0,所以用 el 表达式在文本框中显示时,结果为 0,所以,int 不适合作为 web 层的表单数据的类型

23、java为什么要基本数据类型

性能,性能,还是性能

24、使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。

在这里插入图片描述
在这里插入图片描述

25、replace和replaceAll(replaceAll第一个值应该为正则表达)

1)replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串序列的意思,说白了也就是字符串);

2)replaceAll的参数是regex,即基于正则表达式的替换,比如,可以通过replaceAll(“\d”, “*”)把一个字符串所有的数字字符都换成星号;

版权声明:本文为CSDN博主「之子于归–」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/anmoyyh/article/details/70673812

26、CAS

来自公众号 对线面试官
CAS全程 compare and swap,⽐较并交换

CAS的操作是:
有三个值 当前值A、内存值V、要修改的新值B
假设 当前值A 跟 内存值V 相等,那就将 内存值V 改成B
假设 当前值A 跟 内存值V 不相等,要么就重试,要么就放弃更新
将当前值与内存值进⾏对⽐,判断是否有被修改过,这就是CAS的核⼼

在这里插入图片描述

为什么要用CAS

不加synchronized锁的时候在使用,就是没有多线程的时候可以Atomic下的类,因为synchronized的速度会降低

CAS的问题ABA问题

  • CAS只对比当前值是否和内存相等如果出现
  • 线程A读的当前值是10,线程B可能吧值修改为100,然后c又把值修改为10
  • 等A在拿到执行权的是时候,当前值和内存值一直,线程A就是可以修改的
  • 对应A来说这个值没有变,但对于从上帝视角的我们来看这个变量已经被B和C修改过了

在这里插入图片描述

解决ABA问题

AtomicStampedReference类
Java也提供了AtomicStampedReference类供我们⽤,说⽩了就是加了个版本,⽐对的就是内存值+版本是否⼀致
其中的一个方法

    /**
    如果当前引用==为预期引用,并且当前戳等于预期戳,则原子化地将引用和戳的值设置为给定的更新值。
	可能会错误地失败,并且不提供排序保证,因此很少是compareAndSet的合适替代方案。
	参数:
	expectedReference–引用的预期值newReference–引用新值expectedStamp–邮票的预期值newStamp–印章新值
	退货:
	如果成功,则为true
     */
    public boolean weakCompareAndSet(V   expectedReference,
                                     V   newReference,
                                     int expectedStamp,
                                     int newStamp) {
        return compareAndSet(expectedReference, newReference,
                             expectedStamp, newStamp);
    }

Web

1、Get和Post的区别

  1. Get 是不安全的,因为在传输过程,数据被放在请求的 URL 中;Post 的所有操作对用户 来说都是不可见的。
  2. Get 传送的数据量较小,一般传输数据大小不超过 2k-4k(根据浏览器不同,限制不一样, 但相差不大这主要是因为受 URL 长度限制;Post 传送的数据量较大,一般被默认为不受限 制。
  3. Get 限制 Form 表单的数据集的值必须为 ASCII 字符;而 Post 支持整个 ISO10646 字符 集。
  4. Get 执行效率却比 Post 方法好。Get 是 form 提交的默认方法。

2、TCP的粘包、拆包以及解决方案

参考文章
1。。。。。。。。。。
2。。。。。。。。。。

UDP没有粘包、拆包,因为UDP首部采用了16bit来指示UDP数据报文的长度,所以应用层能很好的将不同的数据报文区分开

因为TCP是面向流,没有边界,而操作系统在发送TCP数据时,会通过缓冲区来进行优化,例如缓冲区为1024个字节大小。

  • 如果一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送,这就形成了粘包问题。

  • 如果一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是拆包。

在这里插入图片描述
发生状况原因
1、要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。
2、待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。
3、要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。
4、接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。
部分解决方法
1、发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。
2、发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
3、可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。(有可能会输入特殊符号问题)

微服务

1、Eureka自我保护机制

在一定时间内(15分钟),向注册中心注册的服务超过85%没有心跳,注册中心会认为是自己出现故障或者网络出现故障,宁可放过一千,不可以错杀一个,不会把大量服务从注册中心剔除,而是保护,起来,让整个微服务分布式集群可以正常运行。
大佬文档1
**自我保护机制开启条件:**当Eureka服务器每分钟收到心跳续租的数量低于一个阈值,就会触发自我保护模式。当它收到的心跳数重新恢复到阈值以上时,该Eureka服务器节点才会自动退出自我保护模式。心跳阀值计算公式如下:
服务实例总数量+1)×(60/每个实例心跳间隔秒数)×自我保护系数(0.85)

当新服务注册时:register 148行 173行 957行
续约类:AbstractInstanceRegistry idea 点击ctrl+N在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当前注册中心的总服务数 :expectedNumberOfClientsSendingRenews=1
ExpectedClientRenewalIntervalSeconds: 客户端续约间隔,心跳时长,不配置时30
这些都可以看到
在这里插入图片描述
在这里插入图片描述

  renewalPercentThreshold:续约百分比阀值因子,默认值为0.85

在这里插入图片描述
有1个服务在线时: 2*2 *0.85 3

关闭自我保护模式
eureka.server.enable-self-preservation=false

2、zookeeper,eureka两个注册中心的区别

dubbo 注册中心 ;zookeeper
springcloud 注册中心 eureka
分布式框架

  • CAP原则(C数据一致性,A高可用性,P分区容错性) 两个注册中心只能满足两个原则。zk 满足CP,eureka满足AP。
  • zk有leader和follower, eureka peer所有节点都是对等的
  • zk在选举期间,不能对外提供服务,必须有leader,保证数据一致,选举期间但不能保证集群一定可以用。eureka自我保护机制,不能保证节点数据同步,还可以注册新的服务,可用的
  • eureka是一个项目,而zk是个进程 (jps quorumpeermain…)

3、ribbon 和 nginx 的区别

         Ribbon是从注册中心服务器端上获取服务注册信息列表,缓存到本地,然后在本地实现轮询负载均衡策略一种客户端负载平衡器。nginx是客户端所有请求统一交给 nginx,由 nginx 进行实现负载均衡请求转发,一个服务器端负载均衡。
算法不同

4、feign 和 ribbon 的区别

启动方式

  • ribbon 使用:@RibbonClient
  • feign 使用: @EnableFeignClients

负载均衡位置不同

  • ribbon在 RibbonClient注解上配置
  • feign 在接口注解上@FeignClient配置

原理

  • ribbon 借助于RestTemplate使用的HTtp和 Tcp协议,实现服务调用和负载均衡
  • feign 使用调用方式 调用接口,支持springMVC的注解

5、微服务之间如何独立通信的

同步: ubbo 使用rpc(rpc参考帖子),springcloud使用restful传递json(ribbon,openfeign)
异步: 使用消息队列框架(MQ:kafka,activeMQ,rabbitMq等等)

spring框架

1、什么是spring

         spring是一个简化的java企业级开发的一个框架 ,包含了很多技术,比如:控制反转&依赖注入,面向切面编程,spring事务管理,通过spring集成其他框架,springMVC,springBoot,springCloud等待

2、什么是IOC(控制反转)

         控制反转(IOC):是面向编程的一种设计原则,可以降低计算机代码的耦合度,将创建对象的权利给了 容器,通过工程创建对象,称为控制反转

3、什么是Spring的依赖注入

         依赖注入(DI):依赖注入是Spring框架的好像之一。当某个角色(可能是一个java实例,调用者)需要另一个角色(另一个java实例,被调用者)的协助时,在传统的程序设计中,通常由调用者来创建被调用者的实例,但在Spring中,创建被调用者不在由调用者来创建,因此被称之为控制反转,创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此被称之为依赖注入

依赖注入方式
Setter 注入
构造函数注入

4、 推荐的依赖注入方式(2024年3月4日更新)

Spring最新版本建议构造器注入
来自副驾驶的答案
字段注入的问题
在Java开发中,字段注入是一种常见的依赖注入方式,但是它有一些潜在的问题,这可能是为什么IDEA会给出警告。

字段注入的问题主要有:

  1. 测试困难:如果你直接在字段上使用注解进行注入,那么在单元测试中,你需要使用反射来改变这个字段的值,这会使得测试变得复杂。

  2. 不可变性:如果你使用字段注入,那么你的类就不能是不可变的,因为你需要提供一个无参数的构造函数,并且字段需要是非final的。

  3. 空指针风险:在对象被完全构造之前,你不能保证依赖的对象已经被注入,这可能会导致空指针异常。

因此,一种更好的依赖注入方式是构造器注入。在构造器注入中,你在构造函数中接收所有的依赖,这样可以保证对象在被构造时就已经有了所有需要的依赖,同时也使得类可以是不可变的,而且更容易进行单元测试。

例如,如果你有一个类需要一个Service对象,那么你可以这样做:

@Service
public class MyComponent {

    private final MyService myService;

    @Autowired
    public MyComponent(MyService myService) {
        this.myService = myService;
    }

    // ...
}

在这个例子中,MyService对象是通过构造函数注入的,而不是直接在字段上注入。这样可以避免上述提到的字段注入的问题。

setter的问题
Setter注入是另一种常见的依赖注入方式,它允许你在对象创建后的任何时间点注入依赖。然而,它也有一些潜在的问题:

  1. 不完整的状态:使用Setter注入,对象可能会在没有所有依赖的情况下存在。这可能会导致对象处于不完整或不一致的状态,从而导致运行时错误。

  2. 不可变性:与字段注入一样,Setter注入也不能保证对象的不可变性,因为它需要提供setter方法来改变字段的值。

  3. 测试困难:虽然Setter注入比字段注入更容易进行单元测试,但是它仍然比构造器注入更难测试,因为你需要在每个测试中调用setter方法来设置依赖。

  4. 过多的setter方法:如果一个类有很多依赖,那么你需要为每个依赖提供一个setter方法,这会使得类的代码变得冗长和难以管理。

因此,构造器注入通常是更好的选择,因为它可以保证对象在被构造时就已经有了所有需要的依赖,同时也使得类可以是不可变的,而且更容易进行单元测试。

如果一个类有多个构造器,或者你想明确标记哪个构造器被用于依赖注入,你应该使用@Autowired注解

JVM

推荐去看周志明大佬写的深入理解JVM虚拟机这本书

HotSpot虚拟机 流行

1、Java 代码的执行流程和JVM类型(简单和复杂)

在这里插入图片描述

2、JVM类加载过程

参考文章1 作者:尚同学

3、JVM内存模型

请看文章

MYSQL

1.MySQL 的隐式转换和隐式类型转换规则

当操作符与不同类型的操作数一起使用时,会发生类型转换以使操作数兼容。
举个例子,当操作数是字符跟数字时, MySQL 会根据使用的操作符,转换字符到数字或转换数字成字符。

mysql> SELECT 1+'1';
        -> 2
mysql> SELECT CONCAT(2,' test');
        -> '2 test'

比较操作时 MySQL 隐式类型转换规则

  • 两个参数至少有一个是 NULL 时,比较的结果也是 NULL,例外是使用 <=> 对两个 NULL 做比较时会返回 1,这两种情况都不需要做类型转换
  • 两个参数都是字符串,会按照字符串来比较,不做类型转换
  • 两个参数都是整数,按照整数来比较,不做类型转换
  • 十六进制的值和非数字做比较时,会被当做二进制串
  • 有一个参数是 TIMESTAMP 或 DATETIME,并且另外一个参数是常量,常量会被转换为 timestamp
  • 有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较
  • 所有其他情况下,两个参数都会被转换为浮点数再进行比较

小米: 浅析 MySQL 的隐式转换

2、select * 为什么不用

  1. 不方便后期问题排查
  2. 无法进入缓存池
  3. 容易产生回表操作

3

项目管理

1、Maven的打包方式和区别

参考 作者:爱Rap篮球写代码的蔡徐
mvn package

  • 如果不在 POM 中配置任何插件,去直接用 mvn package 进行项目打包,这对于没有使用外部依赖包的项目是可行的。但如果使用了第三方 JAR 包,就会出现问题,因为 mvn package 打的 JAR 包中是不含有依赖包, 会导致作业运行时出现找不到第三方依赖的异常。这种方式局限性比较大,因为实际的项目往往很复杂,通常都会依赖第三方 JAR。
  • 大数据框架的开发者也考虑到这个问题,所以基本所有的框架都支持在提交作业时使用 --jars 指定第三方依赖包,但是这种方式的问题同样很明显,就是你必须保持生产环境与开发环境中的所有 JAR 包版本一致,这是有维护成本的。基于上面这些原因,最简单的是采用 All In One 的打包方式,把所有依赖都打包到一个 JAR 文件中,此时对环境的依赖性最小。要实现这个目的,可以使用 Maven 提供的 maven-assembly-pluginmaven-shade-plugin 插件。

maven-assembly-plugin

  • 支持将项目的所有依赖、文件都打包到同一个输出文件中。
  • 打包命令:#mvn assembly:assembly
  • 打包后会同时生成两个 JAR 包,其中后缀为 jar-with-dependencies 是含有第三方依赖的 JAR 包,后缀是由 assembly.xml 中 标签指定的,可以自定义修改。
    assembly.xml
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0
                              http://maven.apache.org/xsd/assembly-2.0.0.xsd">
    <id>jar-with-dependencies</id>
    <!--打包方式-->
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>runtime</scope>
            <!--这里以排除 storm 环境中已经提供的 storm-core 为例,演示排除 Jar 包-->
            <excludes>
                <exclude>org.apache.storm:storm-core</exclude>
            </excludes>
        </dependencySet>
    </dependencySets>
</assembly>
   <plugins><!--配置assembly-->
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptors><!--配置-->
            <descriptor>src/main/resources/assembly.xml</descriptor>
          </descriptors>
          <archive>
            <manifest><!--指定mainClass入口类-->
              <mainClass>com.aaa.packageTest.Test1</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>

在这里插入图片描述

maven-shade-plugin

   <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <configuration>
          <createDependencyReducedPom>true</createDependencyReducedPom>
          <filters>
            <filter>
              <artifact>*:*</artifact>
              <excludes>
                <exclude>META-INF/*.SF</exclude>
                <exclude>META-INF/*.sf</exclude>
                <exclude>META-INF/*.DSA</exclude>
                <exclude>META-INF/*.dsa</exclude>
                <exclude>META-INF/*.RSA</exclude>
                <exclude>META-INF/*.rsa</exclude>
                <exclude>META-INF/*.EC</exclude>
                <exclude>META-INF/*.ec</exclude>
                <exclude>META-INF/MSFTSIG.SF</exclude>
                <exclude>META-INF/MSFTSIG.RSA</exclude>
              </excludes>
            </filter>
          </filters>
          <artifactSet>
            <excludes>
              <exclude>org.apache.storm:storm-core</exclude>
            </excludes>
          </artifactSet>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer
                        implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                <transformer
                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>

在配置过shade时他会吧mvn package这个原来的操作替换成shade的操作

以上配置来源于 Storm Github,在上面的配置中,排除了部分文件,这是因为有些 JAR 包生成时,会使用 jarsigner 生成文件签名 (完成性校验),分为两个文件存放在 META-INF 目录下:

  • a signature file, with a .SF extension;

  • a signature block file, with a .DSA, .RSA, or .EC extension。

    如果某些包的存在重复引用,这可能会导致在打包时候出现 Invalid signature file digest for Manifest main attributes 异常,所以在配置中排除这些文件。

maven-shade-plugin 比 maven-assembly-plugin 功能更为强大,比如你的工程依赖很多的 JAR 包,而被依赖的 JAR 又会依赖其他的 JAR 包,这样,当工程中依赖到不同的版本的 JAR 时,并且 JAR 中具有相同名称的资源文件时,shade 插件会尝试将所有资源文件打包在一起时,而不是和 assembly 一样执行覆盖操作。

  • 使用 maven-shade-plugin 进行打包的时候,打包命令和普通打包一样:
  • 打包后会生成两个 JAR 包,提交到服务器集群时使用非 original 开头的 JAR。
    在这里插入图片描述

maven-jar-plugin 和 maven-dependency-plugin
可以把不用Maven管理的jar包打包
maven-scala-plugin
打包Scala文件

2、Maven的快照你了解嘛

MAVEN的代码仓库 有RELEASE版本 跟 SNAPSHOT版本机制:
可以将 release 理解为稳定的发布版本,当版本 release 后,如果你发现你的代码有问题,希望马上进行修改的话,一般来说是不可以的。

代码仓库通常不允许你将 release 版本多次发布,如果你需要进行再次发布的话,你需要修改版本号。

snapshot 针对 release 来理解的话,最简单的说法就是可以多次发布,如果你愿意,你可以将任何字符修改一下,然后发布上去。使用 snapshot 发布的时候的代码库,多次发布是不会被拒绝的。

  1. RELEASE版本机制
    先检查本地仓库是否有依赖的包,如果没有就去中央仓库或远程私有仓库进行下载。如果本地仓库已经有的话,不论远程私有仓库(MAVEN私服)是否有更新都不进行下载,除非把本地仓库的文件删除掉。(即使在编译的时候加参数-U也没效果)

  2. SNAPSHOT版本机制:
    快照是一种特殊的版本,指定了某个当前的开发进度的副本。不同于常规的版本,Maven 每次构建都会在远程仓库中检查新的快照。 现在 data-service 团队会每次发布更新代码的快照到仓库中,比如说 data-service:1.0-SNAPSHOT 来替代旧的快照 jar 包。
    类似于自动更新修改副本的jar包,而且不需要去修改jar包版本就可自动更新

作者:爱蛇
链接:https://www.jianshu.com/p/7e8e67205b97

大数据量高并发等问题

1、数据库中存在上亿的数据,索引已经很多了,怎么优化

参考文章
作者:大别山码将

  • 判断是否有低效率索引,是否不规范,不合理等。
  • 判断是否因为索引过多而影响了插入效率,去减少索引或者合并索引
  • 通过 explain查看语句性能,去优化sql语句
  • 对表进行拆分
    1.垂直拆分: 把主键和一些列放在一个表中, 然后把主键和另外的列放在另 一个表中。 如果一个表中某些列常用, 而另外一些不常用, 则可以 采用垂直拆分。     
    2.水平拆分: 根据一列或者多列数据的值把数据行放到二个独立的表中。
  • 使用中间表来提高查询速度
    创建中间表, 表结构和源表结构完全相同, 转移要统计的数据 到中间表, 然后在中间表上进行统计, 得出想要的结果。
  • 主从复制, 读写分离, 负载均衡
    实现数据库的读写分离,从而改善数据库的负载压力。一个系 统的读操作远远多于写操作,因此写操作发向 master,读操作发向 slaves 进行操作(简 单的轮循算法来决定使用哪个 slave)。
  • 调整磁盘调度算法      选择合适的磁盘调度算法, 可以减少磁盘的寻道时间。
  • 调整数据库磁盘阵列
  • procedure analyse() ,ANALYSE()检查查询的结果,并返回对结果的分析,该分析建议每列的最佳数据类型,这可能有助于减小 table 的大小。,(PROCEDURE ANALYSE()自 MySQL 5.7.18 起已弃用,并已在 MySQL 8.0 中删除。)

2、数据库limit分页偏移量问题

limit后跟两个参数,第一个参数为从第几个数据开始,第二个参数为取多少个数据。

第一个参数也叫偏移量,初始值是0

数据量很小,这么写分页当然没问题,但是当数据量大起来的时候,查询速度就会慢很多。
select * from user_address limit 100,10 查询用时0.011S

select * from user_address limit 100000,10 查询用时0.618S

一种解决方式 直接通过分页查询到这个id然后去条件查询到这个id开始后面然后进行分页得出结果页(适用在偏移量大的时候)
select * from user_address where id >= (select id from user_address order by id limit 100000,1) limit 10 查询用时0.068S

当一个查询语句偏移量offset很大的时候,如select * from table limit 10000,10 ,
先获取到offset的id后,再直接使用limit size来获取数据,效率会有一些提升,但不是很大。

3、什么时候需要JVM调优

  • OutfMemoryError,内存不足的时候
  • 内存泄漏
  • 线程死锁
  • 锁挣用
  • java进程消耗cpu资源过多

具体情况具体分析,需要性能分析工具

  • Jconsole jdk自带功能简单,但对垃圾回收有详细跟踪
  • JProfiler:商业软件功能强大
  • VisualVM jdk自带功能确定和上面一个类似 (推荐 这个工具放在JDK安装目录的bin目录下,双击jvisualvm.exe即可打开)
  • MAT(Memory Analyzer Tool) 基于Eclipse 的内存分析工具
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Network porter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值