erudev / blog Goto Github PK
View Code? Open in Web Editor NEWPeople die,but long live in GitHub.
People die,but long live in GitHub.
掘金小册《玩转 MyBatis:深度解析与定制》笔记
SqlSession
是与 MyBatis 交互的核心接口(包括后续整合 Spring Framework 用到的 SqlSessionTemplate
);SqlSession
执行的方法,底层需要经过配置文件的解析、SQL 解析,以及执行 SQL 时的参数映射、SQL 执行、结果集映射,另外还有穿插其中的扩展插件;掘金小册《SpringBoot 源码解读与原理分析》笔记
@SpringBootApplication
是组合注解;@ComponScan
默认扫描当前配置类所在包以及包下所有组件,exclude
属性会将主启动类、自动配置类屏蔽掉;@Configuration
可标注配置类,SpringBootConfiguration
并没有对其做实质性扩展AutoConfigurationPackages.Registrar
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
ImportBeanDefinitionRegistrar 用于保存导入的配置类所在的根包
AnnotationMetadata
类的注解元数据,个人理解其实就是对类的包装
AutoConfigurationPackages#register
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
// 判断 BeanFactory 中是否包含 AutoConfigurationPackages
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
// addBasePackages:添加根包扫描包
constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
}
else {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}
小结:
@SpringBootApplication
标注的主启动类所在包会被视为扫描包的根包SPI 全称 Service Provider Interface,是 JDK 内置的一种服务提供发现机制。简单来说,它就是一种动态替换发现的机制。
SPI规定,所有要预先声明的类都应该放在 META-INF/services 中。配置的文件名是接口/抽象类的全限定名,文件内容是抽象类的子类或接口的实现类的全限定类名,如果有多个,借助换行符,一行一个。
SpringFramework的SpringFactoriesLoader
AutoConfigurationImportSelector
配合 SpringFactoriesLoader
可加载 “META-INF/spring.factories” 中配置的 @EnableAutoConfiguration
对应的自动配置类。DeferredImportSelector
的执行时机比 ImportSelector
更晚。public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
SpringApplication
的创建和运行是两个不同的步骤,上面代码是创建。ApplicationContextInitializer
和 ApplicationListener
,分别是初始化器和监听器,它们都在 构建 SpringApplication
时注册。【至此,SpringApplication
初始化完成,下面会真正启动 SpringApplication】
public ConfigurableApplicationContext run(String... args) {
// 4.1 创建StopWatch对象
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 4.2 创建空的IOC容器,和一组异常报告器
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 4.3 配置与awt相关的信息
configureHeadlessProperty();
// 4.4 获取SpringApplicationRunListeners,并调用starting方法(回调机制)
SpringApplicationRunListeners listeners = getRunListeners(args);
// 【回调】首次启动run方法时立即调用。可用于非常早期的初始化(准备运行时环境之前)。
listeners.starting();
try {
// 将main方法的args参数封装到一个对象中
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 4.5 准备运行时环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//.............
}
Environment
它是 IOC 容器的运行环境,它包括 Profile 和 Properties 两大部分,它可由一个到几个激活的 Profile 共同配置,它的配置可在应用级 Bean 中获取。
SpringApplicationRunListener
来监听 SpringBoot 应用的启动过程。Environment
//最终调到AbstractApplicationContext的refresh方法
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 1. 初始化前的预处理
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 2. 获取BeanFactory,加载所有bean的定义信息(未实例化)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 3. BeanFactory的预处理配置
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 4. 准备BeanFactory完成后进行的后置处理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 5. 执行BeanFactory创建后的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 6. 注册Bean的后置处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 7. 初始化MessageSource
initMessageSource();
// Initialize event multicaster for this context.
// 8. 初始化事件派发器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 9. 子类的多态onRefresh
onRefresh();
// Check for listener beans and register them.
// 10. 注册监听器
registerListeners();
//到此为止,BeanFactory已创建完成
// Instantiate all remaining (non-lazy-init) singletons.
// 11. 初始化所有剩下的单例Bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 12. 完成容器的创建工作
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
// 13. 清除缓存
resetCommonCaches();
}
}
}
BeanPostProcessor:Bean 的后置处理器,可以在对象实例化但初始化之前,以及初始化之后进行一些后置处理。
BeanDefinition
的过程。BeanFactory
的初始化中会注册后置处理器,和自动注入的支持。BeanPostProcessor
的执行时机是在 Bean 初始化前后执行。main() 函数退出后,该线程是否会强制退出?整个线程是否会强制退出?
不会。在t1.start() 前面加一行代码 t1.setDaemon(true)。当 main() 函数退出,线程 t1 会跟着退出,整个进程也会退出
线程被分为两类:守护线程和非守护线程,默认都是非守护线程。 在Java中有一个规定:当所有的非守护线程退出后,整个JVM进程就会退出。例如,垃圾回收线程就是守护线程,它们在后台默默工作,当开发者的所有前台线程(非守护线程)都退出之后,整个JVM进程就退出了。
锁的对象是什么?
class A{
public void synchronized f1() {...}
public static void synchronized f2() {...}
}
等价于如下代码:
class A {
public void f1 () {
synchronized (this) {...}
}
public void f1 () {
synchronized (A.class) {...}
}
}
对于非静态函数,锁其实是加在对象 a 上面的;对于静态函数,锁是加在 A.class 上的
锁的本质是什么?
从程序角度来看,锁其实就是一个 "对象":
打个比方,线程就是一个个游客,资源就是一个待参观的房子。这个房子每次只允许进去一个人,而锁就是这个房子的门卫。
volatile:64 位写入的原子性、内存可见性和禁止重排序
SHOW [GLOBAL|SESSION] VARIABLES [LIKE 匹配的模式]
; show variables like 'max_conn%'
字符集指的是某个字符范围的编码规则
比较规则是指对某个字符集中的字符比较大小的一种规则
MySQL 有 4 个级别的字符集和比较规则
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.