值传递&引用传递

Java 中的传递,是值传递,而这个值,实际上是对象的引用。

1、传递的值在栈中,直接拷贝一份值传递,改变的形参不会对实参造成影响。

2、传递的值在栈中存放的是地址(引用),先根据栈中的地址找到在堆上的值,然后把地址拷贝一份(拷贝的地址是一个值),此时形参和实参指向堆上同一个地址,形参的修改导致了实参的改变。

注:java只有值传递,没有引用传递。

WeakHashMap-弱引用Map

我们都知道Java中内存是通过GC自动管理的,GC会在程序运行过程中自动判断哪些对象是可以被回收的,并在合适的时机进行内存释放。GC判断某个对象是否可被回收的依据是,是否有有效的引用指向该对象。如果没有有效引用指向该对象(基本意味着不存在访问该对象的方式),那么该对象就是可回收的。这里的 有效引用 并不包括 弱引用。也就是说,虽然弱引用可以用来访问对象,但进行垃圾回收时弱引用并不会被考虑在内,仅有弱引用指向的对象仍然会被GC回收

WeakHashMap 内部是通过弱引用来管理 entry 的,弱引用的特性对应到 WeakHashMap 上意味着什么呢?

WeakHashMap 里的 entry 可能会被GC自动删除,即使程序员没有调用remove()或者clear()方法。

WeakHashMap 的这个特点特别适用于需要缓存的场景。在缓存场景下,由于内存是有限的,不能缓存所有对象;对象缓存命中可以提高系统效率,但缓存MISS也不会造成错误,因为可以通过计算重新得到。

HashMap

java1.7的 hashmap 基于哈希表实现,采用冲突链表方式,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n)。

java1.8的 hashmap 基于数组+链表+红黑树,就是在上面的链表的元素达到了 8 个时,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。

ResponseEntity

ResponseEntity是一种泛型类型。因此,我们可以使用任何类型作为响应主体,还可以设置返回的状态码、响应头等信息,比较方便。

因此建议将所有的 rest 接口的返回值外面包一层 ResponseEntity,如:ResponseEntity<String>

MessageFormat.format-代码里直接打印输出

在代码里面打印输出时,使用MessageFormat.format,而不是String.format

public static void main(String[] args)throws Exception{
    System.out.println(MessageFormat.format("{0}-{1}",11,22));
}

说明:感觉这种打印方式,比String.fromat的要好,跟slf4j日志框架的一致,更习惯。

如何将 java 项目的依赖打成一个大的 jar 包

Caused by: java.lang.ClassNotFoundException: org.apache.thrift.TException

报错,是因为打jar包的时候,没有将依赖一起打包,导致找不到相关的包,只是在pom.xml中引用不够的~

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <mainClass>Main</mainClass>
            </manifest>
        </archive>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
    </configuration>
</plugin>

上面的插件,将依赖一起打成一个大的jar包,descriptorRef是jar包后面的描述信息,是jar包名称的一部分。

加载证书报错:Could not parse certificate: java.io.IOException: Incomplete data

ca 证书需要有换行符\n,不是一连串的字符串,可以手动给每行后面补一个\n,然后去 BeJson 上面进行压缩,注意开头和结尾的证书单词不要被压缩的合在一起了。

powermock使用注意

被测试类:

class A {
    public void handle() {
        B b = new B();
    }
}

测试handle方法,而我不想真正去执行new B()操作,那么可以使用PowerMockito.whenNew:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({A.class})//此处写被测试类,而不是whenNew的类
    public class ATest extends PowerMockTestCase {
        @Test
        public void testHandle() {
            B b = PowerMockito.mock(B.class);
            PowerMockito.whenNew(B.class).withNoArguments().thenReturn(b);
        }
    }

@PrepareForTest后面应该加上被测试的类,而不是要whenNew的类。

jpa的使用注意

JPA 的 save 方法被事务注解包裹,如果在 save 之后对 entity 的数据又做了操作,则会影响保存到数据库中的数据。

解决方案:可以使用深拷贝 BeanUtils.copyProperties(dbEntity, voEntity),对拷贝出来的对象进行操作,就不会影响 save 的数据了。

AOP切面

1、正常的执行顺序是:

@Around ->@Before->主方法体->@Around中pjp.proceed()->@After->@AfterReturning

2、异常的执行顺序是:

如果异常在 Around 中 pjp.proceed() 之前,则执行顺序为:@Around -> @After -> @AfterThrowing

如果异常在 Around 中 pjp.proceed() 之后,则执行顺序为:@Around -> @Before->主方法体->@Around中pjp.proceed()->@After->@AfterThrowing

