Java笔记


回答问题

是什么,为什么有它,解决什么问题,怎么解决?

读取列表

public class ReadList {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        String line = bufferedReader.readLine();
        int[] nums = stringToIntegerArray(line);
        System.out.println(Arrays.toString(nums));
        int k = Integer.parseInt(bufferedReader.readLine());
        System.out.println(k);
    }

    private static int[] stringToIntegerArray(String line) {
        line = line.trim();
        line = line.substring(1,line.length()-1);
        String[] strs = line.split(",");
        int[] output = new int[strs.length];
        for(int i=0;i<strs.length;i++) {
            output[i] = Integer.parseInt(strs[i].trim());
        }
        return output;
    }

    /**
     * [1,2,3        ,4,6 ]  
     * [1, 2, 3, 4, 6]
     * 5
     * 5
     */
}

concurrenthashmap

多线程分配任务

img

扩容时存取

20190602184408984

JVM gc root

堆、方法区是线程共享的,栈、本地方法栈、程序计数器是线程独有的。

JVM在垃圾回收的时候,要先找到垃圾对象,也就是没有引用的对象,但是直接找垃圾不好找,就反过来先找正常对象,这就需要从一些根开始,根据根的引用找到正常对象。这些根特征就是会引用其他对象,但是不会被引用,如:栈中的本地变量、本地方法栈中的变量、方法区中的静态变量。

Spring IOC启动流程

ioc容器的启动过程分为两个步骤,第一个阶段是容器的启动阶段,第二个阶段是bean实例化阶段。

image-20211220213356816

BeanDefinition 主要是用来描述 Bean,其存储了 Bean 的相关信息

bean实例化阶段:

image-20211220213623529

实例化、设置对象属性、配置依赖、会将对象实例传到 BeanPostProcessor,(方便做前置和后置处理)、注册回调接口。。。

Spring解决循环依赖

先问自己三个问题:是什么,如何出现的,怎么解决

是什么?循环依赖指的是bean和bean之间的依赖关系,循环依赖指的是两个或者多个bean相互依赖。

image-20211220203440006

Spring只解决了单例Bean的 setter 注入循环依赖,对于构造器循环依赖,和 prototype模式的循环依赖是无法解决的,在创建Bean的时候就会抛出异常。

Spring容器会将每一个正在创建的Bean标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中。因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖。

理论依据:java基于引用类型传递,获取对象引用时,对象的属性可以延后设置。

image-20211220211048658

对于单例模式,Spring整个容器的生命周期内,值存在一个对象,cache,解决循环依赖用到了三级cache

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of early singleton objects: bean name --> bean instance */
//实例化了,还没有初始化
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

image-20211220212235037

三级,如果有动态代理的需求,可以将原始bean包装后返回。二三级是为了功能的分离?

Spring @transactional

image-20211220155320038

spring定义了以@Transactional注解为切点,这样才知道其标注的方法需要被代理。

image-20211220192223313

把事务行为抽象为事务管理器、事务状态、事务定义这些形态,最终将事务的开启、提交、回滚嵌入到被增强方法的前后,完成统一的事务模型管理。

注意事项

一、抛出检查异常

@Transactional
void transfer() {
    try{
        //...
    } catch (Exception e){
        LOGGER.error(e.getMessage())
    }
}

方法如果是抛出检查异常,如fileNotFound,是不会回滚的,默认rollbackFor是运行时异常,可以指定rollbackFor。

@Transactional(rollbackFor = Exception.class)

二、错误try catch

捕获了异常,却没有抛出,事务不会被正确回滚。原因:Spring使用代理来管理事务,调用顺序:开启事务,执行目标方法,提交或者回滚事务,如果目标方法出现了异常,但是自己处理了,在代理类看来,就是目标方法没有抛出异常。

例如:错误情况:

@Transactional(rollbackFor = Exception.class)
public void transfer(int amount) {
    try{
        serviceB.sub(amount);
        serviceA.add(amount);
    } catch (Exception e) {
        LOGGER.error("error occur");
    }
}

正确做法是在catch里抛出异常或者手动告诉spring要回滚。

// 1
throw new RuntimeException(e);
// 2
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();

三、只能加在public方法

spring为这个方法创建代理,添加事务,前提是public

四、调用本类方法导致传播行为失效

websocket长连接

建立WebSocket连接的过程为:

1.客户端发起HTTP请求,经过3次握手建立TCP连接,HTTP请求里存放WebSocket支持的版本号等信息。

2.服务器收到客户端握手请求后,回馈数据。

以上两个步骤完成后,HTTP握手部分完成,协议升级为WebSocket,此时服务器就不再需要客户端发起请求,再响应请求了,可以主动推送信息给客户端了。

参考:

Spring的@Transactional如何实现的?