《Spring原始碼分析》IOC的實現
由一個簡單的例子引出本文
程式碼如下:
user.java
@Data
public class User {
private String username;
private int id;
}
userbean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="user" class="com.mryan.springcore.demo.User">
<property name="username" value="MRyan"></property>
<property name="id" value="666"></property>
</bean>
</beans>
啟動類,並實現了ApplicationRunner方法
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("userbean.xml");
User user = (User) context.getBean("user");
System.out.println(user.toString());
}
}
xml配置檔案向spring ioc容器中註冊一個bean,並執行程式列印bean資訊。
成功列印結果。
我們會發現貌似我們什麼都不用知道,spring框架都替我們想到了,我們幾乎不用做什麼,spring框架替我們做了,那麼問題來了,它是怎麼做到的呢?物件到底是怎麼建立的呢?
在閱讀原始碼之前我們先補一下知識
知識小課堂
-
我們可以用XML,配置類,註解等方式來定義bean資訊,容器會讀取bean資訊,那容器如何能相容讀取這些不同方式定義的bean資訊?
spring為我們定義了一個BeanDefinitionReader的統一抽象層,專門讀取bean資訊 -
獲得了bean資訊我們可以直接用反射的方式獲取物件這是我們的線性思維,顯然是不合理的。
spring中引用了工廠模式為我們建立bean的例項,工廠類名為BeanFactory -
物件的建立過程分為例項化分配記憶體,和初始化。
spring中物件的建立也不例外,除了bean的例項化還需要對屬性進行填充值,當然還需要執行自定義初始方法init-method(原始碼中見) -
在不同的階段如果要做不同的操作怎麼辦?
spring中為我們建立了觀察者模式:包括監聽器,事件釋出,當釋出不同的事件之後,監聽器接受到之後開始做相應的處理工作
原始碼分析
啟動類ApplicationContext 處打斷點一步一步除錯
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("userbean.xml");//斷點處
User user = (User) context.getBean("user");
System.out.println(user.toString());
}
}
進入ClassPathXmlApplicationContext中
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
//使用給定的父上下文建立一個新的AbstractXmlApplicationContext
super(parent);
//設定此應用程式上下文的配置位置
setConfigLocations(configLocations);
if (refresh) {
//核心
refresh();
}
}
繼續debug進入refresh方法,下面對於一些非核心的方法選擇性跳過,只分析核心程式碼,對於refresh方法也可以看之前我寫的文章《SpringBoot原始碼分析》 Context初始化流程
@Override
public void refresh() throws BeansException, IllegalStateException {
//1 加鎖,確保了同一時間startupShutdownMonitor的狀態不發生改變。
synchronized (this.startupShutdownMonitor) {
//2 為重新整理做準備 設定啟動日期和活躍狀態等
prepareRefresh();
//3 ****核心****
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//4 準備BeanFactory 各種設定 各種register這裡不做敘述
prepareBeanFactory(beanFactory);
try {
//5 ****核心****
postProcessBeanFactory(beanFactory);
//6 執行BeanFactoryPostProcessors 例項化並且執行已經註冊了的BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(beanFactory);
//7 例項化並且註冊所有BeanPostProcessor的Beans
registerBeanPostProcessors(beanFactory);
//8 國際化配置
initMessageSource();
//9 初始化應用事件廣播器。事件廣播器用來向 ApplicationListener 通知各種應用產生的事件,是一個標準的觀察者模式。
initApplicationEventMulticaster();
//10 是留給子類的擴充套件步驟,用來讓特定的 Context 子類初始化其他的 Bean。
onRefresh();
//11 把實現了 ApplicationListener 的 Bean 註冊到事件廣播器,並對廣播器中的早期未廣播事件進行通知。觀察者模式:包括監聽器,事件釋出,當釋出不同的事件之後,監聽器接受到之後開始做相應的處理工作
registerListeners();
// 12 ****核心****
finishBeanFactoryInitialization(beanFactory);
// 13 完成上下文的重新整理工作,呼叫 LifecycleProcessor 的 onFresh() 方法以及釋出 ContextRefreshedEvent 事件。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
//14
resetCommonCaches();
}
}
}
在3處
根據程式碼命名我們很容易猜到obtainFreshBeanFactory方法作用是獲取BeanFactory,並載入bean定義資訊
進入方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//判斷當前容器中是否由BeanFactory,如果由就銷燬,沒有則建立
refreshBeanFactory();
//返回BeanFactory
return getBeanFactory();
}
進入refreshBeanFactory方法
@Override
protected final void refreshBeanFactory() throws BeansException {
//判斷當前的beanFactory是否為空,不為空則證明當前容器中存在BeanFactory進行銷燬,否則建立BeanFactory
if (hasBeanFactory()) {// return (this.beanFactory != null);
destroyBeans();
closeBeanFactory();
}
try {
//建立BeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//設定序列號ID
beanFactory.setSerializationId(getId());
//自定義BeanFactory
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
可以發現此時beanDefiinitionMap中就存在了之前定義的bean資訊
在5處:
進入postProcessBeanFactory方法
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
空的方法,這其實是Spring為我們提供讓我們自行擴充套件的方法,在上面我們獲取了BeanDefinition,在放入BeanFactory之前我們可以對bean資訊進行修改等操作,我們就可以實現BeanFactoryPostProcessor並重寫postProcessBeanFactory方法在其中新增邏輯程式碼。
在第12處開始
就進入最最最核心的地方。
進入finishBeanFactoryInitialization內部
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 Bean,以便儘早註冊其轉換器。
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 停止使用臨時ClassLoader進行型別匹配。
beanFactory.setTempClassLoader(null);
// 允許快取所有bean定義後設資料,而不期望進一步的更改。
beanFactory.freezeConfiguration();
// ****核心**** 例項化所有剩餘的(非延遲初始化)單例。
beanFactory.preInstantiateSingletons();
}
我們可以看到最後一行標註核心的程式碼,我們繼續進入方法
@Override
public void preInstantiateSingletons() throws BeansException {
****省略之前
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 觸發所有非惰性單例bean的初始化...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//如果它不是抽象的並且是單例是懶載入的才進入此判斷語句
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//如果FactoryBean中存在該beanName走此判斷語句
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
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 {
getBean(beanName);
}
}
}
***省略之後
首先核心程式碼處for迴圈,從beanDefinitionNames中獲取BeanName,顯而易見本例中只有一個beanName=user
進入getBean方法
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
在進入doGetBean方法
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
***省略以上程式碼
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//斷點
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
***省略以下程式碼
如果是單例的話進入判斷,進入createBean方法 此時完成對bean的建立
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
***省略以上程式碼
try {
//doCreateBean 實際建立指定的bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
進入doCreateBean方法 此時才進行Bean的例項化
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 例項化bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//*****核心***** 使用適當的例項化策略為指定的bean建立一個新例項
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
來看看createBeanInstance做了什麼吧
使用適當的例項化策略為指定的bean建立一個新例項,
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
//預設構造的首選建構函式 案例中沒有給定構造器
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
//無需特殊處理:只需使用no-arg建構函式
return instantiateBean(beanName, mbd);
}
上述流程進入到instantiateBean方法
此時才會使用其預設建構函式例項化給定的bean
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(
//核心 在此工廠中以給定名稱返回Bean的例項
(PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, this),
getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
進入instantiate方法中
此時在此工廠中以給定名稱返回Bean的例項,並且過程中呼叫ctor.newInstance(argsWithDefaultValues); 完成了例項化
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
//此處執行ctor.newInstance(argsWithDefaultValues); 真正的完成物件的例項化
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
繼續step over結果逐層返回直到到AbstractAutowireCapableBeanFactory類的doCreateBean方法
可以看到當前bean物件已經被例項化出來了,但是還沒有設定屬性值。
下方有段核心程式碼
//填充bean 其實就是填充屬性值
populateBean(beanName, mbd, instanceWrapper);
結果逐層返回,我們發現屬性值填充成功
接著流程走到initializeBean方法
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//BeanPostProcessor(前置方法)
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//bean初始化使用者自定義初始方法init-method
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//BeanPostProcessor(後置方法)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
到此為止完成了bean物件的讀取,建立,例項化,執行使用者自定義初始方法init-method。
可能原始碼不好理解,沒關係,我畫了個圖,方便過下流程
相關文章
- Spring Ioc原始碼分析系列--@Autowired註解的實現原理Spring原始碼
- Spring原始碼分析之IoC(一)Spring原始碼
- Spring原始碼分析之IoC(二)Spring原始碼
- Spring IOC容器核心流程原始碼分析Spring原始碼
- 深入理解Spring IOC原始碼分析Spring原始碼
- spring原始碼深度解析— IOC 之 容器的基本實現Spring原始碼
- Spring原始碼教程02--Spring的IoC容器分析Spring原始碼
- Spring原始碼分析:Spring IOC容器初始化Spring原始碼
- Spring5原始碼解析_IOC之容器的基本實現Spring原始碼
- 從原始碼看Spring中IOC容器的實現(二):IOC容器的初始化原始碼Spring
- spring原始碼分析第二天------spring系統概述以及IOC實現原理Spring原始碼
- Spring原始碼分析之IOC迴圈依賴Spring原始碼
- 對Spring IoC容器實現的結構分析Spring
- 【spring原始碼學習】spring的遠端呼叫實現原始碼分析Spring原始碼
- 從原始碼看Spring中IOC容器的實現(一):介面體系原始碼Spring
- Spring IoC容器初始化 — Resource定位原始碼分析Spring原始碼
- 小白都能看懂的Spring原始碼揭祕之IOC容器原始碼分析Spring原始碼
- Spring原始碼之IOC(一)BeanDefinition原始碼解析Spring原始碼Bean
- spring-IOC容器原始碼分析(二)BeanDefinition註冊流程Spring原始碼Bean
- Spring:原始碼解讀Spring IOC原理Spring原始碼
- Spring IOC原始碼分析之-重新整理前的準備工作Spring原始碼
- 手寫Spring ioc 框架,狠狠的“Spring 原始碼Spring框架原始碼
- Spring原始碼解析02:Spring IOC容器之XmlBeanFactory啟動流程分析和原始碼解析Spring原始碼XMLBean
- Spring-IOC原始碼淺析Spring原始碼
- Spring的IOC常用註解(含原始碼)Spring原始碼
- spring-IOC容器原始碼分析(一)bean初始化流程Spring原始碼Bean
- Spring Ioc原始碼分析系列--Bean例項化過程(二)Spring原始碼Bean
- Spring Ioc原始碼分析系列--Bean例項化過程(一)Spring原始碼Bean
- Spring學習之——手寫Spring原始碼V2.0(實現IOC、DI、MVC、AOP)Spring原始碼MVC
- Spring原始碼分析(二)bean的例項化和IOC依賴注入Spring原始碼Bean依賴注入
- Spring Ioc原始碼分析系列--容器例項化Bean的四種方法Spring原始碼Bean
- Spring IOC原始碼深度剖析:Spring IoC迴圈依賴問題Spring原始碼
- 面試:spring ioc實現原理面試Spring
- 【spring 原始碼】IOC 之 ClassPathXmlApplicationContextSpring原始碼XMLAPPContext
- Spring原始碼閱讀-IoC容器解析Spring原始碼
- spring原始碼解析之IOC容器(一)Spring原始碼
- Spring原始碼分析之 lazy-init 實現原理Spring原始碼
- Spring實現IOC容器的兩種實現方式Spring