0%

先导知识

xv6为每一个进程都创建一张页表,除此之外还有一张表用来描述内核的虚拟地址映射(这有很多不合理之处,之后的实验会手动修改)。

下图是原始的xv6的内核的内存映射图:

可以看到,大部分的映射的线都是水平的,也就是虚拟地址直接映射到物理内存,只有最上面的那些是斜着映射到RAM中的,而且看样子似乎能够覆盖掉内核的代码段。

阅读全文 »

先导知识

系统调用中,我们是如何传递参数的?

在x86-32中:通过中断实现(int 0x80)。把对应的系统调用的号码放入eax寄存器中,具体的参数放到指定的寄存器中。更为具体的代码:

1
2
3
4
5
6
pushl  ebx          # 把寄存器的内容丢到用户栈里面
pushl ecx
movl $2, %eax # 在32位系统中,2代表着fork
int $0x80 # 执行系统中断
popl ecx # 把寄存器的内容从栈中弹出
popl ebx

INT是用于x86处理器的汇编语言指令,该指令会生成软件中断。后面跟的0x80可以理解为指代是一个具体的中断处理程序。在Linux中,这个中断处理程序恰好就是内核。更加具体的中断号码对应的操作可以看这里

在x86-64中:通过syscall指令实现(其实也可以通过int 80,但是推荐别那么做)。同样把对应的系统调用放入eax寄存器中,具体的参数放到指定的寄存器中(和32位不同)。具体为什么从32位系统过度到64位系统的时候,会有这种变化,主要还是因为有了新的指令的支持,所以可以重新用新的机制。具体的变化的更为详细的信息可以阅读这份文档

阅读全文 »

This lab will familiarize you with xv6 and its system calls.

这个实验能让你熟悉xv6和它的系统调用。

Boot xv6(简单)

直接从GitHub上克隆下对应的仓库,切换到指定分支就可以了。该实验还贴心地提供了git的用户手册和面向CS人员的简单手册

然后就可以直接在该分支上面进行编译,然后运行qemu来运行xv6这个虚拟机了。

确保能成功启动xv6。

阅读全文 »

前言

这篇博客是学习spring的时候,对于官网中的guides做出的一些自己的理解和拓展。

官方几乎对于所有的方面都做了相关的guides介绍,每一个guides只需要15-30分钟即可。

构建一个RESTful的web服务

先导知识

首先,你需要了解,什么是RESTful,这个概念是Roy Thomas Fielding这位老哥在2000年的时候,在自己的博士毕业论文中提出的概念,有兴趣可以去阅读一下原文

在这个小guide中,将会介绍,如果使用spring来返回一个json数据格式。

具体实现

只需要构造好一个对应的对象(bean),然后创建对应的controller就可以了。

拓展

为什么返回对象能够输出json呢?

问题来了,我们的controller只是返回了一个对象,为什么最后能够以json的形式返回呢?

这是因为在类上声明了@RestController(@ResponseBody),有了这个注解,它会利用jackson自动把对象给解析成json进行返回。

更加具体的,只需要你的pojo有对应的getter方法,那么这些有getter方法的属性,就会自动解析成json返回。

@Component、@Repository、@Service、@Controller的区别

@Component是一个比较通用的说法,即任何被spring管理的类,都可以加上这个注解。剩下的三个则是它的更加具体的表现,显然如果你的类有更加明确的作用,那么标注更加具体能够在语义上更好地表现。

定时任务

这个小guide没有使用web,只是展示了如何使用spring实现一个定时任务,比如每隔多久运行一次,spring也可以轻易实现。

具体实现

其实就是把需要实现定时功能的代码写到一个方法中,然后使用@Scheduled注解即可。

这里注意需要把对应的类加上componet注解加入到spring中,否则是不生效的。

同时还需要在主应用中使用@EnableScheduling来开启定时任务。

拓展

Scheduled这个注解本身如果需要测试的话,需要额外使用awaitility这个工具。

消费RESTful的web服务

前面学习了如何使用spring来构造一个RESTful的web服务,这一部分则是讲述如果收到一个json数据,如何去处理它。

官方为我们提供了一个随机的RESTful的网站,访问即可获取对应的json数据。

对应的json数据看起来长这样:

1
2
3
4
5
6
7
{
type: "success",
value: {
id: 10,
quote: "Really loving Spring Boot, makes stand alone Spring apps easy."
}
}

具体实现

第一步自然而然就是根据上面的json数据来构建一个java的POJO了。

这里有一个新的知识点,就是之前是我们把一个对象给序列化成json,而这里是别人的json数据我们反序列化成对应的对象,要是里面有我们不认识的数据怎么办?这里jackson是提供了一个注解(@JsonIgnoreProperties(ignoreUnknown = true))来忽略的。

当然你也可以每个对象的名字和上面的json的key不对应,只需要@JsonProperty指定就可以了。

然后就是重点:RestTemplate这个类了。这个类以json数据作为输入,然后用第三方库进行处理,并且这个类可以从远端获取对应的json数据串,并且解析成对应的对象。

拓展

如果我的json的key和POJO的属性名不对应,会发生什么情况?那就解析不了,对应的值是NULL。当然是用@JsonProperty指定对应的json的key就可以了。

RestTemplate使用Jackson的解析库来解析。CommandLineRunner会自动在springboot启动的时候进行运行。

@Bean和@Component有什么区别?

这两者区别就大了,而且是完全不能搞混的。

@Component通过使用类路径扫描来进行自动检测和自动配置,让spring管理一个类。

@Bean则是告诉spring管理这个方法返回的对象。

所以这两者都是能够让框架来管理对应的类。

CommandLineRunner有什么作用?

