Spring核心之IOC--快速入门_舞鹤白沙编码日志-CSDN博客
Spring核心之IOC--相关API_舞鹤白沙编码日志-CSDN博客
Spring核心之IOC--配置文件开发_舞鹤白沙编码日志-CSDN博客
Spring核心之IOC--注解开发_舞鹤白沙编码日志-CSDN博客
(一)BeanFactory与ApplicationContext区别BeanFactory是Spring框架中IoC容器的顶层接⼝,它只是⽤来定义⼀些基础功能,定义⼀些基础规范,⽽ApplicationContext是它的⼀个⼦接⼝,所以ApplicationContext是具备BeanFactory提供的全部功能的。
通常,我们称BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的⾼级接⼝,⽐
BeanFactory要拥有更多的功能,⽐如说国际化⽀持和资源访问(xml,java配置类)等等。
(1)xml方式(两种,推荐第一种)
ClassPathXmlApplicationContext:从类的根路径下加载配置⽂件(推荐)
FileSystemXmlApplicationContext:从磁盘路径上加载配置⽂件(不推荐)
// 通过读取classpath下的xml文件来启动容器(xml模式SE应用下推荐)
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// 不推荐使用
//ApplicationContext applicationContext1 = new FileSystemXmlApplicationContext("文件系统的绝对路径");
// 第一次getBean该对象
Object accountPojo = applicationContext.getBean("accountPojo");
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
Spring之applicationContext.xml代码示例_舞鹤白沙编码日志-CSDN博客
(2)纯注解方式
AnnotationConfigApplicationContext:纯注解模式下启动Spring容器
// 通过读取classpath下的xml文件来启动容器(xml模式SE应用下推荐)
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
System.out.println(accountDao);
Spring之配置类代码示例_舞鹤白沙编码日志-CSDN博客
2. Web环境下启动IoC容器(1)从xml启动容器
Archetype Created Web Application contextConfigLocation classpath:applicationContext.xml org.springframework.web.context.ContextLoaderListener
(2)从配置类启动容器
(三)纯XML模式、半XML半注解模式及纯注解模式代码示例Archetype Created Web Application contextClass org.springframework.web.context.support.AnnotationConfigWebAppli cationContext contextConfigLocation com.lagou.edu.SpringConfig org.springframework.web.context.ContextLoaderListener
这里将用银行转账案例来演示纯XML模式、半XML半注解模式及纯注解模式
1. 纯XML模式(不常用)银行转账案例-Spring纯XML模式代码示例_舞鹤白沙编码日志-CSDN博客
2. 半XML半注解模式外部引用的包采用XML方式,自定义类采用注解方式
银行转账案例-Spring半XML半注解模式代码示例_舞鹤白沙编码日志-CSDN博客
3. 纯注解模式银行转账案例-Spring纯注解模式代码示例_舞鹤白沙编码日志-CSDN博客
二. Spring IOC高级特性 (一)lazy-Init 延迟加载Spring高级特性之lazy-Init 延迟加载_舞鹤白沙编码日志-CSDN博客
(二)FactoryBean 和 BeanFactoryFactoryBean 和 BeanFactory_舞鹤白沙编码日志-CSDN博客
(三)后置处理器Spring高级特效之后置处理器_舞鹤白沙编码日志-CSDN博客
三. Spring IOC源码深度剖析 (一)Spring IOC容器体系介绍IoC容器是Spring的核⼼模块,是抽象了对象管理、依赖关系管理的框架解决⽅案。Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器 必须遵从的⼀套原则,具体的容器实现可以增加额外的功能,⽐如我们常⽤到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容,AnnotationConfigApplicationContext 则是包含了注解解析等⼀系列的内容。Spring IoC 容器继承体系⾮常聪明,需要使⽤哪个层次⽤哪个层次即可,不必使⽤功能⼤⽽全的。
BeanFactory 顶级接⼝⽅法栈如下:
BeanFactory 容器继承体系:
通过其接⼝设计,我们可以看到我们⼀贯使⽤的 ApplicationContext 除了继承BeanFactory的⼦接⼝,还继承了ResourceLoader、MessageSource等接⼝,因此其提供的功能也就更丰富了。
下⾯我们以 ClasspathXmlApplicationContext 为例,深⼊源码分析,以探明 IoC 容器的初始化流程。
Spring之IoC 容器源码分析_舞鹤白沙编码日志-CSDN博客
(二)Spring IoC容器初始化主流程由上分析可知,Spring IoC 容器初始化的关键环节就在 AbstractApplicationContext#refresh() ⽅法中,我们查看 refresh ⽅法来俯瞰容器创建的主体流程,主体流程下的具体⼦流程我们后⾯再来讨论。
public Collection> getApplicationListeners() {
return this.applicationListeners;
}
@Override
public void refresh() throws BeansException, IllegalStateException {
// 对象锁加锁
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
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...
resetCommonCaches();
}
}
}
(三)Spring IoC容器初始化主流程中部分子流程剖析
接上部分代码中refresh()方法的执行主流程,下面就其中部分重要的子流程进行深入剖析:
1. 第二步:获取BeanFactory;默认实现是DefaultListableBeanFactory,加载BeanDefition 并注册到 BeanDefitionRegistry。
Spring IOC容器初始化之获取BeanFactory、BeanDefinition加载解析及注册子流程剖析_舞鹤白沙编码日志-CSDN博客
2. 第十一步: 初始化所有剩下的非懒加载的单例bean,初始化创建非懒加载方式的单例Bean实例(未设置属性)填充属性,初始化方法调用(比如调用afterPropertiesSet方法、init-method方法)
调用BeanPostProcessor(后置处理器)对实例bean进行后置处理
普通 Bean 的初始化是在容器启动初始化阶段执⾏的,⽽被lazy-init=true修饰的 bean 则是在从容器⾥第⼀次进⾏context.getBean() 时进⾏触发。Spring 启动的时候会把所有bean信息(包括XML和注解)解析转化成Spring能够识别的BeanDefinition并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个BeanDefinition 进⾏处理,如果是懒加载的则在容器初始化阶段不处理,其他的则在容器初始化阶段进⾏初始化并依赖注⼊。
以下是: DefaultListableBeanFactory类的preInstantiateSingletons方法
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 所有bean的名字
List beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 触发所有非延迟加载单例bean的初始化,主要步骤为getBean
for (String beanName : beanNames) {
// 合并父BeanDefinition对象
// map.get(beanName)
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// 如果是FactoryBean则加&
if (bean instanceof FactoryBean) {
final FactoryBean> factory = (FactoryBean>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction)
((SmartFactoryBean>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 实例化当前bean
getBean(beanName);
}
}
}
对于被修饰为lazy-init的bean Spring 容器初始化阶段不会进⾏ init 并且依赖注⼊,当第⼀次
进⾏getBean时候才进⾏初始化并依赖注⼊。
对于⾮懒加载的bean,getBean的时候会从缓存⾥头获取,因为容器初始化阶段 Bean 已经
初始化完成并缓存了起来。
Spring IoC循环依赖问题_舞鹤白沙编码日志-CSDN博客
四. 扩展知识点-源码的阅读 (一)源码阅读好处:提⾼培养代码架构思维、深⼊理解框架
原则:
定焦原则:抓主线
宏观原则:站在上帝视⻆,关注源码结构和业务流程(淡化具体某⾏代码的编写细节)
读源码的⽅法和技巧:
断点(观察调⽤栈)
反调(Find Usages)在idea中读到某个方法时,鼠标右键选FindUsages去找哪里调用了该方法
经验(spring框架中doXXX,做具体处理的地⽅)
spring-5.1.x_ch(含文档): 8888
2. 安装gradle 5.6.3(类似于maven) Idea 2019.1 Jdk 11.0.5Gradle 安装配置详解_舞鹤白沙编码日志-CSDN博客
3. 导⼊(耗费⼀定时间)Spring源码的导入_舞鹤白沙编码日志-CSDN博客
4. 编译⼯程顺序:core-oxm-context-beans-aspects-aop
⼯程—>tasks—>compileTestJava



