代理模式

代理模式简单来说就是,使用代理对象代替真实对象的访问。可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能,比如在某个方法执行前后,可以增加一些自定义的操作。

[静态代理](多线程详解.md/#静态代理模式 static proxy)

动态代理

静态代理中,对目标对象的每个方法的扩展都是手动完成的,非常不灵活(比如一旦新增方法,目标对象和代理对象都要进行修改)、麻烦(需要对每个目标类都单独写一个代理类)。日常开发几乎看不到使用静态代理的场景

相比于静态代理来说,动态代理更加灵活。不需要针对每个目标类都单独创建一个代理类,并且也不需要我们必须实现接口,可以直接代理实现类(CGLIB 动态代理机制)。从JVM角度说,动态代理是在运行时 动态生成类字节码,并加载到JVM中

Spring AOP、RPC框架的实现都依赖了动态代理。动态代理在日常开发中使用相对较少,但在框架中是必用的一门技术,对于各种框架原理的理解和学习很有帮助。就Java来说,动态代理的实现方式有很多种,比如JDK 动态代理、CGLIB 动态代理

阅读全文 »

Kryo的注册

和很多其他的序列化框架一样,Kryo 为了提供性能和减小序列化结果体积,提供注册的序列化对象类的方式。在注册时,会为该序列化类生成 int ID,后续在序列化时使用 int ID 唯一标识该类型。注册的方式如下:

1
kryo.register(SomeClass.class);

线程不安全

Kryo 不是线程安全的。每个线程都应该有自己的 Kryo 对象、输入和输出实例。因此在多线程环境中,可以考虑使用 ThreadLocal 或者对象池来保证线程安全性。

ThreadLocal 是一种典型的牺牲空间来换取并发安全的方式,它会为每个线程都单独创建本线程专用的 kryo 对象。对于每条线程的每个 kryo 对象来说,都是顺序执行的,因此天然避免了并发安全问题。创建方法如下:

1
2
3
4
5
6
7
8
9
static private final ThreadLocal<Kryo> kryos = new ThreadLocal<Kryo>() {
protected Kryo initialValue() {
Kryo kryo = new Kryo();
// 在此处配置kryo对象的使用示例,如循环引用等
return kryo;
};
};

Kryo kryo = kryos.get();

之后,仅需要通过 kryos.get() 方法从线程上下文中取出对象即可使用。


Kryo相关配置参数详解

深入理解RPC之序列化篇–Kryo - 知乎 (zhihu.com)

1
2
kryo.setRegistrationRequired(false); // 关闭注册行为
kryo.setReferences(true); // 支持循环引用

Kryo支持注册行为,如kryo.register(SomeClazz.class);,这会赋予该Class一个从0开始的编号。但Kryo使用注册行为最大的问题在于,其不保证同一个Class每一次注册的号码相同,这与注册的顺序有关,也就意味着在不同的机器、同一个机器重启前后都有可能拥有不同的编号,这会导致序列化产生问题,所以在分布式项目中,一般关闭注册行为。

第二个注意点在于循环引用,Kryo为了追求高性能,可以关闭循环引用的支持。不过我并不认为关闭它是一件好的选择,大多数情况下,请保持kryo.setReferences(true)

Kryo默认情况下是不启用对象引用的。这意味着如果一个对象多次出现在一个对象图中,它将被多次写入,并将被反序列化为多个不同的对象。

举个例子,当开启了引用属性,每个对象第一次出现在对象图中,会在记录时写入一个 varint,用于标记。当此后有同一对象出现时,只会记录一个 varint,以此达到节省空间的目标。此举虽然会节省序列化空间,但是是一种用时间换空间的做法,会影响序列化的性能,这是因为在写入/读取对象时都需要进行追踪。

开发者可以使用 kryo 自带的 setReferences 方法来决定是否启用 Kryo 的引用功能。

深入浅出序列化(2)——Kryo序列化

缓冲区

Buffer类及其实现

Buffer类是缓冲区的实现,类似于Java中的数组,也是用于存放和获取数据的。但它包含了一系列对于数组的快捷操作。

Buffer是一个抽象类,它的核心内容:

1
2
3
4
5
6
7
8
9
public abstract class Buffer {
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;

// 直接缓冲区实现子类的数据内存地址
long address;
阅读全文 »

常见的语义分割评价指标

  1. Pixel Accuracy 像素准确率

    ${\Sigma_i n_{ii}}\over {\Sigma_i t_i}$

    • $n_{ij}$:类别i被预测称类别j的像素个数
    • $t_i$:目标类别i的总像素个数(真实标签)
  2. mean Accuracy 平均准确率

    ${1\over n_{cls}}\cdot \Sigma_i {n_{ii}\over t_i}$

    • $n_{cls}$:目标类别个数(含背景
  3. mean IoU 平均并集上的交集率

    ${1\over n_{cls}}\cdot \Sigma_i {n_{ii}\over t_i+\Sigma_j n_{ij} - n_{ii}}$

    真实标签与预测标签

    • 绿色:真实标签$t_i$
    • 蓝色:预测标签$\Sigma_j n_{ij}$
    • 重叠:准确预测的部分$n_{ii}$

日志门面和日志框架实现

日志门面(Facade)把不同的日志系统的实现进行了抽象化,只提供了统一的日志使用接口。由于它只是一个接口,所以最终日志的格式、记录级别、输出方式等都要通过接口绑定的具体日志框架实现

image-20230612215155120

实际的项目开发中可能会使用到很多不同的框架,而这些框架又使用了不同的日志框架。我们希望所有的框架一律使用日志门面(Slf4j)进行日志打印,这时该怎么去解决?

  • logback直接实现了slf4j-api中的接口,通过接口实现的方式完成了门面的实现。
  • log4j2没有直接实现接口,需要适配器log4j-slf4j-impl
阅读全文 »

Docker安装

Docker之介绍与安装 - Qubernet - 博客园 (cnblogs.com)


镜像 image

如果我们要写一个比如论坛、电商这类的Java项目,那么数据库、消息队列、缓存这类中间件是必不可少的。因此我们如果想要将一个服务部署到服务器,要提前准备好各种各样的环境,先安装好MySQL、Redis、RabbitMQ等应用,配置好了环境,再将我们的Java应用程序启动。整个流程下来,光是配置环境就要浪费大量的时间,如果是大型的分布式项目,可能要部署很多台机器,项目上个线就要花几天时间,显然是很荒唐的。

而上述的MySQL、Redis、RabbitMQ等应用以及Java应用程序,可以一起被打包成一个镜像,整个镜像中环境都是已经配置好的状态,开箱即用。镜像就是一堆静态的模板,根据这个模板运行起来的就是容器。镜像一般需要拉取下来,是只读的。

阅读全文 »

简介

Spring的理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架

  • Spring是一个开源的免费框架
  • Spring是一个轻量级的、非侵入式的框架
  • 重要特性:IoC(控制反转)、AOP(面向切面编程)
  • 支持事务的处理。支持整合框架

image-20221121233807593

阅读全文 »

MyBatis

简介

MyBatis 是一款优秀的 持久层框架。它支持 定制化 SQL、存储过程以及高级映射

MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML注解 来配置和映射 原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为 数据库中的记录

  • 持久化

    • 持久化就是将程序的数据在 持久状态瞬时状态 转化的过程。

    • 由于内存有断电之后数据就会丢失的特点,有一些对象不能丢失,需要将其持久化。

  • 持久层

    • 完成持久化工作的代码块就是持久层。

传统的 JDBC 代码太复杂,MyBatis 简化了将数据存入数据库这一过程。MyBatis 将 sql 和代码分离,提高了可维护性;提供了映射标签,支持对象与数据库的字段关系的映射(ORM,Object Relation Mapping);提供 xml 标签,支持编写动态 sql

阅读全文 »
0%