Spring IoC源码分析

这是一篇纯源码的文章,可能有些枯燥,希望大家喜欢。不废话


一、源码编译

1.下载:

git clone https://github.com/spring-projects/spring-framework.git 1

cd spring-framework/

2.编译:

先配置gradle编译环境

gradle -v

idea中配置gradle

3.直接导入idea,在Terminal中执行如下命令,编译Spring源码

gradlew spring-oxm:compileTestJava

4.正常情况是不会确实cglib包的,如果确实,在Terminal中执行

gradle objenesisRepackJar gradle cglibRepackJar

会在Spring-framework\spring-core\build\libs生成缺失的jar

二、IoC容器设计理念

IoC也称为依赖注入dependency injection, DI)。它是一个对象定义依赖关系的过程,也就是 说,对象只通过构造函数参数、工厂方法的参数或对象实例构造或从工厂方法返回后在对象实 例上设置的属性来定义它们所使用的其他对象。然后容器在创建bean时注入这些依赖项。这 个过程基本上是bean的逆过程,因此称为控制反转(IoC)

在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是由Spring IoC容器实例化、组装和管理的对象。

IoC容器设计理念:通过容器统一对象的构建方式,并且自动维护对象的依赖关系。

三、Spring IoC的使用及其原理分析

1.bean的装配方式 xml

ApplicationContext context = new

ClassPathXmlApplicationContext("spring.xml");

实现FactoryBean

public class MyFactroyBean implements FactoryBean {

@Override

public Object getObject() throws Exception {

return new ReentrantLock();

}

@Override

public Class getObjectType() {

return ReentrantLock.class;

}

}

思考:FactoryBean和BeanFactory的区别?

AbstractBeanFactory#getObjectForBeanInstance

!(beanInstance instanceof FactoryBean) ||

BeanFactoryUtils.isFactoryDereference(name)

ObjectFactory 和FactoryBean的区别?

@Component +@ComponentScan @Component , @Repository,@Service , @Controller @Component 是通用注解,其他三个注解是这个注解的拓展,并且具有了特定的功能 @Repository 注解在持久层中,具有将数据库操作抛出的原生异常翻译转化为spring的持 久层异常的功能。 @Service 层是业务逻辑层注解,这个注解只是标注该类处于业务逻辑层。 @Controller 层是spring-mvc的注解,具有将请求进行转发,重定向的功能。

@ComponentScan("bat.ke.qq.com")

@Configuration

public class AppConfig {

}

AnnotationConfigApplicationContext context = new

AnnotationConfigApplicationContext(AppConfig.class)

思考: @Configuration和@Component区别?

@Configuration 实现了@Component,还有其他作用

@Bean+ @Configuration

@Configuration

public class AppConfig {

@Bean

public User user(){

return new User();

}

}

思考:配置 @Configuration和不配置的区别? 不配置@Configuration: 当内部method bean发生彼此依赖的时候会导致多例 @Configuration: 1.将@Configuration配置的Appconfig由普通类型转变为cglib代理类型 2.将AppConfig的beanDefinitioin属性赋值为full类型的(不配置的是lite) @Configuration源码分析: ConfigurationClassPostProcessor#postProcessBeanFactory

AbstractApplicationContext#invokeBeanFactoryPostProcessors

>PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(Configu

rableListableBeanFactory, BeanFactoryPostProcessor>)

>ConfigurationClassPostProcessor#postProcessBeanFactory

>> enhanceConfigurationClasses(beanFactory); //增强配置类 cglib

// 转换为cglib类型

>>Class enhancedClass = enhancer.enhance(configClass,

this.beanClassLoader);

@Import

@ComponentScan("bat.ke.qq.com")

@Configuration

@Import(value = MyImportBeanDefinitionRegistrar.class)

public class AppConfig {

@Bean

public User user(){

return new User();

}

}

@Import(AppConfig2.class)

ImportSelector

public class MyImportSelector implements ImportSelector {

@Override

public String[] selectImports(AnnotationMetadata

importingClassMetadata)

return new String[]{Fox.class.getName()};// 只能根据byType

}

}

ImportBeanDefinitionRegistrar

public class MyImportBeanDefinitionRegistrar implements

ImportBeanDefinitionRegistrar {

@Override

public void registerBeanDefinitions(AnnotationMetadata

importingClassMetadata,BeanDefinitionRegistry registry) {

//创建BeanDefinition

RootBeanDefinition rootBeanDefinition = new

RootBeanDefinition(Fox.class);

// 注册到容器

registry.registerBeanDefinition("fox",rootBeanDefinition);

}

}

