Java虚拟机 JVM
JVM启动入口:JLI_Launch
函数
以OPENJDK8源码GitHub - openjdk/jdk at jdk8-b120为例,虚拟机的启动入口在jdk/src/share/bin/java.c
的JLI_Launch
函数,整个流程分为:
- 配置JVM装载环境
- 解析虚拟机参数
- 设置线程栈大小
- 执行
JavaMain
方法
JLI_Launch
函数以OPENJDK8源码GitHub - openjdk/jdk at jdk8-b120为例,虚拟机的启动入口在jdk/src/share/bin/java.c
的JLI_Launch
函数,整个流程分为:
JavaMain
方法发起HTTP请求调用,控制台报错:
org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:322) ~[spring-webmvc-6.1.10.jar:6.1.10]
任何接口,如果只包含一个抽象方法,它就是一个函数式接口。对于函数式接口,可以通过Lambda表达式来创建该接口的对象
Runnable就是一个函数式接口。
@Transactional
的事务注解。spring事务的依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
public class Test {
public void testTransaction() {
int a = 0;
int b = 1;
TransactionConsumer transactionConsumer = () -> {
insertDataA(a);
updateDataB(b);
};
transactionConsumer.doInTransaction();
}
private void updateDataB(int b) {
}
private void insertDataA(int a) {
}
}
@FunctionalInterface
public interface TransactionConsumer {
@Transactional
void doInTransaction();
}
Lombok 项目其实就是一个 java 库,它可以自动插入到编辑器和构建工具中,增强 java 的性能。以后你 只需要一些简单的注解,就可以再也不用在类中反复去写 getter、equals 等方法,让代码变得简介,不用过多地去关注相应的方法。属性修改时,也简化了维护这些属性所生成的 get、set 方法。
使用方式:
IDEA 下载 Lombok 插件
项目中导入 Lombok 的 jar 包
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
Optional 被设计出来,主要是为了解决空指针异常。
以一个 Student 类为例:
@Getter
class Student {
private String name;
private int age;
private int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
public Student() {
}
}
Queue<Integer> queue1 = new PriorityQueue<>();
Queue<Integer> queue2 = new PriorityQueue<>(Comparator.comparingInt(o -> o));
Queue<Integer> queue3 = new PriorityQueue<>(Comparator.comparingInt(o -> -o));
Java中的PriorityQueue常用于实现小顶堆、大顶堆。由上述代码可见,通常有默认无参构造函数、传入Comparator对象等方式的实现。
从构造函数层面,完全不清楚默认构造函数的排序规则,也完全不明白Comparator实现的comparingInt方法对应的排序规则。
根据网上绝大多数文章的描述,都没有解释或者只是说明了对应的排序规则,但是不知道为什么是对应升序或降序。通过阅读源码,才得到准确的认知。
图床是一个网络术语,指的是一种用于存储和托管图片的在线服务。用户可以上传图片文件,并获得一个唯一的链接或嵌入代码,方便在网页、博客、论坛等地方分享和展示这些图片。
将七牛云作为图床,实际上是使用了七牛云的对象存储服务(OSS)。
官方开发文档:Java SDK_SDK 下载_对象存储 - 七牛开发者中心
首先添加依赖:
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.17.0</version>
</dependency>
注意:
7.17.0版本,qiniu-java-sdk
自身依赖的gson的scope为runtime,在编译 main
目录下的 Java 类时,编译器会无法找到 gson
库,需要显式添加gson的依赖:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
</dependency>
qiniu:
accessKey: "实际的ak"
secretKey: "实际的sk"
bucket: "目标存储空间名称"
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.springframework.beans.factory.annotation.Value;
@SpringBootTest
@Slf4j
public class OSSTest {
@Value("${qiniu.accessKey}")
private String accessKey;
@Value("${qiniu.secretKey}")
private String secretKey;
@Value("${qiniu.bucket}")
private String bucket;
@Test
public void testOSS() {
// 构造一个带指定 Region 对象的配置类
Configuration cfg = new Configuration(Region.autoRegion());
cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
UploadManager uploadManager = new UploadManager(cfg);
// 默认不指定key的情况下,以文件内容的hash值作为文件名
String key = "hunter.jpg";
Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket);
try {
InputStream inputStream = new FileInputStream("C:\\Users\\Hunter\\Pictures\\Saved " +
"Pictures\\Rukawa-Sara-Sakuragi-Hanamichi-Slam-Dunk-slum-dunk.jpg");
Response response = uploadManager.put(inputStream, key, upToken, null, null);
// 解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
System.out.println(putRet.key);
System.out.println(putRet.hash);
} catch (QiniuException ex) {
ex.printStackTrace();
if (ex.response != null) {
System.err.println(ex.response);
try {
String body = ex.response.toString();
System.err.println(body);
} catch (Exception ignored) {
}
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
System.err.println("file not found");
}
}
}
实际应用,需要获取图片上传至图床后的访问链接。
七牛云提供了临时的外链域名:
qiniu:
accessKey: "实际的ak"
secretKey: "实际的sk"
bucket: "目标存储空间名称"
domain: "http://外链域名/"
当前的 年份/月份/日期 + 随机数 + 文件类型
的形式作为文件名,实际会以/
为分隔,按多级目录进行存储。${qiniu.domain} + 文件名
@Service
@Slf4j
public class UploadServiceImpl implements UploadService {
@Value("${qiniu.accessKey}")
private String accessKey;
@Value("${qiniu.secretKey}")
private String secretKey;
@Value("${qiniu.bucket}")
private String bucket;
/**
* 域名
*/
@Value("${qiniu.domain}")
private String domain;
@Override
public ResponseResult<String> uploadImg(MultipartFile img) throws IOException {
// 判断文件类型
String originalFilename = img.getOriginalFilename();
assert originalFilename != null;
String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
if (!".jpg".equals(fileType) && !".jpeg".equals(fileType)
&& !".png".equals(fileType)) {
throw new GlobalException(HttpCodeEnum.FILE_TYPE_ERROR);
}
// “当前的 年份/月份/日期 + 随机数 + 文件类型”作为文件名
String fileName =
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd/"))
+ UUID.randomUUID()
+ fileType;
// 上传文件到七牛云,返回链接地址
String url = uploadToQiniu(img, fileName);
return ResponseResult.success(url);
}
/**
* 上传文件到七牛云
*
* @param img 上传的文件
* @param fileName 文件名
* @return 文件存储的地址
*/
private String uploadToQiniu(MultipartFile img, String fileName) throws IOException {
// 构造一个带指定 Region 对象的配置类
Configuration cfg = new Configuration(Region.autoRegion());
// 指定分片上传版本
cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;
Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket);
try {
UploadManager uploadManager = new UploadManager(cfg);
InputStream inputStream = img.getInputStream();
// 默认不指定key的情况下,以文件内容的hash值作为文件名
Response response = uploadManager.put(inputStream, fileName, upToken, null, null);
// 解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
log.info("文件成功上传到七牛云,key: {}, hash: {}", putRet.key, putRet.hash);
return domain + putRet.key;
} catch (QiniuException ex) {
log.error("上传文件到七牛云失败: {}", ex.getMessage(), ex);
throw ex;
} catch (FileNotFoundException ex) {
log.error("文件不存在: {}", ex.getMessage(), ex);
throw ex;
}
}
}