Bean的生命周期

Bean的生命周期

1.调用Bean的构造方法创建Bean;

2.通过反射调用setter方法进行属性的依赖注入;

3.如果bean实现了BeanNameAware,则为bean设置名称;

4.如果bean实现了BeanFactoryAware,会把 BeanFactory 设置给 Bean;

5.如果bean实现了ApplicationContextAware,,会给 Bean 设置 ApplictionContext;

6.如果实现了BeanPostProcessor接口,则执行前置处理方法;

7.实现了InitializingBean接口的话,执行afterPropertiesSet方法

8.执行自定义的init方法;

9.执行BeanPostProcessor接口的后置处理方法;

MYSQL数据库设计规范

MYSQL数据库设计规范

1、数据库命名规范

采用26个英文字母(区分大小写)和0-9的自然数(经常不需要)加上下划线’_’组成;
命名简洁明确(长度不能超过30个字符);
例如:user, stat, log, 也可以wifi_user, wifi_stat, wifi_log给数据库加个前缀;
除非是备份数据库可以加0-9的自然数:user_db_20151210;

2、数据库表名命名规范

采用26个英文字母(区分大小写)和0-9的自然数(经常不需要)加上下划线’‘组成;
命名简洁明确,多个单词用下划线’
‘分隔;
例如:user_login, user_profile, user_detail, user_role, user_role_relation,
user_role_right, user_role_rightrelation
表前缀’user
‘可以有效的把相同关系的表显示在一起;

3、数据库表字段名命名规范

采用26个英文字母(区分大小写)和0-9的自然数(经常不需要)加上下划线’‘组成;
命名简洁明确,多个单词用下划线’
‘分隔;
例如:user_login表字段 user_id, user_name, pass_word, eamil, tickit, status, mobile, add_time;
每个表中必须有自增主键,add_time(默认系统时间)
表与表之间的相关联字段名称要求尽可能的相同;

4、数据库表字段类型规范

用尽量少的存储空间来存数一个字段的数据;
例如:能使用int就不要使用varchar、char,能用varchar(16)就不要使用varchar(256);
IP地址最好使用int类型;
固定长度的类型最好使用char,例如:邮编;
能使用tinyint就不要使用smallint,int;
最好给每个字段一个默认值,最好不能为null;

5、数据库表索引规范

命名简洁明确,例如:user_login表user_name字段的索引应为user_name_index唯一索引;
为每个表创建一个主键索引;
为每个表创建合理的索引;
建立复合索引请慎重;

6、简单熟悉数据库范式

第一范式(1NF):字段值具有原子性,不能再分(所有关系型数据库系统都满足第一范式);
例如:姓名字段,其中姓和名是一个整体,如果区分姓和名那么必须设立两个独立字段;

第二范式(2NF):一个表必须有主键,即每行数据都能被唯一的区分;
备注:必须先满足第一范式;

第三范式(3NF):一个表中不能包涵其他相关表中非关键字段的信息,即数据表不能有沉余字段;
备注:必须先满足第二范式;
数据库的三范式:
①字段不可分。
②有主键,非主键字段依赖主键。
③非主键字段不能互相依赖。

备注:往往我们在设计表中不能遵守第三范式,因为合理的沉余字段将会给我们减少join的查询;
例如:相册表中会添加图片的点击数字段,在相册图片表中也会添加图片的点击数字段;

MYSQL数据库设计原则

1、核心原则

不在数据库做运算;
cpu计算务必移至业务层;
控制列数量(字段少而精,字段数建议在20以内);
平衡范式与冗余(效率优先;往往牺牲范式)
拒绝3B(拒绝大sql语句:big sql、拒绝大事物:big transaction、拒绝大批量:big batch);

2、字段类原则

用好数值类型(用合适的字段类型节约空间);
字符转化为数字(能转化的最好转化,同样节约空间、提高查询性能);
避免使用NULL字段(NULL字段很难查询优化、NULL字段的索引需要额外空间、NULL字段的复合索引无效);
少用text类型(尽量使用varchar代替text字段);

3、索引类原则

