1. 容器的初始化(一) Root WebApplicationContext容器
概述123456789101112131415161718192021222324252627<!-- [1] Spring配置 --><listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 指定Spring Bean的配置文件所在目录。默认配置在WEB-INF目录下 --><context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/applicationContext.xml</param-value></context-param><!-- [2] Spring MVC配置 --><servlet> ...
1. JAVA代码执行机制
JAVA代码编译机制JVM规范定义了class文件格式,但并未定义java源码如何编译为class文件,各个厂家实现JDK时,通常会将符合java语言规范的源码编译为class文件的编译器,例如sun JDK中是javac
分析和输入到符号表(Parse and Enter)
Parse过程所做的为词法和语法分析。词法分析(com.sun.tools.javac.parser.Scanner)要完成的是将代码字符串转变为token序列(例如Token.EQ(name:=));语法分析(com.sun.tools.javac.parser.Parser)要完成的是根据语法由token序列生成抽象语法树 。
Enter(com.sun.tools.javac.comp.Enter)过程为将符号输入到符号表,通常包括确定类的超类型和接口、根据需要添加默认构造器、将类中出现的符号输入类自身的符号表中等。
注解处理
该步骤主要用于处理用户自定义的annotation,可能带来的好处是基于annotation来生成附加的代码或进行一些特殊的检查,从而节省一些共用的 ...
1. 内存分配TLAB
Java对象所占用的内存,多数是堆上进行分配,堆是所有线程共享的,因此在堆上进行分配需要进行加锁,这导致了创建对象开销很大。 当堆上空间不足时,会触发GC,如果GC后空间仍然不足,则会抛出OutOfMemory错误
Sun JDK为了提升内存分配效率,会为每个新创建的线程在新生代Eden Space上分配一个块独立的空间,成为TLAB(Thread Local Allocation Buffer),大小由JVM根据运行情况计算而得,可通过-XX:TLABWasteTargetPercent来设置TLAB所占用的Eden Space比例,默认为1%。
JVM根据上述比率、线程数量及线程是否频繁分配对象给每个线程分配合适大��的TLAB。在TLAB上分配内存时,不需要加锁,因此JVM在线程中的对象分配内存时,会尽量在TLAB上分配,如果对象过大或TLAB空间已用完,依旧会进行内存分配
因此,编写JAVA程序时,通常多个小对象比大的对象分配起来更加高效
可以通过在启动参数上添加-XX:PrintTLAB,来查看TLAB空间使用情况
1. JVM常见配置
123456789101112131415161718192021222324252627282930313233343536373839404142434445堆设置-Xms:初始堆大小-Xmx:最大堆大小-XX:NewSize=n:设置年轻代大小-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5-XX:MaxPermSize=n:设置持久代大小收集器设置-XX:+UseSerialGC:设置串行收集器-XX:+UseParallelGC:设置并行收集器-XX:+UseParalledlOldGC:设置并行年老代收集器-XX:+UseConcMarkSweepGC:设置并发收集器垃圾回收统计信息-XX:+PrintGC-XX:+PrintGCDetails-XX:+PrintGCTimeSta ...
1. JVM线程同步机制
1234int i=0;public int getNextId() { return i++;}
执行步骤:
JVM首先在main memory(JVM堆),分配给i一个内存存储场所(常量池),并赋值为0
线程启动后,自动分配一片working memory区(通常是操作数栈),当线程执行到return i++时,JVM中并不是简单的一个步骤完成的。
i++的动作,在JVM中分为:装载i、读取i、进行i+1操作、存储i及写入i,五个步骤:
装载i
线程发起一个装载i的请求给JVM线程执行引擎,引擎接收请求后,会向main memory发起一个read i指令
当read i执行完毕后一段时间,线程会将i的值从main memory区复制到working memory区中
读取i
此步负责从main memory中读取 i
进行i + 1
线程执行
存储i
将i+1的值,赋给i,然后存储到working memory中
写入i
一段时间后,会将i的值写入main memory
上述步骤,由于不是原子性操作的问题,在多 ...
1. 性能瓶颈分析
调优过程是一个复杂的过程,涉及很多方面:硬件、操作系统、运行环境软件以及系统本身。通常步骤如下
调优步骤
衡量系统现状
包括目前系统请求次数、响应时间、资源消耗等
设定调优目标
通常根据用户能接受的响应速度或系统所拥有的机器和所支撑的用户量来决定
找出性能瓶颈
结合工具找到造成瓶颈点的代码或配置
分析需求场景
结合优化技巧制定策略
选择收益比最高(优化后预期结果/优化需要付出的代价)的方案
优化部署后
如果成功,可结束
如���失败,则考虑是否产生了新的性能瓶颈或尝试上一步中的其他策略
可能的原因
资源消耗过多
CPU、文件IO、网络IO、内存等
外部处理系统性能不足
其他系统功能、数据库响应速度
代码效率不够高
未充分利用资源
程序结构不合理
1. 插件机制原理
在编写插件时,除了需要让插件类实现 Interceptor 接口外,还需要通过注解标注该插件的拦截点。所谓拦截点指的是插件所能拦截的方法,MyBatis 所允许拦截的方法如下:
Executor: update, query, flushStatements, commit, rollback,getTransaction, close, isClosed
ParameterHandler: getParameterObject, setParameters
ResultSetHandler: handleResultSets, handleOutputParameters
StatementHandler: prepare, parameterize, batch, update, query
如果我们想要拦截 Executor 的 query 方法,那么可以这样定义插件
1234567891011@Intercepts({ @Signature( type = Executor.class, method = "quer ...
1. 缓存类介绍
MyBatis 中,Cache 是缓存接口,定义了一些基本的缓存操作,所有缓存类都应该实现该接口。 MyBatis 内部提供了丰富的缓存实现类:
PerpetualCache
具有基本缓存功能
LruCache
具有 LRU 策略的缓存
SynchronizedCache
可保证线程安全的缓存
BlockingCache
具备阻塞功能的缓存
除此之外,还有很多缓存实现类。MyBatis 在实现缓存模块的过程中,使用了装饰模式。
PerpetualCache 相当于装饰模式中的ConcreteComponent
LruCache、SynchronizedCache和BlockingCache等相当于装饰模式中的ConcreteDecorator。
1. 内置数据源初始化过程
先来看一下数据源配置方法,如下:
123456<dataSource type="UNPOOLED|POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql..."/> <property name="username" value="root"/> <property name="password" value="1234"/></dataSource>
数据源的配置是内嵌在environment节点中的,MyBatis在解析environment节点时,会一并解析数据源的配置。MyBatis会根据具体的配置信息,为不同的数据源创建相应工厂类,通过工厂类 ...
1. SQL 执⾏入口
在单独使用 MyBatis 进行数据库操作时,我们通常都会先调用 SqlSession 接口的getMapper方法为我们的Mapper接口生成实现类。然后就可以通过Mapper进行数据库操作。比如像下面这样:
12ArticleMapper articleMapper = session.getMapper(ArticleMapper.class);Article article = articleMapper.findOne(1);
SqlSession 是通过JDK动态代理的方式为接口生成代理对象的。在调用接口方法时,相关调用会被代理逻辑拦截。在代理逻辑中可根据方法名及方法归属接口获取到当前方法对应的 SQL 以及其他一些信息,拿到这些信息即可进行数据库操作。
为 Mapper 接口创建代理对象我们从 DefaultSqlSession 的 getMapper 方法开始看起
12345678910111213141516171819202122232425// -☆- DefaultSqlSessionpublic <T> T getMapper(Class& ...