@ImportResource("spring.xml")

@Conditional

@ComponentScan("bat.ke.qq.com")

@Configuration

public class AppConfig {

@Bean

public Cat cat(){

return new Cat();

}

@Bean

@Conditional(value = MyConditional.class)

public Fox fox(){

return new Fox()

}

}

public class MyConditional implements Condition {

@Override

public boolean matches(ConditionContext context, AnnotatedTypeMetadata

metadata) {

if(context.getBeanFactory().containsBean("cat"))

return true;

return false;

}

}

2.bean的注册原理

思考:bean的属性是什么对象承载的? bean是如何注册到容器中的?

BeanDefinition (Bean定义) 承载bean的属性信息

BeanDefinitionRegistry(Bean注册器) bean的id作为key注册 beanName

AliasRegistry (别名注册器) bean的name作为key注册

BeanDefinitionHolder 包装 BeanDefinition id name(多个)

BeanDefinitionReader(Bean定义读取) 读取spring配置文件

BeanDefinitionParser bean定义解析器 parser解析 schema

ConfigurationClassParser 配置类解析器

BeanMethod @bean修饰的方法bean

ConfigurationClass 配置类 缓存BeanMethod到 beanMethods

Beanfactory (bean工厂) 生产bean

xml配置

//创建一个简单注册器

//BeanDefinitionRegistry register = new SimpleBeanDefinitionRegistry();

//创建一个实现了注册器的工厂

BeanDefinitionRegistry registry = new DefaultListableBeanFactory();

//创建bean定义读取器

BeanDefinitionReader reader = new XmlBeanDefinitionReader(register);

// 创建资源读取器

//DefaultResourceLoader resourceLoader = new DefaultResourceLoader();

// 获取资源

//Resource xmlResource = resourceLoader.getResource("spring.xml");

reader.loadBeanDefinitions("spring.xml");

// 装载Bean的定义

reader.loadBeanDefinitions(xmlResource);

// 打印构建的Bean 名称

System.out.println(Arrays.toString(register.getBeanDefinitionNames());

// 工厂调用getBean方法

System.out.println(regis解析xml并注册beanter.getBean("user"));

源码分析

AbstractApplicationContext#refresh

>>obtainFreshBeanFactory();

>>refreshBeanFactory();

>>loadBeanDefinitions(beanFactory);

>>loadBeanDefinitions(beanDefinitionReader);

>XmlBeanDefinitionReader#doLoadBeanDefinitions

>DefaultBeanDefinitionDocumentReaderarseBeanDefinitions

// 解析xml bean标签

>BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element)

// 生成beanName(id 和name) 和beanDefinition

>BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element,

BeanDefinition)

>DefaultBeanDefinitionDocumentReader#processBeanDefinition

>>BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,

getReaderContext().getRegistry());

>BeanDefinitionReaderUtils#registerBeanDefinition

>> registry.registerBeanDefinition(beanName,

definitionHolder.getBeanDefinition());

// 注册beanDefiniton

>DefaultListableBeanFactory#registerBeanDefinition

>>this.beanDefinitionMap.put(beanName, beanDefinition);

>>this.beanDefinitionNames.add(beanName);

>>this.manualSingletonNames.remove(beanName);

java Configuration

AnnotationConfigApplicationContext context =

new AnnotationConfigApplicationContext(AppConfig.class);

// 通过容器获取到beanFactory 即是工厂,又是注册器

DefaultListableBeanFactory factory =

context.getDefaultListableBeanFactory();

RootBeanDefinition beanDefinition = new RootBeanDefinition(Fox.class);

factory.registerBeanDefinition("fox",beanDefinition);

//beanDefinition.setAutowireMode(2);

//spring 填充属性

beanDefinition.getPropertyValues().add("name","foxxx");

ConfigurationClassPostProcessor#processConfigBeanDefinitions ConfigurationClassParser#processConfigurationClass ConfigurationClassParser#doProcessConfigurationClass

gApplicationContext context = new

AnnotationConfigApplicationContext(AppConfig.class);

eregister(annotatedClasses);

>AnnotatedBeanDefinitionReader#registerBean(Class)

// 注册appConfig 到容器

>AnnotatedBeanDefinitionReader#doRegisterBean

// 容器启动

