這是一篇純源碼的文章厨姚,可能有些枯燥,希望大家喜歡。不廢話
一、源碼編譯
1.下載:
git clone https://github.com/spring-projects/spring-framework.git 1
cd spring-framework/
2.編譯:
先配置gradle編譯環(huán)境
gradle -v
idea中配置gradle
3.直接導(dǎo)入idea钻弄,在Terminal中執(zhí)行如下命令,編譯Spring源碼
gradlew spring-oxm:compileTestJava
4.正常情況是不會(huì)確實(shí)cglib包的卖局,如果確實(shí),在Terminal中執(zhí)行
gradle objenesisRepackJar gradle cglibRepackJar
會(huì)在Spring-framework\spring-core\build\libs生成缺失的jar
二双霍、IoC容器設(shè)計(jì)理念
IoC也稱為依賴注入dependency injection, DI)砚偶。它是一個(gè)對(duì)象定義依賴關(guān)系的過程,也就是 說洒闸,對(duì)象只通過構(gòu)造函數(shù)參數(shù)染坯、工廠方法的參數(shù)或?qū)ο髮?shí)例構(gòu)造或從工廠方法返回后在對(duì)象實(shí) 例上設(shè)置的屬性來定義它們所使用的其他對(duì)象。然后容器在創(chuàng)建bean時(shí)注入這些依賴項(xiàng)丘逸。這 個(gè)過程基本上是bean的逆過程单鹿,因此稱為控制反轉(zhuǎn)(IoC)
在Spring中,構(gòu)成應(yīng)用程序主干并由Spring IoC容器管理的對(duì)象稱為bean深纲。bean是由Spring IoC容器實(shí)例化仲锄、組裝和管理的對(duì)象。
IoC容器設(shè)計(jì)理念:通過容器統(tǒng)一對(duì)象的構(gòu)建方式湃鹊,并且自動(dòng)維護(hù)對(duì)象的依賴關(guān)系儒喊。
三、Spring IoC的使用及其原理分析
1.bean的裝配方式 xml
ApplicationContext context = new
ClassPathXmlApplicationContext("spring.xml");
實(shí)現(xiàn)FactoryBean
public class MyFactroyBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new ReentrantLock();
}
@Override
public Class getObjectType() {
return ReentrantLock.class;
}
}
思考:FactoryBean和BeanFactory的區(qū)別币呵?
AbstractBeanFactory#getObjectForBeanInstance
!(beanInstance instanceof FactoryBean) ||
BeanFactoryUtils.isFactoryDereference(name)
ObjectFactory 和FactoryBean的區(qū)別怀愧?
@Component +@ComponentScan @Component , @Repository,@Service , @Controller @Component 是通用注解余赢,其他三個(gè)注解是這個(gè)注解的拓展芯义,并且具有了特定的功能 @Repository 注解在持久層中,具有將數(shù)據(jù)庫操作拋出的原生異常翻譯轉(zhuǎn)化為spring的持 久層異常的功能妻柒。 @Service 層是業(yè)務(wù)邏輯層注解扛拨,這個(gè)注解只是標(biāo)注該類處于業(yè)務(wù)邏輯層。 @Controller 層是spring-mvc的注解举塔,具有將請求進(jìn)行轉(zhuǎn)發(fā)鬼癣,重定向的功能陶贼。
@ComponentScan("bat.ke.qq.com")
@Configuration
public class AppConfig {
}
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(AppConfig.class)
思考: @Configuration和@Component區(qū)別?
@Configuration 實(shí)現(xiàn)了@Component待秃,還有其他作用
@Bean+ @Configuration
@Configuration
public class AppConfig {
@Bean
public User user(){
return new User();
}
}
思考:配置 @Configuration和不配置的區(qū)別拜秧? 不配置@Configuration: 當(dāng)內(nèi)部method bean發(fā)生彼此依賴的時(shí)候會(huì)導(dǎo)致多例 @Configuration: 1.將@Configuration配置的Appconfig由普通類型轉(zhuǎn)變?yōu)閏glib代理類型 2.將AppConfig的beanDefinitioin屬性賦值為full類型的(不配置的是lite) @Configuration源碼分析: ConfigurationClassPostProcessor#postProcessBeanFactory
AbstractApplicationContext#invokeBeanFactoryPostProcessors
>PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(Configu
rableListableBeanFactory, BeanFactoryPostProcessor>)
>ConfigurationClassPostProcessor#postProcessBeanFactory
>> enhanceConfigurationClasses(beanFactory); //增強(qiáng)配置類 cglib
// 轉(zhuǎn)換為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()};// 只能根據(jù)byType
}
}
ImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements
ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata
importingClassMetadata,BeanDefinitionRegistry registry) {
//創(chuàng)建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的屬性是什么對(duì)象承載的? bean是如何注冊到容器中的章郁?
BeanDefinition (Bean定義) 承載bean的屬性信息
BeanDefinitionRegistry(Bean注冊器) bean的id作為key注冊 beanName
AliasRegistry (別名注冊器) bean的name作為key注冊
BeanDefinitionHolder 包裝 BeanDefinition id name(多個(gè))
BeanDefinitionReader(Bean定義讀韧鞯) 讀取spring配置文件
BeanDefinitionParser bean定義解析器 parser解析 schema
ConfigurationClassParser 配置類解析器
BeanMethod @bean修飾的方法bean
ConfigurationClass 配置類 緩存BeanMethod到 beanMethods
Beanfactory (bean工廠) 生產(chǎn)bean
xml配置
//創(chuàng)建一個(gè)簡單注冊器
//BeanDefinitionRegistry register = new SimpleBeanDefinitionRegistry();
//創(chuàng)建一個(gè)實(shí)現(xiàn)了注冊器的工廠
BeanDefinitionRegistry registry = new DefaultListableBeanFactory();
//創(chuàng)建bean定義讀取器
BeanDefinitionReader reader = new XmlBeanDefinitionReader(register);
// 創(chuàng)建資源讀取器
//DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
// 獲取資源
//Resource xmlResource = resourceLoader.getResource("spring.xml");
reader.loadBeanDefinitions("spring.xml");
// 裝載Bean的定義
reader.loadBeanDefinitions(xmlResource);
// 打印構(gòu)建的Bean 名稱
System.out.println(Arrays.toString(register.getBeanDefinitionNames());
// 工廠調(diào)用getBean方法
System.out.println(regis解析xml并注冊beanter.getBean("user"));
源碼分析
AbstractApplicationContext#refresh
>>obtainFreshBeanFactory();
>>refreshBeanFactory();
>>loadBeanDefinitions(beanFactory);
>>loadBeanDefinitions(beanDefinitionReader);
>XmlBeanDefinitionReader#doLoadBeanDefinitions
>DefaultBeanDefinitionDocumentReaderarseBeanDefinitions
// 解析xml bean標(biāo)簽
>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
// 容器啟動(dòng)
tBean("fox"));
源碼分析
AbstractApplicationContext#refresh
>>invokeBeanFactoryPostProcessors(beanFactory);
>PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcess
ors
>ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
>ConfigurationClassPostProcessor#processConfigBeanDefinitions
>>ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,
this.metadataReaderFactory) // 設(shè)置配置類屬性是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 并不會(huì)將bean注冊到容器plements ImportSelector
>>> selector.selectImports(currentSourceClass.getMetadata());
// 處理@Bean ConfigurationClass 緩存beanMethods
>>>ConfigurationClass#addBeanMethod
// 回到processConfigBeanDefinitions
>ConfigurationClassPostProcessor#processConfigBeanDefinitions
// 注冊bean到容器
>>> this.reader.loadBeanDefinitions(configClasses);
>>ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurati
onClass
// 注冊 實(shí)現(xiàn)了ImportSelector的bean
>>> registerBeanDefinitionForImportedConfigurationClass(configClass);
// 方法bean 注冊到容器
>>> loadBeanDefinitionsForBeanMethod(beanMethod);
// @ImportResource("spring.xml") 配置的bean注冊到容器
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources(
));
// 實(shí)現(xiàn) ImportBeanDefinitionRegistrar的 bean 注冊到容器
>>> loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionR
egistrars());
3.bean的依賴注入原理
查找方式:
byType
byName
注入方式: field
反射的方式暖庄,field.set(obj,value)
constructor
不配置 @Autowired情況下
多構(gòu)造器時(shí)聊替,有無參構(gòu)造器,則調(diào)用無參構(gòu)造器培廓,若沒有無參構(gòu)造器惹悄,當(dāng)剩余構(gòu)造器大于 1個(gè)時(shí),拋異常肩钠,當(dāng)只有一個(gè)時(shí)泣港,會(huì)執(zhí)行此構(gòu)造器
當(dāng)只有一個(gè)有參構(gòu)造器時(shí),會(huì)執(zhí)行此構(gòu)造器
當(dāng)該bean的beanDefinition設(shè)置了AutowireMode為3后价匠,則會(huì)選擇構(gòu)造器貪婪模式当纱,執(zhí)行參數(shù)最多的構(gòu)造器(前提:構(gòu)造參數(shù)類型都是bean類型)
@Component
public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory
beanFactory) throws BeansException {
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition)
beanFactory.getBeanDefinition("userServiceImpl");
beanDefinition.setAutowireMode(3);//構(gòu)造器貪婪模式
}
}
setter方法
不配置 @Autowired情況下 通過設(shè)置AutowireMode為1或者2,會(huì)調(diào)用setter方法踩窖,通過setter方法注入bean
AutowireCapableBeanFactory類
//沒有外部定義的自動(dòng)裝配
int AUTOWIRE_NO = 0;
//基于規(guī)范的setter方法名調(diào)用坡氯,比如setUserDao(UserDao userDao)
//---setUserDao---bat.ke.qq.com.dao.UserDao@64cd705f
int AUTOWIRE_BY_NAME = 1;
/**
*基于setter方法的參數(shù)類型調(diào)用,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;
//自動(dòng)裝配最貪婪的構(gòu)造函數(shù)
int AUTOWIRE_CONSTRUCTOR = 3;
今天就寫到這里了洋腮,太累了箫柳。頭發(fā)又少了幾根,啃了一陣子spring源碼啥供,今天才敢寫一點(diǎn)東西滞时,希望對(duì)大家有幫助,最少也能理清一下滤灯。
創(chuàng)作不易坪稽,各位的支持和認(rèn)可,就是我創(chuàng)作的最大動(dòng)力鳞骤,我們下篇文章見窒百!
下篇文章我準(zhǔn)備整理一篇《Bean的生命周期》不知道大家是否感興趣,也可以評(píng)論告訴我豫尽。
如果本篇有任何錯(cuò)誤篙梢,請批評(píng)指教,不勝感激 美旧!
聯(lián)系我/公眾號(hào)(java耕耘者)一個(gè)每天吃飯睡覺打豆豆寫代碼的人渤滞。