xiaozhigang

长风破浪会有时,直挂云帆济沧海。

架构图

四层结构

cola-arch.jpg

  1. 适配层(Adapter Layer):负责对前端展示(web,wireless,wap)的路由和适配,对于传统B/S系统而言,adapter就相当于MVC中的controller;

  2. 应用层(Application Layer):主要负责获取输入,组装上下文,参数校验,调用领域层做业务处理,如果需要的话,发送消息通知等。层次是开放的,应用层也可以绕过领域层,直接访问基础实施层;

  3. 领域层(Domain Layer):主要是封装了核心业务逻辑,并通过领域服务(Domain Service)和领域对象(Domain Entity)的方法对App层提供业务实体和业务逻辑计算。领域是应用的核心,不依赖任何其他层次;

  4. 基础实施层(Infrastructure Layer):主要负责技术细节问题的处理,比如数据库的CRUD、搜索引擎、文件系统、分布式服务的RPC等。此外,领域防腐的重任也落在这里,外部依赖需要通过gateway的转义处理,才能被上面的App层和Domain层使用。

    阅读全文 »

简述

ThreadLocal是什么,是java中用于实现线程内变量的工具类。允许每个线程都拥有自己的副本,从而实现线程隔离,解决多线程的共享对象的线程安全问题。

image-20240330210435879

ThreadLocal的使用

1
2
3
public static ThreadLocal<String> localVariable = new ThreadLocal<>(); // 新建
localVariable.set("他是沙雕"); // 设置值
String value = localVariable.get(); // 获取值

详述

实现原理

ThreadLocal的底层实现是一个特殊的map,可以理解往ThreadLocal设置一个xxx值,就是往这个特殊的map中设置一个key为当前线程,value为xxx的值。由于他的key只能为当前线程,所以在某个线程中set和get都不会影响其他线程,从而到达线程安全。下图的ThreadLocalMap就是拿个特殊的map。

image-20240330211735870

总体来说,java在运行的过程中会维护一个ThreadLocalMap,这个ThreadLocalMap的key为各个线程,value为各个线程想存放的东西,可以是String,可以是map,List等等。当时由于key为各个线程,所有每个线程只能由一个Entry ,也就是一个键值对(key-value),当然线程也可以不设置不存放。

阅读全文 »

简述

IoC是指控制反转,是指有容器来控制对象的生命周期和对象之间的关系。简单来说就是之前使用对象首先需要new一个对象,而现在直接从容器中取就可以了。这就像有小农经济转变到商品经济。

小农经济:自给自足,什么东西都需要自己动手也就类似于对象需要自己new。

商品经济:需要啥去商店买就行,这里的商店就相当于容器,商品就相当于对象,生成商品的工厂就相当于对象工厂等。

Spring IOC 的简单实现

分析

1、首先我们得有一个容器,这个容器负责保存和生成bean,这也就是对象工厂BeanFactory 。

2、其次,得有一个bean注册器,这负责bean的注册和真正生成。

3、然后,还得有一个资源加载器,用来加载bean的定义

阅读全文 »

简述

都知道spring的自动加载是通过注解实现的,但是这注解又是怎么实现的呢?

通过@SpringBootApplication注解开启,读取配置文件中的配置类,然后过滤掉不需要的配置类,最后将剩余的配置类加载配置。

具体过程

上面说了一下大概的概念,接下来我们分析一下具体的执行过程。

1、开启自动加载

都知道自动开启加载注解@SpringBootApplication,但是这个注解是个复合注解,他是由多个注解合并而成,但是主要的是三个注解:

1
2
3
@SpringBootConfiguration // 配置文件
@EnableAutoConfiguration // 开启自动配置
@ComponentScan // 扫描

image-20240401205815186

@EnableAutoConfiguration注解继续下钻,主要有@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})两个注解,@AutoConfigurationPackage继续下钻主要有@Import({AutoConfigurationPackages.Registrar.class})这个注解。

阅读全文 »

代理模式

Spring AOP 就是基于代理模式,被代理对象有实现某个接口,则用JDK Proxy创建对象,没有实现接口则用Cglib创建代理对象。

当然也可以使用AspectJ,AspectJ是Java生态系统中最完整的AOP框架。

image-20240414185312122

Spring AOP属于运行时增强,AspectJ是编译时增强。

Spring AOP AspectJ
1 与spring ioc紧密集成,新项目使用 维护老项目使用
2 运行时织入 编译时生成
3 不支持static和final修饰方法和类 支持
4 简单,有注解 复杂,需要.aj文件来创建切面,并且需要使用ajc来编译代码

两者异同:https://developer.aliyun.com/article/720402

模板方法

父类定义算法骨架或者关键步骤,而具体实现延迟到子类中,使子类再不改变父类结构的情况下可重定义某些特定步骤的实现。

Spring 中 JdbcTemplateHibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。一般情况下,我们都是使用继承的方式来实现模板模式,但是 Spring 并没有使用这种方式,而是使用 Callback 模式与模板方法模式配合,既达到了代码复用的效果,同时增加了灵活性。定义了资源获取、执行SQL、释放资源这些基本流程,执行sql的具体方式又以回调函数的形式开放。

