Spring5深度源码分析(三)之AnnotationConfigApplicationContext启动原理分析
代码地址:https://github.com/showkawa/spring-annotation/tree/master/src/main/java/com/brian
AnnotationConfigApplicationContext启动原理分析主要分析下面三点
1.@Qualifier与@Primary注解的使用
2.BeanFactory与ApplicationContext区别
3.AnnotationConfigApplicationContext启动原理分析
1.@Qualifier与@Primary注解的使用
下面是 @Qualifier 和 @Primary注解的官方解释
@Qualifier
This annotation may be used on a field or parameter as a qualifier for candidate beans when autowiring. It may also be used to annotate other custom annotations that can then in turn be used as qualifiers.这个注释可用于作为预备bean的字段或参数,也可以用在其他的自定义注释下 @Qualifier(“XXX”) Spring的Bean注入配置注解,该注解指定注入的Bean的名称,Spring框架使用byName方式寻找合格的bean,这样就消除了byType方式产生的歧义。
qualifer字面意思合格者,一般情况下:代码里面需要注入其他依赖,一般用@Reource( 默认按名称装配,当找不到与名称匹配的bean才会按类型装配和@Autowired(默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用)
@Primary
Indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If exactly one ‘primary’ bean exists among the candidates, it will be the autowired value. This annotation is semantically equivalent to the {@code} element’s {@code primary} attribute 不难看出如果用primary注解其中一个bean就要优先于其他的Bean,当然这个对于这种三方jar包最好不要添加的,谁知道它会不会后期又出什么幺蛾子,只能改自己的代码了最后的方案是改成@qualifiel(“getMetricRegistry”),选取了其中一个bean注入
primary字面意思最主要者,如果是有配置过多数据源,那一定会熟悉这个注解
1.1 @Qualifier的使用
我们这里定义一个BookService接口
public interface BookService { void printBook(); }
两个实现类BookServiceImpl和OtherBookServiceImpl实现BookService接口的printBook()方法
@Service
public class BookServiceImpl implements BookService {
@Override
public void printBook() {
System.out.println("---BookServiceImpl---: spring5源码分析");
}
}
@Service
public class OtherBookServiceImpl implements BookService {
@Override
public void printBook() {
System.out.println("---OtherBookServiceImpl---: 天道酬勤,一步一个坑");
}
}
我们在BookController注入BooKService
@Controller
public class BookController { @Autowiredprivate BookService bookService; private void printBook() {
bookService.printBook();
} }
附上配置类MainConfig
@Configuration //告诉spring这是一个配置类
/*
* @ComponentScan
* value:只当于扫描的的包
* excludeFilters = 指定扫描的时候按照什么规则排除哪些组件
* includeFilters = 指定扫描的时候只需要包含哪些组件
* Filter.ANNOTATION:按照注解
* Filter.ASSIGNABLE_TYPE: 按照给定的类型
* */ //@ComponentScans(value = {
// @ComponentScan(value = "com.brian",includeFilters = {
// @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
// @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}),
// @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {BrianTypeFilter.class})
// },useDefaultFilters = false)
//})
@ComponentScan({"com.brian.service", "com.brian.controller"})
//@Import({Brian.class,Alan.class})
@Import({BrianSelector.class})
public class MainConfig { @Bean("person") //给容器中注册一个Bean;类型为返回值的类型;id默认是方法名作为id
public Person person(){
return new Person("Alan",18);
} /*
* @Conditional() 按照条件注册
*
* */
@Conditional({BrianCondition.class})
@Bean("person01")
public Person person01() {
return new Person("Brian",17);
} @Conditional({BrianCondition.class})
@Bean("person02")
public Person person02() {
return new Person("wenTao",19);
} /*
*
*给容器中注册组件
* 1,包扫描+ 组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的方法]
* 2, @Bean [导入的第三方包里面的组件]
* 3,@Import [快速的给容器导入一个组件]
* 1.@Import(要导入的组件class)
* 2.ImportSelector:返回需要导入的组件的全类名数组
* 3.ImportBeanDefinitionRegistrar: 手动注册bean到容器
* 4. 使用Spring提供的FactoryBean
* */
@Bean
public BrianBeanFactory brianBeanFactory() {
return new BrianBeanFactory();
} }
在测试类MainTest类中测试该printBook()方法
public class MainTest {
public static void main(String[] args) {
ApplicationContext mainConfig =
new AnnotationConfigApplicationContext(MainConfig.class); System.out.println("MainConfig容器创建成功"); BookController bookController = mainConfig.getBean(BookController.class);
try {
Method printBook = bookController.getClass().getDeclaredMethod("printBook");
printBook.setAccessible(true);
printBook.invoke(bookController);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
// Alan alan1 = acac.getBean(Alan.class);
// System.out.println("--ALAN--:" + alan1);
// Alan alan2 = acac.getBean(Alan.class);
//System.out.println("比较两个Alan实例: " + (alan1 == alan2)); // Person person1 = (Person) acac.getBean("person01");
// System.out.println("---main---test---person1---: " + person1.toString());
// Person person2 = (Person) acac.getBean("person02");
// System.out.println("---main---test---person2---: " + person2.toString()); // MathCalculator mathCalculator = (MathCalculator) acac.getBean("mathCalculator");
// System.out.println("----get--mathCalculator---: " + mathCalculator); // BrianBeanFactory beanFactory = acac.getBean(BrianBeanFactory.class);
// WenTao wentao = null;
// try {
// wentao = beanFactory.getObject();
// } catch (Exception e) {
// e.printStackTrace();
// }
// System.out.println("----get--WenTao---: " + wentao); //关闭ioc容器
((AnnotationConfigApplicationContext) mainConfig).close();
}
}
看到有报错No qualifying bean of type 'com.brian.service.BookService' available: expected single matching bean but found 2: bookServiceImpl,otherBookServiceImpl,就是因为默认按类型装配
OK,此时我在BookController注入BookSevice的时候加上@Qualifier指定beanName,再次测试
@Controller
public class BookController { @Autowired
@Qualifier("bookServiceImpl")
private BookService bookService; private void printBook() {
bookService.printBook();
} }
1.2 @Primary的使用
继续返回到上面的报错时候的场景,因为此时BookService有两个实现类,此时我在OtherBookServiceImpl类上加上@Primary注解,再次测试
@Service
@Primary
public class OtherBookServiceImpl implements BookService {
@Override
public void printBook() {
System.out.println("---OtherBookServiceImpl---: 天道酬勤,一步一个坑");
}
}
这里顺便总结下常用的注解:
@Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@Scope注解 作用域
@Lazy(true) 表示延迟初始化
@Service用于标注业务层组件、
@Controller用于标注控制层组件
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope用于指定scope作用域的(用在类上)
@PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上)
@Resource 默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@DependsOn:定义Bean初始化及销毁时的顺序
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用
@Autowired @Qualifier("OtherBookServiceImpl") 存在多个实例配合使用
2.BeanFactory与ApplicationContext区别
之前的源码分析有见过BeanFactory和FactoryBean接口的区别,FactoryBean是创建bean对象,而BeanFactory是获取对象。但ApplicationContext也可以获取对象,我上面的测试类getBean()方法就是的。同样都可以获取bean对象BeanFactory与ApplicationContext有什么区别?
1. BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。
2. ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能:
a. 国际化支持
b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:E:/config.properties”
c. 事件传递:通过实现ApplicationContextAware接口 3. 常用的获取ApplicationContext的方法:
AnnotationConfigApplicationContext 从@Configuration配置类创建容器
FileSystemXmlApplicationContext:从【文件系统】 或者 【classpath的xml配置文件】 创建,参数为配置文件名或文件名数组
ClassPathXmlApplicationContext:从【classpath的xml配置文件】创建,可以从【jar包】中读取配置文件
WebApplicationContextUtils:从web应用的根目录读取配置文件,需要先在web.xml中配置,可以配置监听器或者servlet来实现
Spring的IoC容器就是一个实现了BeanFactory接口的可实例化类。事实上, Spring提供了两种不同的容器:一种是最基本的BeanFactory,另一种是扩展的ApplicationContext。
ApplicationContext的初始化和BeanFactory有一个重大的区别:
BeanFactory在初始化容器时 并未实例化Bean, 直到第一次访问 某个Bean时才实例目标Bean;而ApplicationContext则在初始化应用上下文时就实例化所有的单实例的Bean。
因此ApplicationContext的初始化时间会比BeanFactory稍长一些.
3.AnnotationConfigApplicationContext启动原理分析
从AnnotationConfigApplicationContext的类图中可以看出:
AnnotationConfigApplicationContext继承GenericApplicationContext这个通用应用上下文,GenericApplicationContext内部定义了一个DefaultListableBeanFactory实例,
GenericApplicationContext实现了BeanDefinitionRegistry接口,所以可以通过AnnotationConfigApplicationContext实例注册beanDefinition,然后调用refresh()方法来初始化上下文。
AnnotationConfigApplicationContext继承AbstractApplicationContext,AbstractApplicationContext提供了ApplicationContext的抽象实现。
我这边就从MainTest这个测试类开始AnnotationConfigApplicationContext启动原理分析:
MainTest测试类:
public class MainTest {
public static void main(String[] args) {
// 1.读取配置类创建IOC容器
ApplicationContext mainConfig =
new AnnotationConfigApplicationContext(MainConfig.class); System.out.println("MainConfig容器创建成功"); BookController bookController = mainConfig.getBean(BookController.class);
try {
Method printBook = bookController.getClass().getDeclaredMethod("printBook");
printBook.setAccessible(true);
printBook.invoke(bookController);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}//关闭ioc容器
((AnnotationConfigApplicationContext) mainConfig).close();
}
}
AnnotationConfigApplicationContext点进去,我这边后面的源码都会附带官方注释的翻译
/**
*创建一个新的AnnotationConfigApplicationContext,派生bean定义
*来自给定的带注释的类并自动刷新上下文。
* @param annotatedClasses一个或多个带注释的类,
*例如 {@link Configuration @Configuration}类
*/
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
//1. 初始化bean读取器和扫描器;
/** 调用父类GenericApplicationContext无参构造函数,初始化一个BeanFactory: this.beanFactory = new DefaultListableBeanFactory()*/
this();
// 2.注册bean配置类
register(annotatedClasses);
// 3.刷新上下文
refresh();
}
现在我们点进去this()这个方法;
/**
*创建一个需要填充的新AnnotationConfigApplicationContext
*通过{@link #register}调用,然后手动{@linkplain #refresh刷新}。
*/
public AnnotationConfigApplicationContext() {
//在IOC容器中初始化注解bean读取器AnnotatedBeanDefinitionReader
this.reader = new AnnotatedBeanDefinitionReader(this);
//在IOC容器中初始化按类路径扫描注解bean的扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
this()方法在调用自身的无参构造方法时会先走父类GenericApplicationContext的无参构造方法
/**
*创建一个新的GenericApplicationContext。
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext() {
//初始化一个BeanFactory
this.beanFactory = new DefaultListableBeanFactory();
}
现在我们再点进去看下register(annotatedClasses)这个方法,直接调用AnnotatedBeanDefinitionReader的register方法
/**
*注册一个或多个要处理的注释类。
* <p>对{@code register}的调用是幂等的; 添加相同的
*注释类不止一次没有额外的效果。
* @param annotatedClasses一个或多个带注释的类,
*例如 {@link Configuration @Configuration}类
*/
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
} /**
*从给定的bean类注册bean,从中派生元数据
*类声明的注释。
* @param annotatedClass bean的类
*/
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
} /**
*从给定的bean类注册bean,从中派生元数据
*类声明的注释。
* @param annotatedClass bean的类
* @param instanceSupplier用于创建bean实例的回调
*(可能是{@code null})
* @param命名bean的显式名称
* @param限定符特定限定符注释要考虑,如果有的话,
*除了bean类级别的限定符
* @param definition定制一个或多个用于自定义的回调
*工厂的{@link BeanDefinition},例如 设置lazy-init或主标志
* @since 5.0
*/
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
/** 将Bean配置类信息转成容器中AnnotatedGenericBeanDefinition数据结构,
* AnnotatedGenericBeanDefinition继承自BeanDefinition作用是定义一个bean的数据结构,
* 下面的getMetadata可以获取到该bean上的注解信息 */
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); //@Conditional装配条件判断是否需要跳过注册
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
//设置回调 @param instanceSupplier 用于创建bean实例的回调
abd.setInstanceSupplier(instanceSupplier); //解析bean作用域(单例或者原型),如果有@Scope注解,则解析@Scope,没有则默认为singleton
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); //作用域写回BeanDefinition数据结构, abd中缺损的情况下为空,将默认值singleton重新赋值到abd
abd.setScope(scopeMetadata.getScopeName()); //生成bean配置类beanName
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//通用注解解析到abd结构中,主要是处理Lazy, primary DependsOn, Role ,Description这五个注解
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); // @Qualifier特殊限定符处理,@param qualifiers 除了bean类级别的限定符之外,要考虑的限定符特定限定符注释(如果有)
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
// 如果配置@Primary注解,则设置当前Bean为自动装配autowire时首选bean
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
//设置当前bean为延迟加载
abd.setLazyInit(true);
}
else {
//其他注解,则添加到abd结构中
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
/**自定义bean注册,通常用在applicationContext创建后,手动向容器中一lambda表达式的方式注册bean,
* 比如:applicationContext.registerBean(BookService.class, () -> new BookService()); */
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
//自定义bean添加到BeanDefinition
customizer.customize(abd);
}
//根据beanName和bean定义信息封装一个beanhold,heanhold其实就是一个 beanname和BeanDefinition的映射
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); //创建代理对象
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); /** BeanDefinitionReaderUtils.registerBeanDefinition 内部通过
* DefaultListableBeanFactory.registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
* 按名称将bean定义信息注册到容器中,实际上DefaultListableBeanFactory内部维护一个Map<String, BeanDefinition>类型变量beanDefinitionMap,
* 用于保存注bean定义信息(beanname 和 beandefine映射)*/
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
register方法重点完成了bean配置类本身的解析和注册,处理过程可以分为以下几个步骤:
1.根据bean配置类,使用BeanDefinition解析Bean的定义信息,主要是一些注解信息
2.Bean作用域的处理,没有@Scope注解默认解析成单例
3.借助AnnotationConfigUtils工具类解析通用注解
4.将bean定义信息已beanname,beandifine键值对的形式注册到ioc容器中
然后我们继续点进去refresh()方法
refresh方法在AbstractApplicationContext容器中实现,refresh()方法的作用加载或者刷新当前的配置信息,如果已经存在spring容器,则先销毁之前的容器,重新创建spring容器,载入bean定义,完成容器初始化工作,所以可以看出AnnotationConfigApplicationContext容器是通过调用其父类AbstractApplicationContext的refresh()函数启动整个IoC容器完成对Bean定义的载入。
AbstractApplicationContext类的refresh()方法源代码如下:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//1.刷新前的预处理
prepareRefresh(); //2.获取刷新后的内部Bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //3.BeanFactory的预准备工作
prepareBeanFactory(beanFactory); try {
// BeanFactory准备工作完成后,可以做一些后置处理工作
// 4.空方法,用于在容器的子类中扩展
postProcessBeanFactory(beanFactory); // 5. 执行BeanFactoryPostProcessor的方法,BeanFactory的后置处理器,在BeanFactory标准初始化之后执行的
invokeBeanFactoryPostProcessors(beanFactory); // 6. 注册BeanPostProcessor(Bean的后置处理器),用于拦截bean创建过程,实现对bean的增强
registerBeanPostProcessors(beanFactory); // 7. 初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
initMessageSource(); // 8. 初始化事件派发器
initApplicationEventMulticaster(); // 9.空方法,可以用于子类实现在容器刷新时自定义逻辑
onRefresh(); // 10. 注册事件监听器,将所有项目里面的ApplicationListener注册到容器中来
registerListeners(); // 11. 初始化所有剩下的单实例bean,单例bean在初始化容器时创建,原型bean在获取时(getbean)时创建
finishBeanFactoryInitialization(beanFactory); // 12. 完成BeanFactory的初始化创建工作,IOC容器就创建完成;
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} //销毁已经创建的单例,以避免挂起资源。
destroyBeans(); //重置“活动”标志。
cancelRefresh(ex); //向调用者传播异常。
throw ex;
} finally {
//在Spring的core中重置常见的内省缓存,因为我们可能不再需要单例bean的元数据了...
resetCommonCaches();
}
}
}
接下来我们要分析refresh()里面的这些方法
3.1 prepareRefresh ()刷新预处理方法:
/**
*准备此上下文以进行刷新,设置其启动日期和
*活动标志以及执行属性源的任何初始化。
*/
protected void prepareRefresh() {
//设置容器启动时间
this.startupDate = System.currentTimeMillis();
//启动标识
this.closed.set(false);
this.active.set(true); if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
} //空方法,用于子容器自定义个性化的属性设置方法
initPropertySources(); //检验属性的合法等
getEnvironment().validateRequiredProperties(); //存储预刷新应用程序监听器…
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
//将本地应用程序侦听器重置为预刷新状态。
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
} //保存容器中的一些早期的事件
this.earlyApplicationEvents = new LinkedHashSet<>();
}
3.2 obtainFreshBeanFactory()方法
该方法获取刷新后的内部Bean工厂,obtainFreshBeanFactory方法为内部bean工厂重新生成id,并返回bean工厂
/**
*告诉子类刷新内部bean工厂。
* @return新鲜的BeanFactory实例
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
/**
*为beanfactory生成唯一序列化id,beanfactory已经在GenericApplicationContext构造函数中初始化了,
*refreshBeanFactory的逻辑在AbstractApplicationContext的实现类GenericApplicationContext中
*/
refreshBeanFactory();
//获取beanfactory
return getBeanFactory();
}
GenericApplicationContext类的refreshBeanFactory()方法
//---------------------------------------------------------------------
实现AbstractApplicationContext的模板方法
//---------------------------------------------------------------------
/ * *
*什么都不做:我们只有一个内部BeanFactory,并且依赖于调用者
*通过我们的公共方法(或BeanFactory的)注册bean。
* @see # registerBeanDefinition
* /
@Override
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
//生成一个序列化id
this.beanFactory.setSerializationId(getId());
}
这里使用AbstractApplicationContext.refreshBeanFactory()如果是注解的方式实现,则并没有解析项目包下的注解,而是通过在refresh()方法中执行ConfigurationClassPostProcessor后置处理器完成对bean的加载.
3.3 prepareBeanFactory(beanFactory)方法
prepareBeanFactory主要完成beanFactory的一些属性设置,BeanFactory的预准备工作
/**
*配置工厂的标准上下文特征,
*例如上下文的ClassLoader和后置处理器。
* @param beanFactory要配置的BeanFactory
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//告诉内部bean工厂使用上下文的类加载器等等。
//设置类加载器
beanFactory.setBeanClassLoader(getClassLoader());
//bean表达式解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); //使用上下文回调配置bean工厂。
//添加一个BeanPostProcessor实现ApplicationContextAwareProcessor
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //设置忽略的自动装配接口,表示这些接口的实现类不允许通过接口自动注入
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); //注册可以自动装配的组件,就是可以在任何组件中允许自动注入的组件
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this); //将早期后置处理器注册为application监听器,用于检测内部bean。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); //添加编译时的AspectJ
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
//为匹配的类型设置一个临时类加载器。
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
} // 给beanfactory容器中注册组件ConfigurableEnvironment、systemProperties、systemEnvironment
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
3.4 invokeBeanFactoryPostProcessors(beanFactory)方法
invokeBeanFactoryPostProcessors 执行bean工厂后置处理器
/**
*实例化并调用所有已注册的BeanFactoryPostProcessor beans,
*如果给定则遵守显示的顺序。
* <p>必须在单例实例化之前调用。
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
invokeBeanFactoryPostProcessors方法内部执行实现了BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor这两个接口的Processor,先获取所有BeanDefinitionRegistryPostProcessor的实现,按优先级执行(是否实现PriorityOrdered优先级接口,是否实现Ordered顺序接口);再以相同的策略执行所有BeanFactoryPostProcessor的实现。
PostProcessorRegistrationDelegate. invokeBeanFactoryPostProcessors实现:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { //如果有的话,首先调用BeanDefinitionRegistryPostProcessors。
Set<String> processedBeans = new HashSet<>(); if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>(); for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
//不要在这里初始化FactoryBeans:我们需要保留所有常规bean
//未初始化的,让bean工厂的后置处理程序负责于它们!
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); //首先,调用实现PriorityOrated接口的BeanDefinitionRegistryPostProcessors类的方法。
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear(); //接下来,调用实现Ordered接口的BeanDefinitionRegistryPostProcessors类的方法。
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear(); //最后,调用所有其他BeanDefinitionRegistryPostProcessors,直到没有其他的后置处理器出现。
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
} //现在,调用到目前为止处理完所有处理器的postProcessBeanFactory回调。
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
//调用在上下文实例中注册的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
} //不要在这里初始化FactoryBeans:我们需要保留所有常规bean
//未初始化,以让bean工厂的后值处理器负责于它们!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
//跳过-已经在上面的第一阶段处理
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
} //首先,调用实现PriorityOrated接口的BeanFactoryPostProcessors类。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); //接下来,调用实现Ordered接口的BeanFactoryPostProcessors类方法。
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); //最后,调用所有其他BeanFactoryPostProcessors,直到没有其他的后置处理器出现。
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); //清除缓存的合并bean定义,因为后置处理器可能修改了原始元数据,例如替换了值中的占位符……
beanFactory.clearMetadataCache();
}
这里面在处理BeanDefinitionRegistryPostProcessors时有一个非常重要的过程,AnnotationConfigApplicationContext构造函数在初始化reader时为内部beanFactory容器初始化了一个id为org.springframework.context.annotation.internalConfigurationAnnotationProcessor的组件,这是一个ConfigurationClassPostProcessor组件,用来处理添加@Configuration注解的类,并将Bean定义注册到BeanFactory中。
3.5 invokeBeanFactoryPostProcessors(beanFactory)方法
注册后置处理器的大致逻辑是:
1.获取所有的 BeanPostProcessor
2.根据处理器实现的接口区分出4中类型:
2.1.实现PriorityOrdered接口的处理器
2.2.实现Ordered接口的处理器,
2.3.实现MergedBeanDefinitionPostProcessor接口的处理器,
2.4.普通后置处理器
3.按这个4中类型依次注册到容器中
4.注册一个特殊的后置处理器ApplicationListenerDetector,ApplicationListenerDetector本身也实现了MergedBeanDefinitionPostProcessor接口
/ * *
*实例化并注册所有BeanPostProcessor bean,如果给定则遵循显式顺序。
* <p>必须在应用程序bean的任何实例化之前调用。
* /
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); //注册BeanPostProcessorChecker,当bean在BeanPostProcessor实例化过程中被创建时,即当一个bean没有资格被所有BeanPostProcessor处理时,它记录一条信息到日志。
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); //按优先级分类
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
} //首先,调用实现PriorityOrated接口的BeanPostProcessors类。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); //接下来,调用实现Ordered接口的BeanPostProcessors类方法。
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors); //现在,注册所有常规的BeanPostProcessors。
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); //最后,调用所有其他BeanPostProcessors,直到没有其他的后置处理器出现。
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors); //注册ApplicationListenerDetector,用于Bean创建完时检查是否是ApplicationListener
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
3.6 initMessageSource()方法
初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
/ * *
初始化MessageSource。
*如果在此上下文中没有定义,则使用父类的。
* /
protected void initMessageSource() {
//获取beanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
//让MessageSource知道父类的MessageSource。
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
//如果没有注册父类的MessageSource,则只将父类的上下文设置为父类的MessageSource。
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
//使用空的MessageSource来接受getMessage调用。
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}
3.7 initApplicationEventMulticaster()方法
初始化事件派发器
/ * *
初始化ApplicationEventMulticaster。
如果上下文中没有定义,则使用SimpleApplicationEventMulticaster。
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
* /
protected void initApplicationEventMulticaster() {
//获取BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//如果有配置beanName为applicationEventMulticaster的事件派发器,则将其赋给容器中的applicationEventMulticaster对象
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
//不存在,则创建一个SimpleApplicationEventMulticaster事件派发器,并注册到beanfactory中
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
3.8 registerListeners()方法
registerListeners方法主要实现将事件监听器添加到IOC容器中的事件派发器中,并在最后做了一个事件发布的逻辑(如果之前的步骤有产生事件,则将earlyApplicationEvents中保存的事件逐一发布)
/ * *
添加实现ApplicationListener作为侦听器的bean。
*不影响其他侦听器,可以在不添加bean的情况下添加。
* /
protected void registerListeners() {
//首先注册静态指定的监听器。
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
} //不要在这里初始化factorybean:我们需要不初始化所有常规bean,以便让后置处理器处理它们
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
} //发布早期的application事件…
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
3.9 finishBeanFactoryInitialization(beanFactory)方法
初始化所有剩下的单实例bean,单例bean在初始化容器时创建,原型bean在获取时(getbean)时创建
/ * *
*完成这个上下文的bean工厂的初始化,
初始化所有剩余的单例bean。
* /
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//初始化此上下文的转换服务。
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
} //如果之前没有注册bean后置处理器(例如PropertyPlaceholderConfigurer bean),则注册一个默认的嵌入式值解析器:此时,主要用于在注释属性值中进行解析。
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
} //提前初始化LoadTimeWeaverAware beans,以便尽早注册它们的转换器。
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
} //停止使用临时类加载器进行类型匹配。
beanFactory.setTempClassLoader(null); //允许缓存所有bean定义元数据,不需要进一步更改。
beanFactory.freezeConfiguration(); //实例化所有剩余的(非懒加载初始化)单例。
beanFactory.preInstantiateSingletons();
}
DefaultListableBeanFactory. preInstantiateSingletons()方法的实现:
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
} //容器中所有bean名称
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); for (String beanName : beanNames) {
//获取Bean的定义信息;RootBeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//非抽象,单例,非延迟加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//是否是FactoryBean
if (isFactoryBean(beanName)) {
// 通过"&beanName"获取工厂Bean实例
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
//不是FactoryBean,则利用getBean(beanName)实例化bean
getBean(beanName);
}
}
} for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
3.10 finishRefresh()方法
完成BeanFactory的初始化创建工作,代码走到这一步IOC容器就创建完成
/ * *
*调用LifecycleProcessor,完成此上下文的刷新
方法并发布
* {@link org.springframework.context.event.ContextRefreshedEvent}。
* /
protected void finishRefresh() {
//清除上下文级的资源缓存(例如来自扫描的ASM元数据)。
clearResourceCaches(); //初始化和生命周期有关的后置处理器LifecycleProcessor,默认DefaultLifecycleProcessor
initLifecycleProcessor(); // 回调生命周期处理器
getLifecycleProcessor().onRefresh(); //发布容器刷新完成事件:ContextRefreshedEvent
publishEvent(new ContextRefreshedEvent(this)); LiveBeansView.registerApplicationContext(this);
}
以上基本分析了AnnotationConfigApplicationContext容器的初始化过程, Spring容器在启动过程中,会先保存所有注册进来的Bean的定义信息;Spring容器根据条件创建Bean实例,区分单例,还是原型,后置处理器等(后置处理器会在容器创建过程中通过getBean创建,并执行相应的逻辑);Spring容器在创建bean实例后,会使用多种后置处理器来增加bean的功能,比如处理自动注入,AOP,异步,这种后置处理器机制也丰富了bean的功能。
我这边在AnnotationConfigApplicationContext启动原理分析的代码走读部分有参考博客: https://www.cnblogs.com/ashleyboy/p/9662119.html ,不过有些类的方法会有点不一样,因为我这边时基于Spring5.X的版本分析
Spring5深度源码分析(三)之AnnotationConfigApplicationContext启动原理分析的更多相关文章
- Golang源码探索(三) GC的实现原理(转)
Golang从1.5开始引入了三色GC, 经过多次改进, 当前的1.9版本的GC停顿时间已经可以做到极短.停顿时间的减少意味着"最大响应时间"的缩短, 这也让go更适合编写网络服务 ...
- Golang源码探索(三) GC的实现原理
Golang从1.5开始引入了三色GC, 经过多次改进, 当前的1.9版本的GC停顿时间已经可以做到极短. 停顿时间的减少意味着"最大响应时间"的缩短, 这也让go更适合编写网络服 ...
- twitter storm源码走读之1 -- nimbus启动场景分析
欢迎转载,转载时请注明作者徽沪一郎及出处,谢谢. 本文详细介绍了twitter storm中的nimbus节点的启动场景,分析nimbus是如何一步步实现定义于storm.thrift中的servic ...
- skywalking7 源码解析 (3) :agent启动服务分析以及性能影响
skywalking必看的文章,转载自https://blog.csdn.net/u010928589/article/details/106608864/
- Spring Boot 启动源码解析结合Spring Bean生命周期分析
转载请注明出处: 1.SpringBoot 源码执行流程图 2. 创建SpringApplication 应用,在构造函数中推断启动应用类型,并进行spring boot自动装配 public sta ...
- Spring5.x源码分析 | 从踩坑到放弃之环境搭建
Spring5.x源码分析--从踩坑到放弃之环境搭建 前言 自从Spring发行4.x后,很久没去好好看过Spring源码了,加上最近半年工作都是偏管理和参与设计为主,在技术细节上或多或少有点疏忽,最 ...
- Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Job Manager 启动
Job Manager 启动 https://t.zsxq.com/AurR3rN 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...
- Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Task Manager 启动
Task Manager 启动 https://t.zsxq.com/qjEUFau 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Ma ...
- Tomcat源码分析三:Tomcat启动加载过程(一)的源码解析
Tomcat启动加载过程(一)的源码解析 今天,我将分享用源码的方式讲解Tomcat启动的加载过程,关于Tomcat的架构请参阅<Tomcat源码分析二:先看看Tomcat的整体架构>一文 ...
随机推荐
- "Redis客户端连接数一直降不下来"的有关问题解决 good
[线上问题] "Redis客户端连接数一直降不下来"的问题解决 前段时间,上线了新的 Redis缓存(Cache)服务,准备替换掉 Memcached. 为什么要将 Memcach ...
- python3下的IE自动化模块PAMIE
PAMIE是Python下面的用于IE的自动化模块,支持python2和python3,python3的下载地址:http://sourceforge.net/projects/pamie/files ...
- c#引用相等性比较(ReferenceEquals)
Object.ReferenceEquals方法原型 public static bool ReferenceEquals( object objA, object objB) namespace T ...
- 用 cmake 构建Qt工程(对比qmake进行学习)
cmake vs qmake qmake 是为 Qt 量身打造的,使用起来非常方便 cmake 使用上不如qmake简单直接,但复杂换来的是强大的功能 内置的 out-of source 构建.(目前 ...
- 2017 JavaScript 开发者的学习图谱
码云项目推荐 前端框架类 1.项目名称: 基于 Vue.js 的 UI 组件库 iView 项目简介:iView 是一套基于 Vue.js 的 UI 组件库,主要服务于 PC 界面的中后台产品. 特性 ...
- IdentityServer流程图与相关术语
概念图 apparch 最常见的交互是:浏览器与web应用程序通信web应用程序与web APIs进行通信基于浏览器的应用程序与web APIs通信原生应用与web APIs通信基于服务的应用程序 ...
- liunx 常用操作命令
1.复制粘贴命令:在一行的任何位置按下yy,y是yanked拷贝的意思,然后去想粘贴的位置按下p即可.p是粘贴的意思. 2.如果想复制3行的话,按下3yy,就复制3行,如果想复制多行的话,直接按数字可 ...
- 程序定义了多个入口点。使用 /main (指定包含入口点的类型)进行编译
原文:请使用/main进行编译,以指定包含入口点类型 在使用VS工具初学C#的时候需要不停的写小程序,觉得每次都新建项目太过麻烦,所以试着把程序写在一个项目下面,结果编译的时候出错了,因为我每个小程序 ...
- 处理 Windows Phone 应用中的“后退”按钮 (XAML)
与电脑不同,所有 Windows Phone 设备都有“后退”按钮,它允许用户在应用的页面之间向后导航.如果用户在转到应用的第一页时再次按“后退”按钮,操作系统会挂起你的应用并将用户导航到应用启动前的 ...
- RedHat 7.3 修改ASM磁盘绑定路径
RedHat 7中,很多命令发生了改变,绑定磁盘不再是start_udev,而是udevadm,具体绑定方式,请看另一篇博文: http://www.cnblogs.com/zx3212/p/6757 ...