这是一个接口,实现了这个接口的bean可以在容器加载完成之后执行。一般我们可以让一个方法返回一个CommandLineRunner对象,这样就能启动了;或者也可以在主类中声明实现这个接口,并且重写对应的run方法。

使用Gradle来构建java项目

暂时没有这个需求。

使用Maven来构建java项目

第一步,创建文件夹:mkdir -p src/main/java/hello

第二步,写入对应的java类。

第三步,在和src同级的目录下,创建一个pom.xml文件,写入对应的信息。

第四步,开始使用maven进行编译、打包、安装到本地库等一系列操作。

之后又介绍了一下使用JUnit配合maven进行单元测试。

在Spring中使用JDBC访问关系数据(H2数据库)

首先,我们假定数据需要访问的有一个顾客对象,然后顾客有ID、姓和名这三个属性。

Spring为开发者提供了JdbcTemplate这个类来让开发人员focus on业务。

首先第一步,当然是为了对应的实体创建对应的POJO。

第二步,获取JdbcTemplate对应的实例,由于在pom文件中已经有了对应的starter(spring-jdbc),所以springboot会帮我们自动注入,我们只需要autowire即可。

第三步,教程中选用的是H2数据库,这是一个用java写的嵌入式数据库,且只在内存中生效,所以用来作为测试是非常方便的。然后就是使用JdbcTemplate用来插入和查询,并将查询结果封装到对应的POJO中。

拓展

利用jdbcTemplate简单操作数据库。

一些删除表格、创建表格等的DDL语句,可以直接用jdbcTemplate.execute来执行对应的语句。

插入可以用?作为占位符,然后传入一个Object[]作为参数,这个数组中的每一个参数会一一取出然后填入问号里。

在Spring中使用MySQL(hibernate)

在这一部分,使用Spring Data JPA这项技术来访问数据。所以依赖关系如图所示:

image-20210326162608346

具体实现

到对应的数据库中,创建对应的数据库和用户,并且授予对应的权限(非常标准的做法):

1
2
3
create database db_example; -- Creates the new database
create user 'springuser'@'%' identified by '123456'; -- Creates the user
grant all on db_example.* to 'springuser'@'%'; -- Gives all privileges to the new user on the newly created database

之前我们使用H2数据库的时候,我们并没有做任何配置,似乎是直接拿来就用了,这是因为在springboot中的默认配置文件中,默认指定了数据库是H2,这次使用了MySQL,所以需要修改:

1
2
3
4
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=123456

这里使用的是hibernate框架,第一个是hibernate的设置。

然后创建对应的实体来对应数据库的记录,这里只需要在类上标注上@Entity,然后再在主键上使用@Id就可以了。

创建一个仓库类,来管理所有的这些增删改查,spring中有一个不错的父类可以继承:CrudRepository,它实现了通过id增删改查,所以就省去了很多代码。

好了,最后就是controller层,就是简单封装一下而已。

这里遇到一个比较严重的问题:required a bean named 'entityManagerFactory' that could not be found.,显然是在spring中没有这个对应的bean,然后我网上搜了不少答案,最后大概率应该是有bad的jar file,然后只能把.m2下面的repository删掉了重新下….

相同的问题发现网友也有不少,参考这个链接

测试的话,可以用postman,也可以用命令行工具curl,利用-d(data)这个选项指定对应的数据。当然也可以查看对应的信息。

拓展

具体使用hibernate的crud的这个repo类的话,可以发现在数据库中它还额外生成了一张表,是下一个值的表。

利用spring来上传文件

这次除了标准的web应用之外,还需要用到thymeleaf这个渲染的第三方库。

然后是上传文件的话,需要用到MultipartConfigElement,但是springboot已经帮我们配置好了。也就是在springboot启动的时候,已经有对应的bean在这个容器中了。

上来首先写一个存储服务的接口,因为我们的存储服务肯定需要一些操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface StorageService {

void init();

void store(MultipartFile file);

Stream<Path> loadAll();

Path load(String filename);

Resource loadAsResource(String filename);

void deleteAll();

}

定义好了对应的接口之后,就需要对应的实现。这里教程里非常奇怪,直接就给出了对应的实现,并不要求你去实现它。应该也是固定的一些套路,看了一眼代码并不算很难。

前言

面试中常问,你知道进程之间的通信方式有哪几种吗?它们各有什么优缺点?这篇博文就打算从源码角度好好分析一下。

Inter Process Communication (IPC) 有以下八种:

  • Memory Map(内存映射文件)
  • Pipe(匿名管道)
  • Named Pipe(命名管道)
  • Message Queue(消息队列)
  • Shared Memory(共享内存)
  • Semaphore(信号量)
  • Signal(信号)
  • Socket(套接字)

其中共享内存和信号量一般会搭配使用;匿名管道和命名管道也统称为管道。

阅读全文 »

前情

在更新了macOS Big Sur 11.2.1之后,我用LaTeX写的论文,然后在格式化的时候突然报错:Can't locate File/HomeDir.pm in @INC

简单看了下,应该是perl少了某个模块,因为格式化程序是用到perl写的,那就用perl自己的包管理程序cpan进行安装下载呗。

但是下载的时候出现了一个问题:fatal error: 'EXTERN.h' file not found,一个头文件给丢失了。

阅读全文 »

前请摘要

把博客部署到国内的网站,这样可以快速访问,因为国外实在有点慢。虽然没办法备案导致无法使用域名,但是自己偶尔看看顺便复习下以前学过的知识,这点也无伤大雅了。

阅读全文 »

前言

Jar包,是Java™ Archive的缩写,可以用这项技术把多个文件捆绑为一个文件,或者说,一种比较特殊的压缩技术。

阅读全文 »