*基于javaGuide

java基础

  • 重载(override)要求子类的返回值小于父类(类型相同),修饰符使用范围也大于分类,抛出异常小于父类。
  • 静态方法不能调用类非静态方法,因为静态方法可以在不生成对象的时候直接调用。
  • 默认构造方法,因为子类构造的时候也调用super()父类,所以需要增加一个默认构造函数,避免编译出错。
  • java只有值传递:按值调用,按引用调用(其实也是按值调用,因为传的是一个指针地址)
  • 线程状态:初始状态->就绪状态->运行状态、阻塞状态、等待状态、超时等待状态->终止状态。
  • try:不能单独用,可以不加catch,但是最后要finally{}
  • synchronized:优化加了偏向锁,自旋锁/适应性自旋锁,轻量级锁,锁粗化,锁消除
  • volatile:直接从内存中取值,同时禁止指令重排。
  • 线程池的好处:1.减少创建和销毁线程池的开销、2.任务不用等创建线程即可运行,3.管理,调优,监控
  • 创建线程的方式:1.继承thread、2.实现Runable、3.实现callable

executor.submit()返回执行结果Future(get()返回结果会阻塞线程去执行完成),executor.execute()不返回执行结果

 
 
 
 
 
 
 
 
public ThreadPoolExecutor(int corePoolSize,//核心线程数量
                          int maximumPoolSize,//最大线程数量
                          long keepAliveTime, //超过核心线程数量时,多出的线程等待keepAliveTime                                                 时间后自行销毁 
                          TimeUnit unit,//上面时间的单位
                          BlockingQueue<Runnable> workQueue,//等待队列
                          ThreadFactory threadFactory,//创建新线程的时候用到
                          RejectedExecutionHandler handler //拒绝策略
                         ){...}
 
 

线程安全的理解:是有全局变量及静态变量引起的,只读没问题,但是写的要考虑线程同步。常量不会改没事,线程内的局部变量或者调用方法前每一个实例都是新建的,那也是线程安全的,因为不会访问共享的资源。

ReentrantLock 实现原理:基于AQS来实现。

Synchronized和Lock的异同:前者利用Object的notify/wait之类的调度,后者用Condition进行线程间调度。再者前者是可以加在方法/代码片段给JVM执行,后者直接代码段通过代码控制。前者自动释放,后者手动解锁。

JAVA的JUC、AQS

其实就是指java.util.concurrent/.atomic包下的东西,例如常见的有volatile<特性禁止指令重排(1-开辟空间,2-空间初始化,3-空间指向地址变量)>、cas、concurrentHashMap、ContDownLatch、实现Callable接口创建线程、ReentrantLock同步锁、ReadWriterLock读写锁、线程池

cas:compare and swap,比较旧的值,没有改变则更新为新的值。atomicInteger就是利用cas、volatile和native方法

AQS:位于java.util.concurrent.locks包下,AQS是一个用来构建锁和同步器的框架,例如ReentrantLock和Semaphore等等,原理:被请求的共享资源空闲,那么当前空闲的线程就会被标记为运行状态,资源也被标记为被锁定,需要一套线程阻塞等待以及被唤醒时锁分配的机制,AQS使用CLH队列锁(自旋锁,先来先服务,保证无饥饿)实现,即将暂时获取不到锁的线程放在队列中。

JVM

  • :对象和数组分配内存,是垃圾收集器管理的主要区域,又称为GC堆,1.7之后运行时常量池也在此

  • 方法区/元空间/直接内存:储存已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码数据

    线程独有

    • 程序计数器:保存下条指令、分支,循环,跳转、异常处理,线程恢复的位置,唯一不会OOM
    • 虚拟机栈:一个个栈帧,保存局部变量,操作数栈,动态链接,方法出入口信息
    • 本地方法栈:执行native方法

垃圾回收

基本采用分代垃圾回收算法,粗分为新生代和老年代,细分为eden,from survivor, to survivor,老年区

堆内存常见分配策略:对象优先在eden区分配,大对象直接进入老年代,长期存活的对象将进入老年代。

Minor GC:新生代垃圾收集动作,Minor GC非常频繁,回收速度一般也比较快。

FULL GC/Major GC: 发生在老年代的GC,速度比Minor GC慢10倍以上。

判断对象死亡:引用计数法, 可达性分析法(GC ROOT)

