源碼入口
上篇博文中我們看到了將Spring環境中的 BeanPostProcessor找出來,添加到BeanFactory中的beanPostProcessors中,統一維護,本片博文繼續往下拓展,看下Spring如何實例化bean,以及如何實現在bean的實例化通過各種各樣的后置處理器完成bean的增強
所以本次的程序入口是AbstractApplicationContext
中的finishBeanFactoryInitialization(beanFactory);
,源碼如下,主要做了如下幾件事
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
// 為上下文初始化類型轉換器
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));
}
// 檢查上下文中是否存在類型轉換器
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 盡早初始化LoadTimeWeaverAware bean,以便盡早注冊它們的轉換器。
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
// 禁止使用臨時類加載器進行類型匹配
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes
// 允許緩存所有的bean的定義數據
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
// 准備實例化bean
beanFactory.preInstantiateSingletons();
}
我們着重看他是如何創建實例化bean的,跟進beanFactory.preInstantiateSingletons();
,調用beanFactory的方法准備實例化bean, 這個beanFactory就是Spring默認是bean工廠, DefaultListableBeanFactory
, 源碼如下:方法不算很長,邏輯也很清楚, 一開始Spring取出當前上下文中所有的BeanName列表,因為在執行到這里之前,已經完成包掃描了所以說這個盛放beanName的list里面存放的就是所有的需要實例化的對象的全集,包含Spring自己的,和程序員自己添加的還包含Aspectj的
所以說,當前方法的目標很明了,就是遍歷這個list中的每一個beanName,然后實例化當前beanName相應的bean
當然,如果想實例化,前提是不能是抽象類,不能是接口,非懶加載, 而且針對FactoryBean
還有不同的處理模式
public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Pre-instantiating singletons in " + this);
}
//所有bean的名字
// 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.
//todo 遍歷一個副本以允許init方法,而init方法反過來注冊新的bean定義。
// todo 盛放所有的beanName,所有的需要實例化的beanName都在這里,包括Spring斷斷續續添加的, Aspectj的, 程序員通過注解標識的
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// todo 觸發所有非延遲加載單例beans的初始化,主要步驟為調用getBean
for (String beanName : beanNames) {
// todo 合並父類BeanDefinition,可以進入查看
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//todo 三個條件,抽象,單例,非懶加載
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// todo 如果是FactoryBean則加上&
// todo 檢驗是否是 FactoryBean 類型的對象
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 {
// todo 因為我們沒有添加FactoryBean類型的對象, 一般都會進入這個getBean
getBean(beanName);
}
}
}
下面接着跟進getBean(beanName);
方法,顧名思義獲取Bean,再往下跟下去,就算是本文的正文開始部分了,但是我想在這里提醒自己,一個比較有分量的劇透吧,當前的getBean(beanName)
它是有返回值的,一會當我們往下跟進的是時候會發現會存在遞歸的現象,這一點巧妙的實現了@Autowired
處理setter方式實現循環引用
ok,現在繼續看代碼,經過了幾個空方法的傳遞,我們來到下面的代碼中,它主要做了如下幾件事
首先將傳遞進來的name轉換成了beanName
原因1: FactoryBean的實現類的存儲方式和其他的類完全相同,添加上&是獲取不到的, 因此我們將&去掉 原因2: 解決別名的問題
為什么在創建bean之前先調用getSingleton()
?
回想一下,現在是Spring啟動的過程中,是在准備實例化bean,為什么一開始就來getSingleton()
,跟進源碼查看這個方法,它最終實現中有一行代碼是這樣的Object singletonObject = this.singletonObjects.get(beanName);
而這個singletonObjects
就是微觀層面的IOC容器,循環創建剛開始時,IOC確實是空的,但是我前面存在劇透,一開始的getBean()
方法是存在遞歸調用現象的,直接舉2個例子: 第一:假如現在在實例化A,結果有發現需要給A注入B, 那Spring是不是得獲得B,怎么獲得呢? 遞歸使用getBean(BName)
完成, 第二個例子: A被添加上了@Lazy注解,是懶加載的,但是終究有一個會通過getBean(AName)
獲取A,這是發現A是實例化需要B,B肯定已經實例化完事了,同樣是通過遞歸getBean(BName)
實現注入, 在這兩個過程中就是getSingleton()
保證不會重復創建已經存在的實例
我們關注的重點其實是第二個getSingleton(beanName()->{xxx})
在第二個getSingleton()
方法中才是真正的去實例化bean的方法
最后,在當前的方法最后將bean返回了
前面我就是說過了,getBean(beanName)
存在遞歸調用的情況,為什么我會一直說這個事呢,因為如果不知道這個事的話,這些代碼看起來是沒有頭緒的,但是明白這個事,看代碼就變得很有邏輯,我在簡單總結一下怎個玩這個遞歸呢? 假設現在通過getBean(AName)
來注入A對象,但是呢發現了A依賴B對象,於是在getBean(AName)
里面調用getBean(BName)
,通過這個方法返回出B對象完成A的注入
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 將傳遞進來的name
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 及早的檢查一下有沒有已經注冊了的單例對象
Object sharedInstance = getSingleton(beanName);// todo ::: name=myService時,這次來調用的就是 DefaultSingletonBeanRegistry中的 getSingleton() , 不同之處是多傳遞了一個true
if (sharedInstance != null && args == null) {
// 如果存在的話,將其取出賦值給bean,后續直接返回這個bean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 來到這里就說明要獲取的bean還沒有實例化過
// 於是檢驗一下,如果是原形,直接拋異常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
// 檢查是否存在默認的父工廠
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
// 將當前的beanName存放到AlreadeyCreated這個set集中,標識這個bean被創建了
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 確保當前bean所依賴的bean都已經初始化好了
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
// 實例化bean
sharedInstance = getSingleton(beanName, () -> {
// 真正的完成bean的創建
return createBean(beanName, mbd, args);
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 下面是進行其他的檢查工作,這里不再深究了
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
經過了上面一頓扯,然后我們繼續往下跟,看看createBean(beanName, mbd, args)
方法中是如何實例化我們的Bean的, 上面的方法是在AbstractBeanFactory
中,createBean(beanName, mbd, args)
是它的抽象方法, 那實現類是哪個呢?
AbstractAutowireCapableBeanFactory
,隆重的誇一下這個類,Spring都稱贊這個類是有有才華的
todo 總結這個類
在這個方法中,主要做了兩件事:兩件大事!!!
第一件大事:
在實例化Bean前,第一次調用后置處理器, 這件大事絕對是有歷史意義的!!!為啥呢?大家想想,bean還沒有創建呢!就已經可以插手bean的創建過程了,不是很刺激嗎?接着看回調了什么后置處理器呢? Spring會循環所有的處理器檢查當前被遍歷的處理器是否是InstantiationAwareBeanPostProcessor
類型的,如果是的話呢,就執行這個后置處理器的postProcessBeforeInstantiation(beanClass, beanName);
方法
這個postProcessBeforeInstantiation()
是允許有返回值的,大家可以想想,這一點是不是有點可怕? 事實也是這樣,后置處理器的目的是為了增強對象,而我們卻可以在這里返回一個任何東西,狸貓換台子替換掉原始的,還沒有被創建的對象,還有一點,就是一旦我們在這里真的是沒有返回null,那后續Spring就沒有義務在去為我們創建本來應該創建的對象了,代碼通過if-else的選擇分支會使得當前的對象不再經歷其他后置處理器的增強,最終執行它父類的postProcessorAfterInitialization()
補充一點,我們通過@EnableAspectjAutoProxy添加到Spring上下文中的AnnotationAwareAspectjAutoProxyCreator
對象其實就是這個類型InstantiationAwareBeanPostProcessor
,也就是說在這里這個接口的相關方法會被回調,下面看看他的實現類AbstractAutoProxyCreator
對這個before()
方法的重寫實現,源碼如下:
主要邏輯就是找出需要產生代理增強的bean(切面類),和普通的bean, 需要增強的bean放在advisedBeans
里面,因為需要增強的bean是需要動態植入其他邏輯的,所以不放在一起
判斷當前bean是否是基礎類型的,比如: Advice PointCut Advisor AopInfrastructureBean 或者是 切面Aspectj 都算是基礎類型,標注這些信息的類,是不會被增強的,標記false
主意啊,上面說的都是作用都是進行了一下標記
//todo 跟進來
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// todo 亮點就是在這里, 如果是我們切面類來到這里,條件是滿足的
// todo advicedBeans 見名知意: 通知beans
// todo Spring用它標識, 被放在這個方法中的類,全部都不會被增強
// todo 滿足什么條件時,通過檢查呢? 就是檢查是否標記有 @Aspectj @Before ... 等注解
// todo 說的再直接一點, 就是返回了null, 表示當前的切面仍然需要按照正常的流程創建出來,但是這里進行標記了
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource. todo 如果我們有一個自定義的TargetSource,在這里創建代理
// Suppresses unnecessary default instantiation of the target bean: // todo 抑制不必要的目標bean的默認實例化:
// The TargetSource will handle target instances in a custom fashion. todo TargetSource將以自定義方式處理目標實例。
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
經過上面的標記,在哪里產生的代理對象呢?其實是在AbstractAutowireCapeableBeanFactory
中的initializeBean()
方法中實現的postProcessAfterInitialization()
實現的,在本文的末尾展開討論
第二件大事: 實例化對象, 繼續跟進
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class which cannot be stored in the shared merged bean definition.
// todo 做各種各樣的屬性值的賦值, 比如這種 通過Spring的Bean傳遞給Spring框架的值 ==> bd.setPropertyValue("aaa")
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
// todo 處理 lookup-method 和 replace-method 配置,Spring 將這兩個配置統稱為 override method
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// todo 在實例化之前完成一次解析操作,這也是
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
//todo 調用 doCreateBean 創建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
}
我們繼續跟進doCreateBean(beanName, mbdToUse, args);
方法, 同樣是本類AbstarctAutowireCapableBeanFactory
的方法,源碼如下: 這個方法也是無與倫比的重要,那這個方法中做了什么事情呢?如下
- 創建一個 BeanWrapper,用來存放bean+其他屬性
- 創建bean的實例,封裝進上面的BeanWrapper中
- 分兩次調用處理處理器
- 設置屬性,填充屬性
- 經過AOP處理,將原生對象轉換成Proxy
- 返回BeanWrapper
因為這個方法簡直太重要了,上面列舉的每一點都值得我們仔細分析,我們每一條的分析都寫在下面代碼的下面
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
// todo BeanWrapper 用來包裝bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// todo 一開始 factoryBeanInstanceCache 這個map中是沒有值的, 所以進入下面的if
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// todo !!!!!!!!這里獲取出來的對象是原生對象!!!!!!!!!!!!
final 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.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean; // todo 到目前為止還是原生對象
//todo 用來填充屬性
//設置屬性,非常重要
populateBean(beanName, mbd, instanceWrapper);
// todo 經過AOP處理,原生對象轉換成了代理對象,跟進去
//執行后置處理器,aop就是在這里完成的處理
exposedObject = initializeBean(beanName, exposedObject, mbd);
return exposedObject;
}
實例化對象
我把源碼貼在了下面,下面方法的目的就是選出一個策略來實例化一個對象, 那有什么策略呢? 這就看程序員是怎么配置的了, 程序員可以配置工廠方法,指定構造方法,或者是程序員沒有做出任何干涉,讓Spring按自己的方式去實例化
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);
/**
* todo 檢測一個類的訪問權限, Spring默認是 允許訪問非public類型的方法
*/
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());
}
/**
* 創建一個bean的快捷方式
*/
boolean resolved = false;
boolean autowireNecessary = false; // todo 是否是必須自動裝配
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// todo
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
//如果已經解析了構造方法的參數,則必須要通過一個帶參構造方法來實例
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {// todo 如果是需要自動注入的,就使用構造方法自動注入
// 通過構造方法自動裝配的方式構造 bean 對象
return autowireConstructor(beanName, mbd, null, null);
}
else {
//通過默認的無參構造方法進行
//todo 通過默認的無參構造方法
return instantiateBean(beanName, mbd);
}
}
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// todo 使用特定的構造方法完成自動裝配
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
//todo 使用默認的無參構造方法進行初始化
return instantiateBean(beanName, mbd);
}
我們主要關注上面代碼的 determineConstructorsFromBeanPostProcessors(beanClass, beanName)
這個方法的目的就是推測實例化需要的構造方法, 為什么需要先推測構造方法呢? 因為Spring實例化對象時,需要使用特定的構造方法才能反射出對象,這時如果程序員指定了帶參數的構造方法,spring就會使用這個構造方法實例化對象,如果程序員提供了一個不帶任何參數的默認構造方法,Spring會忽略它,按自己的邏輯使用默認的無參構造
所以上面的if-else分支目的很明確,先是嘗試獲取全部的構造方法,然后看看有沒有解析出來構造方法, 解析出來的話,就使用第一種邏輯,按照 特殊的構造方法模式進行處理,有解析出來,就使用默認的構造方法
我們進一步跟進這個determineConstructorsFromBeanPostProcessors(beanClass, beanName)
方法,可以發現方法里面又是一波后置處理器的回調工作,這次選出的后置處理器的類型是SmartInstantiationAwareBeanPostProcessor
,見名知意,這種處理器可以感知到心儀的構造方法,它的主要實現邏輯就是,查看這個將被實例化的對象中有沒有添加了@Lookup
注解的方法,有的話為這種方法生成代理,循環遍歷所有的構造方法,看看這些構造方法上存在不存在@Value
或者@Autowired
注解,因為這些注解中存在required=true,只要存在這種注解,Spring就將他當成候選的構造方法,但是如果存在多個的話,Spring也不知道到底用哪一個,但是在這里Spring會將所有符合條件的都選出來,但是一般情況下,都可以正確的選出合適的構造
選擇出合適構造方法之后,就根據不同的構造方法,選擇使用不同的方式去實例化對象, 都有什么方式呢? 兩種方式
方式1:
這是比較復雜的方式,此時Spring需要在這個方法內存比較好幾個候選的構造方法,計算它們的差異值,最終值最小的構造函數就是將要用來實例化對象的構造函數,當然很可能是選不出合適的構造函數的,於是Spring沒有立即拋出異常,而是將異常添加進bean工廠的suppressedExceptions這個set集合中
如果成功的選擇出來一個構造函數,就會使用jdk原生的反射機制,實例化一個對象
autowireConstructor(beanName, mbd, ctors, args);
方式2:
直接使用JDK原生的反射機制,實例化一個對象
instantiateBean(beanName, mbd);
小結:
代碼看到這里,方才說的有才華的那個類AbstactAutowiredCapatableBeanFactory
中的doCreateBean()
方法的 instanceWrapper = createBeanInstance(beanName, mbd, args);
也就看完了, 到這里也就知道了,Spring會先把所有滿足條件的bean全部實例化存放起來,這里的對象是百分百原生java對象,不摻水不含糖
接着往下看,我把代碼重寫貼出來, 下面還有五件大事,這四件大事說完了,本文就結束了
第一: 是applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
回調后置處理器,進行有關注解的緩存操作
第二: 是getEarlyBeanReference(beanName, mbd, bean)
獲取一個提早暴露的beanDefinition對象,用於解決循環依賴問題
第三: 將剛才創建原生java對象存放一個叫singletonFactories
的map中,這也是為了解決循環依賴而設計的數據結構,舉個例子: 現在准備創建A實例, 然后將A實例添加到這個singletonFactories
中, 繼續運行發現A實例依賴B實例,於是在創建B實例,接着又發現B實例依賴A實例,於是從singletonFactories
取出A實例完成裝配,再將B返回給A,完成A的裝配
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.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// todo 重點再來看這個 addSingleFactory
// todo 將原始對象new出來之后放到了 這個方法中的map中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean; // todo 到目前為止還是原生對象
try {
//todo 用來填充屬性
//設置屬性,非常重要
populateBean(beanName, mbd, instanceWrapper);
// todo 經過AOP處理,原生對象轉換成了代理對象,跟進去
//執行后置處理器,aop就是在這里完成的處理
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
接着看 populateBean(beanName, mbd, instanceWrapper);
方法,這個方法很重要,就是在這個方法中進行bean屬性的裝配工作,啥意思呢? 比如現在裝配A實例,結果發現A實例中存在一個屬性是B實例,這是就得完成自動裝配的工作,源碼如下:
如果仔細看,就會發現兩個事:
第一: 如果不出意外,就會出現兩次后置處理器的回調,第一后置處理器的回調是判斷當前的bean中是否存在需要裝配的屬性,而第二波后置處理器的回調就是實打實的去完成裝配的動作
第二: 下面的第一個處理器其實就是spring啟動過程中第一個回調的處理器,只不過調用了這個處理器的不同的方法postProcessAfterInstantiation()
,默認返回ture表示按照正常的流程裝配對象的屬性,返回false,表示不會繼續裝配對象中的任何屬性
而我們則繼續關注下面方法中的第二個后置處理器的,看看Spring是如何完成屬性的自動裝配的,關於這部分的跟蹤,我寫在下面代碼的后面
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
//todo 進行了強轉, InstantiationAwareBeanPostProcessor這個接口前面說過
// todo 只要是通過這個接口返回出來的bean Spring不在管這個bean,不給他裝配任何屬性
//todo 當前這里沒有用它這個變態的特性
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// todo postProcessAfterInstantiation()默認是返回true, 加上! 表示false
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
// todo Spring內部可以對BeanDefinition進行設置值, 參照自定義的 BeanFactory中獲取到BeanDefinition.getPropertyValue().addXXX();
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// todo 判斷當前bean的解析模型是 byName 還是 byType
// todo 再次驗證了::: 當程序員直接使用@Autowired注解時, 既不是ByName 也不是ByType, 而是No
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//todo 獲取出對象的所有set get方法,現在是有一個 getClass()方法,因為繼承了Object, 沒什么其他卵用
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
好,繼續跟進 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(),
,看看spring如何完成屬性的自動裝配,當然,還是那句話,如果我們直接跟進去這個方法進入的是InstantiationAwareBeanPostProcessor
抽象接口抽象方法,而我們關注的是它的實現類AutowiredAnnotationBeanDefinitionPostProcessor
的實現,打上斷點依次跟進
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// todo 跟進來, 目的是 為 beanName 填充上屬性 bean
metadata.inject(bean, beanName, pvs);
跟進
metadata.inject(bean, beanName, pvs);
源碼如下:
可以這樣理解,在下面的方法中遍歷當前對象中所有可能需要依賴注入的屬性字段
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// todo 這里的 InjectedElement 表示單個的需要注入的元素對象
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isDebugEnabled()) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
//todo 跟進 AutowiredAnnotationBeanPostProcessor 對這個方法的實現, 在600多行處
element.inject(target, beanName, pvs);
}
}
}
跟進這個inject()
我是手動刪除了這個方法中其他的很多判斷,僅僅保存下來了下面我們關注的邏輯,邏輯很清楚,上面的代碼中不是在遍歷所有需要自動裝配的field嗎?如果找到了的話,就得完成自動裝配,自動裝配什么呢? 其實就是自動裝配上當前對象依賴的其他的對象而已,因為我們使用的后置處理器是AutowireAnnotationBeanPostProcessor
通過下面的代碼就能得出結論就是@Autowired
默認情況下是通過反射實現的自動裝配
// todo 來到這里
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
我們一路往下跟進resolveDependency()
我們關注這個方法如下代碼:
if (instanceCandidate instanceof Class) {// todo !!!!!當運行到這行代碼時, myService還沒有被實例化(singletonObjects中沒有) 執行完這一個行代碼之后, IndexDao1完成了對myService的裝配
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
跟進這個resolveCandidate()
源碼如下:
很直接發現,出現的遞歸的現象,這其實解析清楚了Spring是如何完成屬性注入的,就是只不過前前后后很多接口很多類,會擾亂這個閱讀的過程
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
// todo 從bean工廠的獲取, beanName = myService requiredType = com.changwu...OrderService2 , 跟進去這個方法, 他調用了AbstractBeanFactory中的getBean(){ doGetBean();}
return beanFactory.getBean(beanName);
}
完成裝配后,其實現在的對象依然是原生的java對象 回到AbstractAutowireCapableBeanFactory
中的initializeBean()
方法,源碼如下, 看了下面的代碼就是知道了為什么applyBeanPostProcessorsBeforeInitialization
和init()
和applyBeanPostProcessorsAfterInitialization()
之間的調用順序了
還有最后一個秘密需要揭開: Spring的AOP不是產生了代理對象? 那什么時候完成的代理呢?畢竟從我開始寫這篇文章到最后都沒有看到,其實AOP的實現就在下面的代碼中
protected Object initializeBean(final String beanName, final 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()) {
//todo 執行全部的后置處理器的 Before方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// todo 執行所有的init方法
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()) {
// todo 執行所有的后置處理器的 after方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
我們在前面知道當遇到這個AbstractAutoProxyCreator
時,回調它的before()
方法時,僅僅是標記哪些對象需要進行增強哪些對象不需增強,而沒有立即生成代理對象
現在我們關注這行代碼 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
,生成代理對象的邏輯就在這里面
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// todo 進入
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
看這個方法wrapIfNecessary(bean, beanName, cacheKey);
最終會進入這個實現中
大家可以看到Spring為bean生成了代理對象,默認會先檢查被代理的對象有沒有實現接口,如果實現了接口,就是用jdk動態代理,否則就看看有沒有cglib的相關依賴,如果存在的相關依賴而沒有實現接口,就會使用cglib的代理模式
另外,補充通過編碼的方式控制 下面的if條件
config.isOptimize()
-> 可以通過XMl配置, 默認falseconfig.isProxyTargetClass()
->@EnableAspectjAutoPeoxy(true)
默認也是false
@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
//todo 目標對象是一個接口, 同樣是使用jdk的動態代理
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
// todo 所以默認使用的是 jdk的動態代理
return new JdkDynamicAopProxy(config);
}
}