tBean("fox"));

源码分析

AbstractApplicationContext#refresh

>>invokeBeanFactoryPostProcessors(beanFactory);

>PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcess

ors

>ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

>ConfigurationClassPostProcessor#processConfigBeanDefinitions

>>ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,

this.metadataReaderFactory) // 设置配置类属性是full还是lite

>> parser.parse(candidates); // 解析配置类

>ConfigurationClassParser#parse(Set)

>ConfigurationClassParser#parse(AnnotationMetadata, String)

>> doProcessConfigurationClass(confi// 配置类解析器

gClass, sourceClass);

>ConfigurationClassParser#doProcessConfigurationCla 将@Component修饰的bean

注册到容器ss

// 解析@ComponentScan

>> this.componentScanParser.parse(componentScan,

sourceClass.getMetadata().getClassName());

>>>ComponentScanAnnotationParser#parse

// basePackages属性修饰的

>>> ClassPathBeanDefinitionScanner#doScan

// 找到被@Component修饰的类

>>>> findCandidateCoponents(base Package);

>>>> registerBeanDefinition(definitionHolder, this.registry);

// 处理@Import

>> ConfigurationClassParser#processImports

// im 并不会将bean注册到容器plements ImportSelector

>>> selector.selectImports(currentSourceClass.getMetadata());

// 处理@Bean ConfigurationClass 缓存beanMethods

>>>ConfigurationClass#addBeanMethod

// 回到processConfigBeanDefinitions

>ConfigurationClassPostProcessor#processConfigBeanDefinitions

// 注册bean到容器

>>> this.reader.loadBeanDefinitions(configClasses);

>>ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurati

onClass

// 注册 实现了ImportSelector的bean

>>> registerBeanDefinitionForImportedConfigurationClass(configClass);

// 方法bean 注册到容器

>>> loadBeanDefinitionsForBeanMethod(beanMethod);

// @ImportResource("spring.xml") 配置的bean注册到容器

loadBeanDefinitionsFromImportedResources(configClass.getImportedResources(

));

// 实现 ImportBeanDefinitionRegistrar的 bean 注册到容器

>>> loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionR

egistrars());

3.bean的依赖注入原理

查找方式:

byType

byName

注入方式: field

反射的方式,field.set(obj,value)

constructor

不配置 @Autowired情况下

多构造器时,有无参构造器,则调用无参构造器,若没有无参构造器,当剩余构造器大于 1个时,抛异常,当只有一个时,会执行此构造器

当只有一个有参构造器时,会执行此构造器

当该bean的beanDefinition设置了AutowireMode为3后,则会选择构造器贪婪模式,执行参数最多的构造器(前提:构造参数类型都是bean类型)

@Component

public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {

@Override

public void postProcessBeanFactory(ConfigurableListableBeanFactory

beanFactory) throws BeansException {

AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition)

beanFactory.getBeanDefinition("userServiceImpl");

beanDefinition.setAutowireMode(3);//构造器贪婪模式

}

}

setter方法

不配置 @Autowired情况下 通过设置AutowireMode为1或者2,会调用setter方法,通过setter方法注入bean

AutowireCapableBeanFactory类

//没有外部定义的自动装配

int AUTOWIRE_NO = 0;

//基于规范的setter方法名调用,比如setUserDao(UserDao userDao)

//---setUserDao---bat.ke.qq.com.dao.UserDao@64cd705f

int AUTOWIRE_BY_NAME = 1;

/**

*基于setter方法的参数类型调用,set开头即可,比如

* ---setUserDao---bat.ke.qq.com.dao.UserDao@63355449

* ---setUserDaoxxxx---bat.ke.qq.com.dao.UserDao@63355449

* ---setxxxxxxUserDao---bat.ke.qq.com.dao.UserDao@63355449

**/

int AUTOWIRE_BY_TYPE = 2;

//自动装配最贪婪的构造函数

int AUTOWIRE_CONSTRUCTOR = 3;

今天就写到这里了,太累了。头发又少了几根,啃了一阵子spring源码,今天才敢写一点东西,希望对大家有帮助,最少也能理清一下。

创作不易,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

下篇文章我准备整理一篇《Bean的生命周期》不知道大家是否感兴趣,也可以评论告诉我。

如果本篇有任何错误,请批评指教,不胜感激 !

联系我/公众号(java耕耘者)一个每天吃饭睡觉打豆豆写代码的人。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容