java中的流是否需要关闭

链接: java中这些Stream流不需要关闭,你知道几个

通过查询数据库的日志,来查看每个查询的执行次数以及执行时长等关键的性能数据

1、gaussdb的日志: /var/log/operationlog/gaussdb

2、脚本:

#!/bin/bash
cd /var/log/operationlog/gaussdb
listfiles=$(ls /var/log/operationlog/gaussdb | grep -v current | grep -v syslog_label )
for file in $listfiles
do
    cat $file |grep -w "duration"| grep execute | awk '{out=$1" "$2"|"$4"|"$5"|"$8"|"; for(i=12;i<=NF-1;i++){out=out" "$i}; print out}'| cut -d'[' -f 2 >> /home/GalaX8800/sqlduration2.log
done

3、查询某一段时间内的sql语句执行情况,将相同的查询统计在一起,记录计数项字段。

Java SSH库

1、Apache sshd

2、JSch(Java Secure Channel)

注:第二个没有人维护了,优先选择第一个,支持交互式命令行和非交互式命令行。

WARNING! Using --password via the CLI is insecure. Use --password-stdin.

当使用 docker login -u xxx -p xx 时,报下面的警告:WARNING! Using --password via the CLI is insecure. Use --password-stdin.

解决方案:

1、只是警告而已啦,直接忽略不理就行。

2、将密码写入到一个文件中,例如 /etc/docker_passwd 文件,并使用以下命令执行登录:

cat /etc/docker_passwd  | docker login --username 用户名 --password-stdin

windows 上生成指定大小的空文件,用于测试上传等

在 Linux 下可以通过 dd 命令创建一个固定大小的文件,而在 windows 下也同样可以,不过命令就不是 dd 了。

比如在 Windows 系统中瞬间生成一个 100M 的文件,如下操作:

进入命令提示符,然后输入:

fsutil file createnew test.txt 104857600 

之后就会在当前命令提示符所在工作目录下生成了一个 100M 的 test.txt 文件了

其中 104857600=10010241024字节(Byte)

Http状态码401和403的区别

401 Unauthorized

状态码401标识认证失败,表示请求没有被认证或者认证失败。
通常由web服务器返回,而不是web应用。
场景:token失效、token缺失、token伪造,导致服务端无法识别身份。

403 Forbidden

状态码403表示授权失败,通常表示用户通过了身份验证,但缺少权限对给定的资源进行访问或者操作。
通常由web应用返回。
场景:用户登录成功,但是无权进行读写操作。

总结:401和403的主要区别在于

重点不同:401着重于认证,403着重于授权
返回对象不同:401通常由web服务器返回,403由web应用返回
场景不同:401表示用户未通过身份授权、验证,403表示用户可能通过了身份验证,但缺少指定权限

MultipartFile 配置临时存储目录

MultipartFile 其实只是一个接口,真正实现在org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.StandardMultipartFile

StandardMultipartFile 里面有个 javax.servlet.http.Part 对象,Part 也是一个接口,真正实现在org.apache.catalina.core.ApplicationPart

ApplicationPart 里有个org.apache.tomcat.util.http.fileupload.FileItem接口和 File,FileItem 实现是org.apache.tomcat.util.http.fileupload.disk.DiskFileItem,File 表示上传的文件(是一个临时存放文件)

DiskFileItem 是由org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory创建出来的,

从 DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD = 10240 可以得知:

如果文件大小在 10KB 以内,则直接放在内存,如果大于 10KB (这个是可以配置的),则存储在本地磁盘中(注意是存在临时目录中,意味着这个文件如果你不持久化那这个文件随时会被系统清除)

解决方案:

1、写代码自定义临时文件目录。@Baen MultipartConfigElement

2、在配置文件中增加:server.tomcat.basedir:/your_dir

后面的 transferTo 动作,如果不超过 10KB,则是从内存中直接保存到目标位置,否则就是走文件系统的 mv 到目标位置,不过内存。

控制台执行jar程序的输入参数

> java -jar test.jar mama baba son

public static void main(String[] args)

args数组,长度为3,args[0] = mama, args[1] = baba, args[2] = son

运行 jar 包报 “XXX中没有主清单属性”

D:\hu-git\spring-xxx-xxx\target>java -jar spring-cloud-eureka-0.0.1-SNAPSHOT.jar
spring-xxx-xxx-0.0.1-SNAPSHOT.jar中没有主清单属性

在这里有一个问题就是主清单属性是什么?