无用的类:所有实例被回收,加载该类的classLoader已被回收,对应的java.lang.class没有在任何地方被引用。

分代收集:新生代使用复制算法,老年代使用标记-清除或标记整理。

对象创建过程

  1. 类加载检查:虚拟机遇到一个new指令的时候,首先去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过,没有的话,必须执行相应的类加载过程。
  2. 分配内存:类加载过就可以确定所需内存大小,为对象分配内存就是在java堆中划分出来一块确定带下的内存。方式有“指针碰撞"和”空闲列表“,选择哪个方式取决于JAVA堆是否规整,而java堆是否规整又由采用的垃圾收集器是否带有压缩整理功能决定。涉及线程安全(采用CAS+失败重试,TLAB:每个线程预先分配内存,则首先在TLAB分配,大于剩余内存或快用完,就用上面的CAS)
  1. 初始化零值:内存空间初始化,类字段初始值
  2. 设置对象头:类的元数据信息,对象的哈希码,GC分代年龄
  3. 执行init方法

对象访问定位方式

1.使用句柄:堆中划分一块内存作为句柄,引用(变量名)储存的是对象的句柄地址,句柄包含对象实例数据地址指针和类型数据指针地址。对象移动只需要改变句柄的实例数据指针。

2.直接指针:引用储存的时候直接对象的地址,直接对象中包含到对象类型数据的指针和对象实例数据。速度快

CLASS文件

.class文件包含以下:

  • 魔数:确定这个class文件是否能被虚拟机接收。
  • class文件版本: class文件的版本号,保证编译正常执行。

类加载过程

类加载过程: 加载->链接->初始化。连接过程分为:验证->准备->解析

  1. 加载 :1.通过类名获取定义此类的二进制文字流(还可自定义类加载器)。2.字节流代表的静态储存结构转换为方法区的运行时数据结构。3.在内存中生成一个代表该类的Class对象,作为方法区这些数据的访问入口。

*数组类型不通过类加载器创建,它由Java虚拟机直接创建。

mybatis

#{}是静态替换变量有注入风险,${}是利用PreparedStatement的?替换,相对于加'',防止注入。

select|update|delete|insert|resultMap|parameterMap|sql|include|selectKey|

动态标签trim|where|set|foreach|if|choose|when|otherwise|bind

不同的xml写一样的namespace和id,可以但会覆盖,因为用的map<namespace+id,object>,没有写namespace的话相同id则会报错。

mybatis的executor执行器:(严格限制在SqlSession生命周期范围)

  1. SimpleExecutor:执行一次update或select,就开启一个Statement对象,用完立即关闭。
  2. ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,使用完不关闭,而是放在Map<String, Statement>重复利用。
  3. BatchExecutor:执行update(jdbc批处理不支持select),将所有sql添加到批处理中(addBatch),等待统一执行(executeBatch),它缓存多个Statement对象,先addBatch,再executeBatch

缓存

  • mybatis默认开启一级缓存,一级缓存是查询数据库前的最后一层缓存,使用PerpetualCache(即HashMap缓存),利用自动生成的cacheKey查询出数据,update/delete/insert提交回滚事务时会删除缓存。SqlSession级别的缓存。关闭方式有配置文件,插件,<insert ...flushCache="true">
  • 二级缓存比较复杂,涉及事务脏读,需要在**-mapping.xml配置来开启。mapper级别的缓存。两个Mapper的namespace如果相同,那么这两个Mapper执行的sql查询会被缓存在同一个二级缓存中。要开启二级缓存需要在配置文件中设置cacheEnabled属性为true。

Spring

spring是一些模块的集合,包括核心容器(DI,验证,类型转换,资源,国际化,数据绑定,事件),数据访问/集成,Web,AOP,工具,消息,测试模块。

spring框架中用到哪些设计模式

  1. 工厂设计模式:beanFactory、ApplicationContext创建bean对象
  2. 代理设计模式:AOP
  3. 单例设计模式:默认都是单例的注入对象
  4. 模板方法模式:spring中的jdbctemplate、hibernatetempleta,redistemplate等
  5. 包装器模式:链接多个数据库,不同客户每次访问不同数据库。

spring AOP

使用的是代理模式,如果代理的是一个接口的话,就用java动态代理,如果是其他的类,使用CGLIB。