合理使用索引(改善查询,减慢更新,索引一定不是越多越好);
字符字段必须建前缀索引;
不在索引做列运算;
innodb主键推荐使用自增列(主键建立聚簇索引,主键不应该被修改,字符串不应该做主键)(理解Innodb的索引保存结构就知道了);
不用外键(由程序保证约束);

4、sql类原则

sql语句尽可能简单(一条sql只能在一个cpu运算,大语句拆小语句,减少锁时间,一条大sql可以堵死整个库);
简单的事务;
避免使用trig/func(触发器、函数不用客户端程序取而代之);
不用select (消耗cpu,io,内存,带宽,这种程序不具有扩展性);
OR改写为IN(or的效率是n级别);
OR改写为UNION(mysql的索引合并很弱智);
select id from t where phone = ’159′ or name = ‘john’;
=>
select id from t where phone=’159′
union
select id from t where name=’jonh’
避免负向%;
慎用count(
);
limit高效分页(limit越大,效率越低);
使用union all替代union(union有去重开销);
少用连接join;
使用group by;
请使用同类型比较;
打散批量更新;

5、性能分析工具

show profile;
mysqlsla;
mysqldumpslow;
explain;
show slow log;
show processlist;

程序员必备知识点

程序员必备知识点

1、tcp 三次握手,四次挥手

为什么连接的时候是三次握手,关闭的时候却是四次握手?

image-20200928193010926

image-20200928193246073

原文链接:https://blog.csdn.net/whuslei/article/details/6667471

2、tcp 拆包、粘包问题。

应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包。

应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包。

进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度>MSS的时候将发生拆包。

接收方法不及时读取套接字缓冲区数据,这将发生粘包。

粘包、拆包解决办法

TCP本身是面向流的,作为网络服务器,如何从这源源不断涌来的数据流中拆分出或者合并出有意义的信息呢?通常会有以下一些常用的方法:

1、发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。

2、发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。

3、可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。

3、linux io 类型。

4、线程reactor 模型。

5、redis 分布式锁

6、sortSet 排序时间复杂度,及常用命令

Java基础

ArrayList源码

HashMap源码

ConcurrentHashMap源码

线程池ThreadPool

synthronized, volatile, Lock的使用和区别

NIO实现

工厂,代理,单例模式(单例模式多线程问题)

cglib与proxy的使用和区别

Java可重入锁和读写锁

JVM内存模型

JVM GC机制和相关算法

JVM类的加载

JVM性能调优的大体步骤

CAS算法

一致性Hash

arrayList底层结构,linkedList底层结构,两者的区别(RandomAccess)

hashmap底层结构(java8版本),concurrentHashMap(java8版本)、hashTable,三兄弟对比下吧?

nio和bio相比有啥不同(aio呢)

jvm内存划分(java8版本呢?),堆的划分(系统遇到瓶颈,确定是JVM引起,怎么调优,说下具体做法)

成员变量、局部变量等等的会分配到jvm的哪块儿区域

mysql的引擎知道哪些,有啥区别

乐观锁、悲观锁

索引相关的(btree、失效、组合索引的最左分配原则、explain使用)

线程池相关

volitatle关键字

lock的读写、中断、自旋

对threadLocal的理解

序列化、反序列化(一个已经实现Serializable的类,新增个属性,怎样让程序直接报错)

servlet是否线程安全(为什么你认为是/否)

对dubbo的理解(画下provider、consumer、注册中心、监控的关系)

consumer1次调用provider,在dubbo内部各模块运转的流程

谈谈你对mq的理解(你用的activemq,那kafka与之对比,有啥优势呢)

maven中install、package命令的区别

用过哪些设计模式,单例的懒汉、饿汉、线程安全的懒汉、最好的线程安全懒汉实现?

int的位数

1.字节:byte:用来计量存储容量的一种计量单位;位:bit

2.一个字节等于8位 1byte = 8bit

char占用的是2个字节 16位,所以一个char类型的可以存储一个汉字。

整型:

byte:1个字节 8位 -128~127

short :2个字节 16位

int :4个字节 32位

long:8个字节 64位

浮点型:

float:4个字节 32 位

double :8个字节 64位