阅读全文 »

分支定义

  1. master

    1
    2
    3
    长期分支,存在与整个项目开发过程。

    由项目主要技术负责人管理该分支。
  2. release/xxx

    1
    2
    3
    4
    release/test 和 release/prod
    既可以为长期分支也可以为短期分支,可能存在于一个或者多个版本之间.

    由测试负责人负责人管理该分支。
  3. feature/fixbug/hotfix

    1
    2
    3
    4
    5
    临时分支
    用于开发的具体功能特性和修复bug的分支,功能完成后删除.
    格式为:feature_$date_$name_$description
    fixbug_$date_$name_$description
    hotfix_$date_$name_$description
阅读全文 »

两段式提交是MySQL数据持久化的保证。

两种日志

binlog和redolog

binlog记录了数据库表结构和表数据变更,主要有两个作用:复制和恢复数据

redo log 是 Innodb 引擎独有的日志模块,它只记录有关 Innodb 引擎的事务日志,记录内容为 对数据页的物理操作

binlog redolog
适用对象不同 mysql server 层 Innodb 存储引擎层
写入方式不同适用对象不同 追加写,一个文件满了写新文件mysql server 层 循环写固定文件Innodb 存储引擎层
写入方式不同 逻辑日志,一个事务具体操作内容 物理日志,页的修改情况
写入磁盘时间不同 提交事务前一次写入 在事务进行中有后台线程不断同步
用途不同 主从复制、数据备份 数据恢复

两段式提交

两种日志虽然都保证持久化,但是侧重点不同。

1、redo log(重做日志)让InnoDB存储引擎拥有了崩溃恢复能力。

2、binlog(归档日志)保证了MySQL集群架构的数据一致性,主从节点的同步都是通过binlog保证的。

阅读全文 »

简述

说起回表,肯定要说起MySQL的存储结构B+树。

每条数据是以主键和数据的形式存放在B+树的节点上,如果我们通过主键查询的话,直接通过和节点上的主键比较判断,相等的话直接取。

其他索引是将索引和主键值放在一起的,通过索引查到主键,在通过主键去查找数据。这也就是为什么主键索引会比其他索引快。

主键查询

主键和数据是通过B+数的形式存储的,查的时候肯定也是通过树的查询方式查询的。如下图查询主键Id为4的数据,先根据根节点查询,4小于10,再往子节点查找,然后跟子节点的值比较,在2、4之间,再寻找这区间的节点,第一个值是3,不匹配,在查找下一个,值是4匹配,放回数据记录data。

img

非主键索引查询

其实和主键查询差不多,只不过相当于两次主键索引查询,第一个查询到的不是数据,是主键值,再根据主键值,按照主键索引查询再来一次。如图,如果数据有一条数据是2019-04-01创建的,数据的主键id为4,我们想根据这个创建时间(不知道主键id)找到这条数据。那就是先根据创建时间找到主键4,后根据主键4找到记录数据data。

img

阅读全文 »

结构简述

HashMap和ConcurrentHashMap的结构都是一样的,jdk1.8之后都是 数组+链表+红黑树,链表长度超过8之后转红黑树。

计算

节点为6个的时候,链表的平均查询时间:(1+2+3+4+5+6)/ 6 = 3.5,红黑树的平均查询时间 (1+22+33)/6=2.3

节点为7个的时候,链表的平均查询时间:(1+2+3+4+5+6+7)/ 7 = 4,红黑树的平均查询时间 (1+22+34)/7=2.4

节点为8个的时候,链表的平均查询时间:(1+2+3+4+5+6+7+8)/ 8 = 4.5,红黑树的平均查询时间 (1+22+34+1*4)/8=2.6

链表的时间复杂度为O(n),而树的时间复杂度为O(ln n),上面计算有明显的效率变化,至于为啥选8这个阈值,应该是基于大量数据收集之后比较而定的。

结构图

HashMap

阅读全文 »

虽然网上已经有很多了,但是我还是尝试总结一下,添加一点自己的心得。

总体来说,数组和链表是两种数据结构,所有的异同都是这两种数据结构的特点导致的。这两种数宝结构是计算机的基本数据结构,基态所有都是基于这两种数据结构实现的,只不过在细节上有区别。

简述

数组:多用于读多写少的情况,读取O(1),写入O(n),修改O(1),删除O(n);需要连续内存。

链表:多用于读少写多的情况,读取O(n),写入O(1),修改O(n),删除O(1);不需要连续内存。

数据结构差异

​ 从下图很明显就能看出两者的差别。数组需要连续,即连在一起,而链表不需要,只需要有个指针指向下一个。但是这个指向下一个的指针,也需要占用内存,导致链表中的单个元素比数组中的一个元素的内存大。

image-20240326230530963

增删改查的效率差异

上面的数据结构差异,不可避免的导致了读写性能的差异。

阅读全文 »
0%