spring事务

  • 事务的特性:ACID(原子性、一致性、隔离性、持久性)

  • 并发事务带来的问题:脏读、丢失修改、不可重复读、幻读。

    TransactionDefinition接口定义了五个表示隔离级别的常量

    TransactionDefinition.ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.

    TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

    TransactionDefinition.ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

    TransactionDefinition.ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

    TransactionDefinition.ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

    事务传播行为

    当事务方法被另一个事务方法调用是,必须指定事务应该如何传播。

    支持当前事务的情况:

    • TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
    • TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    • TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

    不支持当前事务的情况:

    • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
    • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    • TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

    其他情况:

    • TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

springboot

  • 相对于spring更加纯注解开发,减少配置和大量样板代码。
  • 与spring生态系统的天然结合。
  • 可以使用内置工具(如Maven和Gradle)开发管理jar和测试Spring Boot应用程序。
  • 提供内嵌的HTTP服务器。
  • 提供命令行接口工具

1. 读取配置文件信息

  • @Value("${property}") 不被推荐
  • @ConfigurationProperties(prefix = "library") 与bean绑定,改bean注解@Component
  • @EnableConfigurationProperties(ProfileProperties.class) 用于启动类上, 配置类用@ConfigurationProperties("my-profile"),这个可以加@notnull之类的校验
  • @PropertySource("classpath:website.properties") 读取指定文件,加@Component

2.全局异常

  • @ControllerAdvice(assignableTypes = {ExceptionController.class})用于类、@ExceptionHandler(value = Exception.class)用于方法
  • @ResponseStatus(code = HttpStatus.NOT_FOUND) 返回特定的码,用于异常类。
  • 方法里throw new ResponseStatusException,没效果

过滤器

  • @Configuration类下生成FilterRegistrationBean的@Bean
 
 
 
x
 
 
 
 
@Bean
    public FilterRegistrationBean<MyFilter> setUpMyFilter() {
        FilterRegistrationBean<MyFilter> filterRegistrationBean = new                FilterRegistrationBean<>();
        filterRegistrationBean.setOrder(2);
        filterRegistrationBean.setFilter(myFilter);
        filterRegistrationBean.setUrlPatterns(new ArrayList<>(Arrays.asList("/api/*")));
        return filterRegistrationBean;
    }
 
 

多个过滤器按指定顺序执行的话需要用上面的方法。

  • @WebFilter(filterName = "MyFilterWithAnnotation", urlPatterns = "/api/*"),启动类要加@ServletComponentScan

参数校验

springboot引进来的基础包上已经包含所要用的校验注解,其中在方法上使用在类的,加@Valid,单独参数的@Valid @NotNull之类(此时controller需要加注解@Validated)。值得一提的是,因为之前有同事说处理参数校验出错的时候,不用在代理里处理bindResult,其实这种说法并不对,因为不单独处理的话时候会抛出异常MethodArgumentNotValidException,如果使用全局异常处理的话,就可以集中处理这类问题。

除了contoller之外,service这些也可以使用

 
 
 
xxxxxxxxxx
 
 
 
 
@Service
@Validated
public class PersonService {
    public void validatePerson(@Valid Person person){
        // do something
    }
}
 
 
  • 自定义校验,实现的一个注解@interface,再实现一个具体类实现ConstraintValidator接口。
  • 校验组,例@NotNull(groups = DeletePersonGroup.class),DeletePersonGroup是接口,在方法上使用@Validated(AddPersonGroup.class)即可生效。

lombok

原文路径

  • val: 用在局部变量上,有点像js的val。
  • @cleanup: 释放资源
 
 
 