注:默认的是double类型,如3.14是double类型的,加后缀F(3.14F)则为float类型的。

char类型:

char:2个字节。

Boolean 类型

boolean: (true or false)(并未指明是多少字节 1字节 1位 4字节)

补充:BigInteger类实现了任意精度的整数运算,BigDecimal实现了任意精度的浮点数运算。

hashMap ConcurrentHashMap 区别,hash冲突如何解决的?

synchronized 和lock的区别,synchronized是悲观锁还是乐观锁,cas算法

https://km.sankuai.com/page/34303789

即compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数

需要读写的内存值 V

进行比较的值 A

拟写入的新值 B

当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试。

3、谈谈threadLocal的理解、InheritableThreadLocal 、TransmittableThreadLocal 以及fastThreadLocal

参考答案:https://mlog.club/article/22197

不清楚,使用注意不清楚。

3、线程池

https://www.cnblogs.com/shijiaqi1066/p/3412300.html

构建常用的线程池不清楚,线程池核心参数不清楚 ,流程不清楚

4、请你说一下自己对于 AQS 原理的理解、

参考答案:https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/Multithread/AQS.md

5、CyclicBarrier 和 CountDownLatch 的区别

对于 CountDownLatch 来说,重点是“一个线程(多个线程)等待”,而其他的 N 个线程在完成“某件事情”之后,可以终止,也可以等待。而对于 CyclicBarrier,重点是多个线程,在任意一个线程没有完成,所有的线程都必须等待。

CountDownLatch 是计数器,线程完成一个记录一个,只不过计数不是递增而是递减,而 CyclicBarrier 更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行。

6、aop实现原理:动态代理、cglib,

两种实现有什么区别:基于接口、基于继承类

MyBatis中#与$的区别

jvm

1、描述下jvm内存模型

2、JVM参数Xms Xmx是如何设置的, 如果大小是一至,为什么这样设置?

参考答案:

Xmx设置JVM 的最大可用内存,Xms 设置JVM实际使用内存,一般Xmx和Xms相同,这是因为当Xmx内存空间不够用时,将进行扩容导致Full GC。将Xmx和Xms设置成相同的值,避免因Xms偏小导致频繁重新分配内存,影响应用使用。

2、有遇到过OOM么,什么情况,怎么发现的,怎么查原因的?

考察点:jstat mat工具

3、如何定位一个CPU Load过高的java线程?

top -c

top -Hp pid

printf “%x\n” pid (将pid转换16进制表示的)

定位线程堆栈 jstack 29054 | grep ‘0x1a17’ -C30 —color

redis

分布式锁:一般,只是提到加超时时间

持久化:rdb、aof,可以

AOF更安全,可将数据及时同步到文件中,但需要较多的磁盘IO,AOF文件尺寸较大,文件内容恢复相对较慢, 也更完整。

RDB持久化,安全性较差,它是正常时期数据备份及 master-slave数据同步的最佳手段,文件尺寸较小,恢复数度较快。

缓存穿透:可以

注意事项:大key

设计模式

mysql

事务隔离级别:OK,默认级别不清楚

慢查询:explain 不清楚

mysql 常见存储引警-清楚 ,聚簇索引和非聚簇索引的区别不清楚

索引最左前缀:理解,了解了

分表:分表维度理解可以

数据迁移:停服务,mq双写

怎么保证迁移后数据正确:记录数,

mvcc :同一份数据临时保留多版本的一种方式,进而实现并发控制

算法:

1、螺旋打印矩阵

https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-leetcode/

2、倒叙速出

主动学习:看过什么书,印象深的点是什么?如何自我学习?

Springboot学习,大V的学习问题解决思路;自己做笔记!

Appollo配置中心原理

Appollo配置中心原理

总体设计图:

image-20200825134410863