以 SpringBoot 为例,jar 包中包含了三个文件夹:BOOT-INF,META-INF,org,可以把 jar 包解压到文件夹下查看,其中 META-INF 文件夹下有一个MANIFEST.MF 文件,该文件指明了程序的入口以及版本信息等内容,如下:

Manifest-Version: 1.0
Implementation-Title: spring-xxx-xxx
Implementation-Version: 0.0.1-SNAPSHOT
Archiver-Version: Plexus Archiver
Built-By: XXXX
Implementation-Vendor-Id: com.huyikang.practice
Spring-Boot-Version: 1.5.9.RELEASE
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.JarLauncher  // 代表了Spring Boot 中启动 jar 包的程序
Start-Class: com.huyikang.practice.eureka.Application    // 代表了Spring Boot 程序的入口类,这个类中应该有一个 main 方法
Spring-Boot-Classes: BOOT-INF/classes/                   // 代表了类的路径,所有编译后的class文件,以及配置文件,都存储在该路径下
Spring-Boot-Lib: BOOT-INF/lib/						   // 表示依赖的jar包存储的位置
Created-By: Apache Maven 3.5.2
Build-Jdk: 1.8.0_151
Implementation-URL: http://maven.apache.org

这些值都是 SpringBoot 打包插件会默认生成的,如果没有这些属性,SpringBoot 程序自然不能运行,就会报错:jar 中没有主清单属性,也就是说没有按照SpringBoot 的要求,生成这些必须的属性。

解决办法:

在pom中添加一个 SpringBoot 的构建的插件,然后重新运行 mvn install 即可。

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

在运行 mvn install 的时候,自动生成这些主清单属性,运行 java -jar xxx.jar 时会根据主清单属性找到启动类,从而启动程序。

PS:也可以手动的改一下上面的 MANIFEST.MF 文件,注明启动类之类的,但最好还是利用插件生成,保证正确性。

java 的 properties 的基本操作

1、默认值

@Value("${external.image.repository.num.limit:10}")
privateintexternalImageRepositoryNumLimit;

2、拆分数组

@Value("#{'${external.image.repository.forbidden.ports}'.split(',')}")
privateList<String>externalImageRepositoryForbiddenPortList;

3、读取配置

@Value("${external.image.repository.cert.check.cron}")
privateStringexternalImageRepositoryCertCheckCron;

关于 try catch finally 语句异常被捕获和未被捕获发生的结果

包括以下几种情况:

1、不抛出异常,try 里面的代码、finally 里面的代码、finally 以后的代码都将正常执行,而 catch 里面的代码不会执行。

2、抛出异常且被 catch 捕获,try 里面的代码部分执行,catch 里面的代码、finally 里面的代码、finally 以后的代码都将正常执行。

3、抛出异常,但未被 catch 捕获,抛出异常的语句将会报错,在 try 中的抛出异常的语句后的语句将不会执行,由于异常未被捕获,故 catch 语句不执行,但是finally 仍然会执行,在 finally 后面的语句由于程序已经报错停止,故将不会执行。

注意:finally 在这三种情况中,都正常执行,finally 永远会执行,除非 try 前面的语句报错。

JPA 中使用了悲观锁,同时使用了事务的话,需要注意下面:

当我们在事务中使用悲观锁并访问实体时,它将立即锁定,通过提交或回滚事务来释放锁。如果不提交或者不回滚的话,锁会一直在,除非重启程序,或者手动删除锁。

select pid,
       state,
       usename,
       query,
       query_start
from pg_stat_activity
where pid in (
    select pid
    from pg_locks l
             join pg_class t on l.relation = t.oid
        and t.relkind = 'r'
);

手动删除锁的方法(PostgreSql 适用):

删除锁:(第一步查出来的结果有 pid 
// (只kill掉select)
SELECT pg_cancel_backend(pid)
// (kill掉select、update、insert、delete)
SELECT pg_terminate_backend(pid)

执行测试用例报错:No tests were found

IDEA中,右键选中某个测试类,可以 Run | Debug | Run with coverage(带覆盖率统计的),但是选中整个 package 再 Run 的时候,提示 “No tests were found”。

说明:

  • 确定 junit 的版本,有 junit4 和 junit5 的区别,注意分析 pom 的依赖。

  • 确定 class 和 functions 都是 public 的。

  • 确定没有其他的测试框架影响,比如我在 krm/base-common 中就遇到了groovy 框架和 testng 两种,前一个导致无法右键整个包执行用例,后一个导致到流水线上执行未发生任何测试用例。去掉这两个框架的依赖就好了。

posted on 2023-07-22 15:49  彦承  阅读(93)  评论(0编辑  收藏  举报