- 面向对象特性:封装、继承、多态
- 集合: List、Set、Map
- 异常:
- Checked Exception
- Unchecked Exception: RuntimeException, Error, and their subclasses
- I/O:
- I/O Streams
- File I/O
- 缺点:性能低
- 原因:
- Method#invoke 方法会对参数做封装和解封操作
- 需要检查方法可见性
- 需要校验参数
- 反射方法难以内联
- JIT 无法优化
- 替代方案: 参考
- 原因:
- 获取Class对象:
- Object.getClass(): 一般对象类型的Class对象获取方式
.class
: 原始类型的Class对象获取方式,boolean.class
- Class.forName(): 根据类全名获取Class对象,
Class.forName("[Ljava.lang.String;")
, 获取String[]
Class对象 TYPE
field for primitive type wrappers:Doulbe.TYPE
- Class对象常见方法:
- 获取Class modifers:
c.getModifiers()
- 获取Type parameters:
c.getTypeParameters()
- 获取实现接口:
c.getGenericInterfaces()
- 获取父类:
c.getSuperClass()
- 获取Annotations:
c.getAnnotations()
- 获取字段:
c.getDeclaredField()
,c.getField()
- 获取方法:
c.getDeclaredMethod()
,c.getMethod()
- 获取构造方法:
c.getDeclaredConstructor()
,c.getConstructor()
- 获取Class modifers:
- 使用:
... Constructor<?>[] ctors = Test.class.getDeclaredConstructors(); Constructor ctor = null; for (int i = 0; i < ctors.length; i++) { ctor = ctors[i]; if (ctor.getGenericParameterTypes().length == 0) { break; } } try { // 1. 反射创建对象 Test t = (Test) ctor.newInstance(); System.out.println(t); // 2. 反射调用对象方法 Method declaredMethod = Test.class.getDeclaredMethod("setName", String.class); declaredMethod.invoke(t, "Reflection"); System.out.println(t); } catch (Exception e) { e.printStackTrace(); } ...
-
- 若两个线程A、B,分别对同一字段先后进行写读,则不能保证A线程对字段的写操作会被随后的B线程读操作可见,容易造成数据不一致问题; 此时对字段加上
volatile
关键字修饰,则可以保证以上场景的A线程写操作必定会被随后的B线程读操作可见,即保证了数据一致 - 注意:在多线程写的场景下,会出现race condition,此时即使字段加上
volatile
关键字也无法解决race condition,必须对操作加锁
- 若两个线程A、B,分别对同一字段先后进行写读,则不能保证A线程对字段的写操作会被随后的B线程读操作可见,容易造成数据不一致问题; 此时对字段加上
-
Runnable
-
Thread:
- Thread.sleep
- Thread.interrupted(), t.isInterrupted()
- t.join
-
Synchronization:
- Thread Interference
- Memory Consistency Errors
- Synchronized Methods and Synchronized Statements: Intrinsic lock
- Atomic Access
-
Lock: 参考
- ReentrantLock: 重入锁,拥有锁的线程可以再次持有锁
- ReadWriteLock: 读写锁,实现ReentrantReadWriteLock,维持一对读写锁
- 适用于多读少写的场景
- 写锁: 互斥锁
- 读锁: 当写锁未被持有时,可以被多个线程持有
- StampedLock: JDK1.8之后新增,也是读写锁的一种,但是比ReadWriteLock多了乐观读操作,优化了ReadWriteLock
- 适用于多读少写的场景
- Condition: @TODO
-
- Executor, ExecutorService, ScheduleExecutorService
- Thread Pools
- CachedThreadPool: 当需要的时候才创建线程,若线程池内有可用的线程也可复用,闲置线程默认等待60s销毁
- FixedThreadPool: 创建指定线程数量的线程池,若池内所有线程都有任务,则新任务将会在队列里等待
- ScheduledThreadPool: 创建调度线程池,具有定期执行或延期执行能力的线程池
- Fork/Join Framework
-
Concurrent Collections
- 接口:
BlockingQueue
: Defines a first-in-first-out data structure that blocks or times out when you attempt to add to a full queue, or retrieve from an empty queue.ConcurrentMap
: A subinterface ofjava.util.Map
that defines useful atomic operations. These operations remove or replace a key-value pair only if the key is present, or add a key-value pair only if the key is absent. Making these operations atomic helps avoid synchronization. The standard general-purpose implementation ofConcurrentMap
isConcurrentHashMap
, which is a concurrent analog ofHashMap
.ConcurrentNavigableMap
: A subinterface ofConcurrentMap
that supports approximate matches. The standard general-purpose implementation ofConcurrentNavigableMap
isConcurrentSkipListMap
, which is a concurrent analog ofTreeMap
.
- 接口:
-
Atomic Vairables
- 类型
- Bootstrap class loader: JVM's built-in class loader, it is the parent of all others class loaders.
- Application/System class loader: An application class loader loads our own files in the classpath.
- Extension class loader: It load classes that are an extension of the standard core Java classes (Sits in
$JAVA_HOME/lib/ext
directory).
- 加载原理:
- The
java.lang.ClassLoader.loadClass()
method is responsible for loading the class definition into runtime. It tries to load the class based on a fully qualified name. - If the class isnt' already loaded, it delegates the request to the parent class loader. This process happens recursively.
- Eventually, if the parent class loader doesn't find the class, then the child class loader will call
java.net.URLClassLoader.findClass()
method to look for classes in the file system itself. - If the last class loader isn't able to load the class either, it throws
java.lang.NoClassDefFoundError
orjava.lang.CLassNotFoundException
.
- The
- Every
Class
object contains areference
to the ClassLoader that defined it, except class objects for array class.
- 生命周期:
当Spring容器启动时,会根据bean的定义去实例化bean,如果bean定义了初始化方法(init,@PostConstruct,InitlizingBean.afterPropertiesSet),就先执行初始化方法;
当bean使用完后,如果bean定义了销毁方法(destroy,@PreDestroy,DisposableBean.destroy),就会执行销毁方法,然后销毁bean实例 - Scope:
- singleton(default): Single bean object instance per Spring IoC container.
- prototype: Opposite to singleton, it produces a new instance each and every time a bean is requested.
- request: A single instance will be created and available during complete lifecycle of an HTTP request. Only valid in web-aware Spring ApplicationContext.
- session: A single instance will be created and available during complete lifecycle of an HTTP session. Only valid in web-aware Spring ApplicationContext.
- application: A single instance will be created and available during complete lifecycle of ServletContext. Only valid in web-aware Spring ApplicationContext.
- websocket: A single instance will be created and available during complete lifecycle of WebSocket. Only valid in web-aware Spring ApplicationContext.
- 创建方式:
- Constructor
<bean id="exampleBean"/>
- Static factory method
<bean id="exampleBean" factory-method="createInstance"/>
- Instance factory method
<bean id="myFactoryBean" class="..."> <bean id="exampleBean" factory-bean="myFactoryBean" factory-method="createInstance"></bean>
- Setter Injection
public class TestSetterDI {
DemoBean demoBean = null;
public void setDemoBean(DemoBean demoBean) {
this.demoBean = demoBean;
}
}
- Constructor Injection
public class ConstructorDI {
DemoBean demoBean = null;
public TestSetterDI (DemoBean demoBean) {
this.demoBean = demoBean;
}
}
- BeanFactory
- ApplicationContext: 添加了读取properties配置,发布应用事件等能力
- ClassPathXmlApplicationContext
- FileSystemXmlApplicationContext
- XmlWebApplicationContext
- Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies.
If the target object to be proxied implements at least one interface, a JDK dynamic proxy is used.
If the target object does not implement any interfaces, a CGLIB proxy is created. - Advice 类型: Before, after, around
- 术语:
- Aspect 切面: 事务管理,日志等等
- Joint Point 切入点: 方法的执行,异常的处理等
- Advice 切入逻辑: 被切入的逻辑, 类型有 Before, after returning, after throwing, after, around.
- Pointcut 切入点的定义: 用表达式去定义切入点,譬如
execution (* Classname.methodName(..))
- Introdcution 切面所新增的方法和字段
- Target Object: 被切入的对象,也叫 advised object.
- AOP Proxy 代理:
- JDK Dynamic Proxy: 基于interface的代理
- CGLIB Proxy: 基于class的代理
-
Front controller: DispatcherServlet
-
Spring web 容器启动后,根据配置(applicationContext.xml或注解或JavaConfig)会默认注册一系列的组件
public class MvcNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser()); registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser()); registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser()); registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser()); registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser()); registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser()); registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser()); registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser()); registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser()); registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser()); registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser()); registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser()); } }
- 以
AnnotationDrivenBeanDefinitionParser
为例 - 注册以下
HandlerMapping
:- RequestMappingHandlerMapping
- BeanNameUrlHandlerMapping
- 注册以下
HandlerAdapter
:- RequestMappingHandlerAdapter
- HttpRequestHandlerAdapter
- SimpleControllerHandlerAdapter
- 注册以下
HandlerExceptionResolver
:- ExceptionHandlerExceptionResolver
- ResponseStatusExceptionResolver
- DefaultHandlerExceptionResolver
- 且注册的
RequestMappingHandlerAdapter
及ExceptionHandlerExceptionResolver
都默认配置了以下实例:- ContentNegotiationManager
- DefaultFormattingConversionService
- LocalValidatorFactoryBean(如果
JSR-303
实现类库存在classpath中) - 一些HttpMessageConverter(具体视classpath中的第三方类库而定)
- 默认的ArugmentResolvers
- 默认的InitBinderArgumentResolvers
- 默认的ReturnValueHandlers
RequestMappingHandlerAdapter.javapublic void afterPropertiesSet() { ... if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.returnValueHandlers == null) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } }
- 以
-
Spring MVC 处理请求流程:
- 所有请求首先都由 DispactherServlet 处理
- 为请求设置 applicationContext, localeResolver, themeResolver等等
- 根据容器内已注册的Handlers,按顺序为请求匹配 Handler,如RequestMappingHandlerMapping,BeanNameUrlHandlerMapping
- 根据容器内已注册的Adapters,按顺序为 Handler 匹配 Adapters, 如RequestMappingHandlerAdapter
- 由Adapter调用已匹配的Handler,开始执行业务逻辑,得到响应或抛出异常
- 根据请求信息和ArgumentResolver,解析业务方法参数
InvocableHandlerMethod.javapublic Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } return doInvoke(args); }
- 由已注册的ReturnValueHandler,解析业务方法返回值
ServletInvocableHandlerMethod.javapublic void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { ... try { this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } ... }
- 若得到正常响应,则渲染ModelAndView,由LocaleResolver设置本地化信息,查找匹配的ViewResolver,解析真实的View进行渲染
- 若抛出异常,则解析异常,查找匹配的HandlerExceptionResolver,解析异常的View或设置http status code返回
- 根据请求信息和ArgumentResolver,解析业务方法参数
事物传递类型: 参考
Provides server-side and client-side support for externalized configuration in distributed system.
- Config Server
- Config Client
- 缓存:
- 一级缓存: 默认开启, Session cache within a SqlSession. It can not be accessed from another SqlSession.
一级缓存开启情况下,当多个会话同时对同个数据进行读写,很容易造成数据脏读. 建议关闭,设置为Statement
. - 二级缓存: 默认关闭,Global cache is shared among SqlSessions.
分布式环境需要使用缓存中间件实现数据一致
- 一级缓存: 默认开启, Session cache within a SqlSession. It can not be accessed from another SqlSession.
- 批量插入:
- 利用
<foreach>
标签: 插入量大时,性能差
<insert id="batchInsert" parameterType="..." useGenerate> INSERT INTO TABLE_NAME(field1, field2) VALUES <foreach collection="list" item="model" seperator=","> (model.field1, model.field2) </foreach> </insert>
- 利用MyBatis的
Batch Insert Support
,需要设置ExecutorType.BATCH
: 针对插入量大的情况
... try(SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { SimpleTableMapper mapper = session.getMapper(SimpleTableMapper.class); List<SimpleTableRecord> records = getRecordsToInsert(); // not shown BatchInsert<SimpleTableRecord> batchInsert = insert(records) .into(simpleTable) .map(id).toProperty("id") .map(firstName).toProperty("firstName") .map(lastName).toProperty("lastName") .map(birthDate).toProperty("birthDate") .map(employed).toProperty("employed") .map(occupation).toProperty("occupation") .build() .render(RenderingStrategies.MYBATIS3); batchInsert.insertStatements().forEach(mapper::insert); session.commit(); } ...
- 如果写xml mapper,创建的`SqlSession`必须设置`ExexcutorType.BATCH`:[参考](https://stackoverflow.com/questions/36407980/mybatis-performance-of-bulk-operator/36425820)
- 利用
- 缓存
- 映射关系
- 数据类型
- Strings: String值默认最大可存储512M
Command:SET
,GET
,INCR
,DECR
... - Lists: Lists of strings. Sorted by insertion order by default. Can add elements on the head or on the tail.
Command:LPUSH
,LPOP
,LSET
,LRANGE
... - Sets: An unordered collection of Strings. Can add, remove, test for existence of members in O(1).
Command:SADD
,SPOP
,SMEMBERS
,SISMEMBER
... - Hashes: Map between string fields and string values.
Command:HSET
,HGET
,HDEL
,HMSET
... - Sorted sets: Sets in order with score.
Command:ZADD
,ZRANGE
,ZINCRBY
,ZSCORE
...
- Strings: String值默认最大可存储512M
- 高可用: Redis Sentinel, Redis Cluster, Redis 主从
- 持久化:
- RDB: 快照,以指定时间间隔保存数据。例如在24小时内的每小时间隔,以及30天内每天间隔保存快照。
- AOF: 追加文件,服务器记录每一个写操作。服务器重启时,再根据记录重建数据。所有命令都会以Redis协议格式记录,追加到数据文件。
- 分布式锁: @TODO 参考
- 实现类库: Redisson
-
问题
- 脏读: 一事务中可以读到其他事务未提交的数据
- 不可重复读: 在一事务中,两次读同一数据,两次结果不同
- 幻读: 在一事务中,同样条件两次查询数据,两次条数不同
-
MySQL(InnoDB): 参考
- ACID特性:
- Atomicity: 原子性,一个事务是一个不可分割的工作单位,要么都做,要么不做。
- Durability: 持久性,保证事务提较后,不会因为宕机等原因导致数据丢失。
- Isolation: 隔离性,保证事务执行尽可能不受其他事务影响。
- Consistency: 一致性,保证事务执行结束后,数据库的完整性约束没有被破坏,事务执行前后都是合法的数据状态。
- 事务隔离级别: 隔离级别越低,系统开销越低,可支持的并发越高,隔离性越差
- Read Uncommitted: 读未提交
- Read Committed: 读已提交
- Repeatable Read: 可重复读
InnoDB默认隔离级别RR,InnoDB通过MVCC Multi-Version Concurrency Control 多版本并发控制,避免了RR脏读、不可重复读、幻读的问题 - Serializable: 串行化
隔离级别 脏读 不可重复读 幻读 Read Uncommitted 可能 可能 可能 Read Committed 不可能 可能 可能 Repeatable Read 不可能 不可能 可能 Serializable 不可能 不可能 不可能 - 索引
- ACID特性:
- 最大并发请求数:视connector类型而定,NIO默认10000,APR/Native默认8192,可修改
maxConnections
参数参见
- 负载均衡
-
均衡方法:
- round-robin: 默认,轮询
- least-connected: 分配给最少连接的server
- ip-hash: 基于连接ip,以ip hash来决定连接的server
- 其他:
- 还可以配置server 权重,以下配置,每5个请求将会有3个连接
srv1
server,srv2、srv3各1个
upstream myapp1 { server srv1.example.com weight=3; server srv2.example.com; server srv3.example.com; }
- 还可以配置server 权重,以下配置,每5个请求将会有3个连接
-
配置:
http { upstream myapp1 { [least_conn | ip_hash] server srv1.example.com; server srv2.example.com; server srv3.example.com; } server { listen 80; location / { proxy_pass http://myapp1; } } }
-
- 动态路由
- HotSpot JVM:
- JVM内存结构和内存模型: 参考0,参考1, 参考2
- Class Loader Subsystem: Classloader is used to load class files.
- Runtime Data Area:
- Method Area: Method area stores data for each and every class like fields, constant pool, methods'data and information
- Heap: Heap is place where all objects are stored in JVM
- Young generation:
- Eden
- Survivor Space:
- S0
- S1
- Old(Tenured) generation
- Permanent generation
- Young generation:
- Java Threads(Java thread Stack): Whenever new method is called, new stack frame is created and it is pushed on top of
that thread's stack - Program counter registers(PC Registers)
- Native internal Threads(Native thread Stack)
- Execution Engine:
- JIT compiler
- Garbage Collector: JVM clears objects from heap to reclaim heap space
- Circular references
- GC Roots: 参考1, 参考2
- local variables, still in the stack of a thread
- active threads
- static variables
- JNI references
- GC Tuning:
- Java 6
- Java 8
- Heap:
-Xms
,-Xmx
: Set the size of minimum/maximum heap-Xmn
: Set the size of young generation-XX:NewRatio
: Control the size of young/old generation ratio-XX:NewRatio=3
, means that the ratio between the young and old generation is 1:3-XX:NewSize
,-XX:MaxNewSize
: Set minimum/maximum size of young generation-XX:PermSize
,-XX:MaxPermSize
: Set minimum/maximum size of permanent generation