Apollo的总体设计,自下而上看:

  • Config Service 提供配置的读取、推送等功能,服务对象是Apollo客户端
  • Admin Service 提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面)
  • Config Service 和 Admin Service 都是多实例、无状态部署,所以需要将自己注册到 Eureka 中并保持心跳
  • 在Eureka之上架了一层 Meta Server 用于封装 Eureka 的服务发现接口
  • Client 通过域名访问 Meta Server 获取 Config Service 服务列表(IP+Port),而后直接通过 IP+Port 访问服务,同时在 Client 侧会做 load balance、错误重试
  • Portal 通过域名访问 Meta Server 获取 Admin Service 服务列表(IP+Port),而后直接通过 IP+Port 访问服务,同时在 Portal 侧会做 load balance、错误重试
  • 为了简化部署,实际上会把 Config Service、Eureka 和 Meta Server 三个逻辑角色部署在同一个JVM进程中

四个核心模块及其主要功能

  1. ConfigService

    • 提供配置获取接口
    • 提供配置推送接口
    • 服务于Apollo客户端
  2. AdminService

    • 提供配置管理接口
    • 提供配置修改发布接口
    • 服务于管理界面Portal
  3. Client

    • 为应用获取配置,支持实时更新
    • 通过MetaServer获取ConfigService的服务列表
    • 使用客户端软负载SLB方式调用ConfigService
  4. Portal

    • 配置管理界面
    • 通过MetaServer获取AdminService的服务列表
    • 使用客户端软负载SLB方式调用AdminService

三个辅助服务发现模块

  1. Eureka

    • 用于服务发现和注册
    • Config/AdminService注册实例并定期报心跳
    • 和ConfigService住在一起部署
  2. MetaServer

    • Portal通过域名访问MetaServer获取AdminService的地址列表
    • Client通过域名访问MetaServer获取ConfigService的地址列表
    • 相当于一个Eureka Proxy
    • 逻辑角色,和ConfigService住在一起部署
  3. NginxLB

    • 和域名系统配合,协助Portal访问MetaServer获取AdminService地址列表
    • 和域名系统配合,协助Client访问MetaServer获取ConfigService地址列表
    • 和域名系统配合,协助用户访问Portal进行配置管理

Apollo客户端设计

image-20200825140157084

上图简要描述了Apollo客户端的实现原理:

  1. 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过Http Long Polling实现)
  2. 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。
  • 这是一个fallback机制,为了防止推送机制失效导致配置不更新
  • 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified
  • 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。
  1. 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中
  2. 客户端会把从服务端获取到的配置在本地文件系统缓存一份
  • 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置
  1. 应用程序从Apollo客户端获取最新的配置、订阅配置更新通知

配置更新推送实现

配置发送后的实时推送设计

image-20200825141138936

上图简要描述了配置发布的大致过程:

  1. 用户在Portal操作配置发布
  2. Portal调用Admin Service的接口操作发布
  3. Admin Service发布配置后,发送ReleaseMessage给各个Config Service
  4. Config Service收到ReleaseMessage后,通知对应的客户端

之前提到了Apollo客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。长连接实际上是通过Http Long Polling实现的,具体而言:

  • 客户端发起一个Http请求到服务端
  • 服务端会保持住这个连接60秒
  • 如果在60秒内有客户端关心的配置变化,被保持住的客户端请求会立即返回,并告知客户端有配置变化的namespace信息,客户端会据此拉取对应namespace的最新配置
  • 如果在60秒内没有客户端关心的配置变化,那么会返回Http状态码304给客户端
  • 客户端在收到服务端请求后会立即重新发起连接,回到第一步

考虑到会有数万客户端向服务端发起长连,在服务端使用了async servlet(Spring DeferredResult)来服务Http Long Polling请求。

Netty权威指南目录抄写

Netty权威指南

走进java NIO

java的I/O演进之路

NIO入门

Netty入门应用

TCP粘包/拆包问题的解决之道

分隔符和定长解码器的应用

编解码技术

Java序列化

Google Protobuf编解码

JBoss Marshalling编解码

HTTP协议开发应用

WebSocket协议开发

UDP协议开发

文件传输

私有协议栈开发

ByteBuf和相关辅助类

Channel和Unsafe

ChannelPipline和ChannelHandler

EventLoop和EventLoopGroup

Future和Promise

java多线程在Netty中的应用

Netty框架剖析

Netty行业应用

Netty未来展望

MySQL权限分配

MySQL权限分配

创建用户