xxxxxxxxxx
 
 
 
 
    try {
        @Cleanup InputStream inputStream = new FileInputStream(args[0]);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
 
 
  • @NonNull: 用于方法参数上,遇到空的值会抛出空指针。
  • @ToString: 自动覆盖toString方法,例如@ToString(exclude=”id”)排除id属性,或者@ToString(callSuper=true, includeFieldNames=true)调用父类的toString方法,包含所有属性
  • @EqualsAndHashCode: 用在类上,自动生成equals方法和hashCode方法**
  • @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor:用在类上,自动生成无参构造和使用所有参数的构造函数以及把所有@NonNull属性作为参数的构造函数,如果指定staticName = “of”参数,同时还会生成一个返回类对象的静态工厂方法,比使用构造函数方便很多
  • @Data: 注解在类上,相当于同时使用了@ToString@EqualsAndHashCode@Getter@Setter@RequiredArgsConstrutor这些注解
  • @Value:用在类上,是@Data的不可变形式,相当于为属性添加final声明,只提供getter方法,而不提供setter方法
  • @Bulider: 用在类上,链式生成类
  • @Log: @CommonsLog、@Log、@Log4j、@Log4j2、@Slf4j、@XSlf4j
  • @SneakyThrows:自动抛受检异常,而无需显式在方法上使用throws语句
  • @Synchronized:用在方法上,将方法声明为同步的,并自动加锁,而锁对象是一个私有的属性$lock或$LOCK
  • @Getter(lazy=true):可以替代经典的Double Check Lock样板代码

设计模式

SOLID模式

  1. 单一原则:对象单一功能
  2. 开闭原则:对拓展开放,对修改关闭
  3. 里氏替换:程序中的对象应该是可以在不改变程序正确性的前提下被它的子类所替换的
  4. 接口隔离:多个特定客户端接口要好于一个宽泛用途的接口
  5. 依赖倒转:代码应当取决于抽象概念,而不是具体实现

数据库

优化方向:数据库表设计,良好的SQL、分库分表,读写分离、缓存、搜索引擎、硬件升级、索引使用、系统配置

第一范式是字段最小不可拆解,第二范式是字段和主键关联依赖,第三范式是字段和主键无间接关联(传递依赖)无冗余。

MVCC 一词代表的是多版本并发控制,只在READ COMMITED和REPEATABLE READ两个隔离级别下工作。

mysql存储引擎

  1. MyISAM:性能极佳,全文索引,压缩。但不支持事务和行级锁,只有表级锁,查询较快,崩溃无法恢复,不支持外键,不支持MVCC
  2. InnoDB:支持外键,事务/回滚,行级锁,崩溃可恢复,支持MVCC

mysql索引 :有Hash索引(单个查询)、BTree索引,全文索引(full text)

  1. MyISAM:B+Tree树叶节点的data域就是数据记录的地址,在索引检索的时候,先安装B+Tree搜索索引,如果指定KEY存在,就取出data域的值,然后更新域值存的地址读取相应的数据记录。非聚簇索引
  2. InnoDB:其数据文件本身就是索引文件,相比MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按B+Tree组织的一个索引结构,树的叶节点data域保存完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引,这称为聚簇索引。其他索引是辅助索引,叶节点为主键key和索引字段数据。

数据库事务

ACID:原子性、一致性、隔离性、持久性

redis

使用redis的好处是,一处缓存多处使用,同时有丰富的数据类型。redis是单线程的,但是IO多路复用。

数据类型:String、List、Hash、Set、Sorted Set、bitmap位图,geo地理位置等

过期删除:定期扫描随机删除,惰性删除查的时候检查是否要删。

提供了一些内存淘汰机制,一般用allkey-lru(内存不足时,删除最近最少使用的key)

持久化机制:RDB、AOF(数据有改就写、每秒写一次、让操作系统决定)

缓存雪崩:本身就要随机地设置过期时间。尽量保证redis集群高可用性,发现机器宕机尽快补上,选择合适的内存淘汰策略。事中本地ehcache缓存+hystrix限流&降级,避免Mysql崩掉。事后利用redis持久化机制恢复缓存。

缓存穿透:null也缓存时间短些,布隆过滤器。

缓存一致:肯定不能读写串行化,一般是先更新数据库,再删除缓存(更新复杂,尤其涉及多表。写频繁就改频繁,再者也是赌你不会那么快读数据),但是在更新数据库的过程中,缓存的数据还是旧的。面对高并发之下的不一致(先删缓存再更数据),更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个jvm内部队列中。读取数据的时候,如果发现数据不在缓存中,那么将重新执行"读取数据+更新缓存"的操作,根据唯一标识路由之后,也发送到同一个jvm内部队列中。一个队列对应一个工作线程,每个工作线程串行拿到对应的操作,然后一条一条的执行(一般就是会先执行更新数据库操作),这样的话,一个数据变更的操作,先删缓存,然后再去更新数据库,但是还没完成更新,如果一个读请求过来,没读到缓存,那么可以先将缓存更新的请求发送到队列中,此时会在队列中积压,然后同步等待缓存更新完成,最好不重复放到队列中。

网络问题

浏览器输入URL发生什么

  1. 查询本机或本浏览器或路由器的域名缓存,查出域名对应的IP和端口,如果没有则请求DNS服务器。
  2. 根据得到的IP和端口发起HTTP请求,达到指定的服务器
  3. 服务器根据请求的内容, 做出处理,然后响应返回到浏览器。
  4. 浏览器根据返回的内容或HTML渲染显示页面。

网络分层:

  1. 应用层:通过应用进程间交互来完成特定网络应用。DNS服务、HTTP服务等等,交互的数据单元称为报文。

  2. 运输层:负责向两台主机进程之间的通信提供通用的数据传输服务。

    用户数据协议UDP--提供无连接、尽最大努力的数据传输服务。(不保证数据传输的可靠性)

  3. 网络层:两个计算机之间经过很多数据链路,也可能通过很多通信子网,就是选择合适的网间路由,确保数据及时发送。把运输层报文段或用户数据报封装成分组和包,使用IP协议,因此分组也叫IP数据报。

  4. 数据链路层:链路层,两台主机的数据传输,总是在一段一段的链路上传送的,将IP数据报组装成帧,其为了数据正确传输,包含了数据验证和纠错。

  5. 物理层:数据单位是比特,实现相邻计算机节点之间比特流的透明传送,尽可能屏蔽具体传输介质和物理设备的差异。

三次握手:A-(SYN)-B,B-(SYN/ACK)-A,A-(ACK)-B。目的建立可靠的通信信道,确认双方发送接收正常。TCP用

四次挥手:A-(FIN)-B,B-(ACK)-A,B-(FIN)-A,A-(ACK)-B

HTTP长连接,短连接:http1.0短连接,每一个请求都建立一次链接。http1.1长连接保持连接性,请求头加上Connection:keep-alive,但是需要服务器也支持长连接。http1.1还增加了一些错误状态效应码,缓存处理更多,允许请求资源的某个部分。

URI:统一资源标志符,就像身份证号码

URL:统一资源定位符,提供资源的路径,就像个人地址。

HTTP和HTTPS的区别 : 1.端口,http用80,https用443。2.http运行在tcp之上,传输内容是明文,客服端和服务器端无法验证对方的身份。https是运行在SSL/TLS之上的HTTP协议,SSL/TLS运行在TCP之上,所有的内容都经过加密,但是HTTPS消耗资源给HTTP耗费更多。

认证授权

认证:你是谁,验证你的身份凭据,系统你知道你这个用户存在。

授权:发生在认证之后,访问系统的权限。

Spring Session:一般与redis使用,可以在不同的项目中共享session。支持一个域名,同一个项目部署多台tomcat,也支持一个域名多个项目,支持同一根域名多个子域名,不支持不同根域名实现session共享。

CSRF:跨站请求伪造,攻击者诱导受害者进入第三方网站,在第三方网站中,向北被攻击网站发送跨站请求,利用受害者已经获取的注册凭证,绕过后台的用户验证,达到冒充用户被攻击的网站执行某项操作的目的。

解决办法:同源策略,token(麻烦在某个请求都要验证)

OAuth2.0:主要用来授权第三方应用获取有限的权限。实际上它就是一种授权机制,它的最终目的是为第三方应用颁发一个有时效性的令牌token,使得第三方应用能够通过该令牌获取相关的资源,也常用于第三方登录,当你的网站接入了第三方登录的时候一般就是使用的OAuth2.0协议。

SSO:单点登录,一个平台登录,可以自动登入其他关联平台。解决公司多平台访问。

Nginx

六种负载均衡方式:(作用也是避免请求过了集中到一台机器)

其他

OOM怎么排查:如果JVM配置了-XX:+HeapDumpOnOutOfMemoryError,可以拿到发生OOM的时候,堆里面都有些什么。

一致性Hash:简单来说,就是一些节点发布在一个圆上,按顺时针找到第一个节点作为处理节点,会涉及增加节点和减少节点。一开始节点太少的时候,可以通过虚拟节点(即同一个节点A,虚拟节点A1,A2..但都是A处理)。

分布式事务

03-24 08:14