1
2
3
4
5
6
7
8
9
10
11
use mysql;
语法:create user 'username'[@'host'] identified by 'password';
如:someuser 用户可以在所有主机登录,密码为 123456
CREATE USER 'someuser' IDENTIFIED BY '654321'
如:someuser 用户只能在本地登录
CREATE USER 'someuser'@'localhost' IDENTIFIED BY '654321'

查看用户权限

1
2
3
4
5
6
7
8
9
语法:SELECT privileges|* FROM user WHERE `user` = 'username';
如:查看someuser的权限
SELECT * FROM user WHERE `user` = 'someuser';
也可以用 SHOW GRANTS 查看 SHOW GRANTS FOR 'username' [@host];
SHOW GRANTS FOR someuser;

赋予用户权限

1
2
3
4
5
6
7
语法:GRANT privileges ON database.table TO 'username'@'host' [IDENTIFIED BY 'password'];
如:赋予 someuser在所有主机的所有权限,但不包含给其他账号赋予权限的权限(如果出现 Access denied for user 'root'@'localhost' to database 'newdatabase',需要退出当前用户,重新登录)
GRANT all ON *.* TO 'local_user'@'%';
FLUSH PRIVILEGES;
  • GRANT命令说明:
    • priveleges (权限列表),可以是all, 表示所有权限,也可以是select,update等权限,多个权限的名词,相互之间用逗号分开。
    • ON 用来指定权限针对哪些库和表。格式为数据库 .表名 ,点号前面用来指定数据库名,点号后面用来指定表名,*.* 表示所有数据库所有表。
    • TO 表示将权限赋予某个用户, 格式为username@host,@前面为用户名,@后面接限制的主机,可以是IP、IP段、域名以及%,%表示任何地方。注意:这里%有的版本不包括本地,以前碰到过给某个用户设置了%允许任何地方登录,但是在本地登录不了,这个和版本有关系,遇到这个问题再加一个localhost的用户就可以了
    • IDENTIFIED BY 指定用户的登录密码,该项可以省略(某些版本下回报错,必须省略)。
    • WITH GRANT OPTION 这个选项表示该用户可以将自己拥有的权限授权给别人。注意:经常有人在创建操作用户的时候不指定WITH GRANT OPTION选项导致后来该用户不能使用GRANT命令创建用户或者给其它用户授权。
      备注:可以使用GRANT重复给用户添加权限,权限叠加,比如你先给用户添加一个select权限,然后又给用户添加一个insert权限,那么该用户就同时拥有了select和insert权限。
  • 授权原则说明:
    • 只授予能满足需要的最小权限,防止用户干坏事。比如用户只是需要查询,那就只给select权限就可以了,不要给用户赋予update、insert或者delete权限。
    • 创建用户的时候限制用户的登录主机,一般是限制成指定IP或者内网IP段。
    • 初始化数据库的时候删除没有密码的用户。安装完数据库的时候会自动创建一些用户,这些用户默认没有密码。
    • 为每个用户设置满足密码复杂度的密码。
    • 定期清理不需要的用户。回收权限或者删除用户。

收回用户权限

1
2
3
语法:REVOKE privileges ON database.table FROM 'username'@'host';
如:收回 someuser 的写入和更新权限
REVOKE insert,update ON *.* FROM 'someuser'@'%';

删除用户

1
2
3
语法:DROP USER 'username'@'host';
如:删除本地用户 local_user
DROP USER 'local_user'@'localhost';

类装载

类加载

类的生命周期

graph LR

A(加载
loading) --> B(验证
Verification)--> C(准备
Preparation)-->D(解析
Resolution)-->E(初始化
Initialization)-->F(使用
Using)-->G(卸载
Unloading)
  1. 虚拟机规范严格规定了有且只有5中情况必须立即对类进行初始化(而加载、验证、准备自然要在此之前):
  2. 遇到new、getstatic、putstatic、或invokestatic这4条指令是,如果类没有进行过初始化,则先触发初始化。
  3. 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则要先触发初始化。
  4. 当初始化一个类的时候,如果发现其父类还没有初始化,则要先触发其父类初始化。
  5. 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会初始化这个主类。
  6. 当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则要先触发初始化。