本文出處Spring Bean如何初始化的 轉載請說明出處
做Java都有很多年了,一直有一個疑惑: Spring 如何初始化bean,怎麼呼叫反射例項化物件的,自己動手來解除這個疑惑。
過去我認為spring bean物件例項化一直都是由BeanPostProcessor
介面實現類去做的,我就是不知道具體那個實現類,下面就去驗證下這個猜想。
三級快取
為什麼面試官特別喜歡問建立bean的三級快取,主要是因為bean建立都是伴隨著三級快取之間的轉換完成的,物件不同狀態分別存在不同快取中,下面我會在分析程式碼時,順便支援物件如何在快取中流轉的。
先了解下spring 三級快取。
/** 一級快取 用於存放完全可以使用單例bean,也就是初始化完成並且注入所有依賴 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 二級快取 過早暴露單例物件,此時bean剛剛完成初始化,未完成屬性注入和執行 init 方法 */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** 三級快取 裝載建立bean的工廠物件 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16)
三級快取主要作用: 建立物件ObjectFactory首先放入三級換快取中,當呼叫getObject 建立例項時,會將建立好物件加入二級快取中,並且刪除三級中快取,當物件已經完成初始化方法和屬性注入,再將快取新增到一級快取中,並且刪除二級快取。
doGetBean
從源頭開始找,所有spring bean 初始化都是由AbstractBeanFactory.doGetBean
方法實現的。下面我將原始碼減除臃腫部分,貼出來。
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
//name 字首處理 beanFactory beanName 帶有&開頭
String beanName = transformedBeanName(name);
Object beanInstance;
//從三級快取去取bean,三級中都沒有則返回null,說明物件還沒有建立
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) { //如果快取中bean 是FactoryBean例項,要通過介面獲取到實際bean
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//判斷bean物件標記是否正在建立中,如果正在建立中則不應該繼續下去,出現依賴迴圈就會出現這個錯誤
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = getParentBeanFactory();
// 檢查父容器是否存在,嘗試從父容器中獲取
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) { //快取中標記beanName 正在被建立
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) { //bean 中@DependsOn 資訊,用於標記bean之間初始化順序,優先建立@DependsOn 中bean
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);
}
}
}
//建立單例物件
if (mbd.isSingleton()) { //重點就在這裡例項化物件 ,getSingleton 就是在這裡將建立完成物件加入到一級快取中
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex)
destroySingleton(beanName);
throw ex;
}
});
//如果生成bean 是FactoryBean ,再獲取真正的物件
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//作用域 = prototype,因為不會放入快取中,每次獲取都要重新建立
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);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else { // session request 這些作用域,由作用域容器去管理這些物件
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
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);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
//返回初始化成功的物件,一個物件初始化就這樣完成的了
return adaptBeanInstance(name, beanInstance, requiredType);
}
大概總結一下上面程式碼流程:
- 先從三級快取中獲取,如果快取中都沒有。再去判斷是否存在父容器,從父容器中獲取。沒有正式進入bean 初始化流程,先根據beanName 獲取到RootBeanDefinition,bean類元資訊、先處理dependsOn中bean,保證bean依賴的建立順序,下面會說明
org.springframework.context.annotation.@DependsOn
這個註解。下一步按照不同scope 進行bean 物件初始化。初始化流程就是這樣,我們將目光放在單例bean 如何例項化,集中關注AbstractAutowireCapableBeanFactory.createBean
獲取註冊一個單例物件
@DependsOn
註解意思是例項化某個物件依賴於某一個例項化,但是不需要持有這個例項物件。比如bean A上 需要依賴bean b才能例項化,但是bean b 不需要作為他的屬性,常常用於不同例項例項化順序標記。
看下getSingleton方法
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) { //標記bean 是否在銷燬
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
}
catch (BeanCreationException ex) {
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject); //就是在這裡刪除二三級快取,提交到一級快取
}
}
return singletonObject;
}
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
新增到一級快取則說明bean已經完成例項化,可以正常使用了。下面看下如何進行例項化和屬性注入的。
createBean
下面進入AbstractAutowireCapableBeanFactory.createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
//克隆一份mbd => mbdToUse
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
//通過BeanPostProcessors 增強返回一個代理物件,這個生成AOP的代理物件,使用多個BeanPostProcessors來處理
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 {
// bean 物件例項化就這裡實現
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
這裡邏輯就比較簡單了 ,克隆一份RootBeanDefinition用於初始化物件,resolveBeforeInstantiation 主要用於初始化代理物件情況,主要使用BeanPostProcessor子類InstantiationAwareBeanPostProcessor實現方法去實現物件初始化,並且在例項化成功後在呼叫後置方法進行物件依賴注入,這裡可以看見此方法返回物件直接跳出方法棧,這裡可以看出單例和代理物件還是有區別的。單例物件初始化就在doCreateBean 實現了
doCreateBean
下面就是AbstractAutowireCapableBeanFactory.doCreateBean
非常接近物件如何例項化的了
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args); //這個就是例項化方法
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 使用BeanDefinitionPostProcessors 對合並bean進行例項化
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;
}
}
// 這裡就需要用到上面說的三級快取知識了
// 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)); //將已經例項化的物件加入到第三級快取 singletonFactories
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper); //對屬性進入注入,下面會具體分析的
exposedObject = initializeBean(beanName, exposedObject, mbd); //執行初始化方法,或者注入Aware 介面bean
}
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);
}
}
//下面程式碼省略
//主要就是對設定了DisposableBean 介面銷燬鉤子方法處理
}
這裡程式碼主要分成三部分
- 初始化例項,建立物件完成,並且新增到3級快取。第3級快取常常用於儲存代理物件,因為有些類需要動態代理方法,需要生成代理物件,會委派給第三級快取方法ObjectFactroy去實現的,普通物件如果不需要會直接返回。
- 對例項化bean進行屬性注入
- 執行初始化方法,DisposableBean介面加入到disposableBeans容器中
instantiateBean
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) {// 有實現Supplier 介面,由instanceSupplier.get() 方法建立例項
return obtainFromSupplier(instanceSupplier, beanName);
}
//factoryName 使用工廠模式建立bean,呼叫工廠方法去建立,這個支援靜態方法和factoryBean.invoke
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);
}
}
// 獲取建構函式引數
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
例項化方法instantiateBean最終會呼叫SimpleInstantiationStrategy.instantiate 進行例項化
instantiate
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);
}
}
}
return BeanUtils.instantiateClass(constructorToUse); //呼叫建構函式進行例項化
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
instantiateClass
@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);
}
}
}
return BeanUtils.instantiateClass(constructorToUse); //呼叫構造器進行初始化
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
這裡要注意下先判斷bean是否有方法重寫的,沒有則使用反射生成的構造器,有就使用gclib方式建立代理物件,具體實現方式就在org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate
,有興趣同學可以去學習下。
到此一個簡單bean例項化完成了。
注入
下面進入IOC另一個特點,bean注入,先從AbstractAutowireCapableBeanFactory.populateBean
方法開始
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 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.
//通過InstantiationAwareBeanPostProcessors.postProcessAfterInstantiation 如果返回true,目標例項內部的返回值會被populate,否則populate這個過程會被忽視
//翻譯說如果返回true可以執行欄位注入 真的6666啊
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
//獲取注入方式分佈有4種
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
//依賴方式,模式都是沒有型別檢查,這種依賴方式一般都是xml 配置用得比較多,沒有配置這裡都是返回false
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); /
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); //獲取註解標註需要注入方法或者是欄位,並且進行注入
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
小知識點:
AutowireCapableBeanFactory.AUTOWIRE_NO 表明不會對當前Bean進行外部類的注入,常規使用@Autowire、@Resource 都是這型別
剩下三種都是通過xml 或者 AutowireCapableBeanFactory.autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) 進行設定autowireMode 。
根據上面程式碼可以知道主流程bean注入都是由InstantiationAwareBeanPostProcessor 進行處理的,簡單說明介面方法
方法 | 描述 |
---|---|
postProcessBeforeInitialization | 方法是最 先執行的方法,它在目標物件例項化之前呼叫,該方法的返回值型別是Object,我們可以返回任何型別的值。由於這個時候目標物件還未例項化,所以這個返回值可以用來代替原本該生成的目標物件的例項(比如代理物件)。如果該方法的返回值代替原本該生成的目標物件,後續只有postProcessAfterInitialization方法會呼叫,其它方法不再呼叫;否則按照正常的流程走 |
postProcessAfterInitialization | 方法在目標物件例項化之後呼叫,這個時候物件已經被例項化,但是該例項的屬性還未被設定,都是null。因為它的返回值是決定要不要呼叫postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法返回false,並且不需要check,那麼postProcessPropertyValues就會被忽略不執行;如果返回true,postProcessPropertyValues就會被執行 |
postProcessPropertyValues | 對bean屬性值賦值後呼叫,對屬性值的修改。如果postProcessAfterInstantiation方法返回false,該方法可能不會被呼叫。可以在該方法內對屬性值進行修改 |
postProcessProperties | Bean屬性賦值就是呼叫這個方法的 |
InstantiationAwareBeanPostProcessor 介面實現類主要分3個
- ConfigurationClassPostProcessor:看類名就知道處理@Configuration例項化,並沒有屬性注入邏輯,不詳講略過。
- CommonAnnotationBeanPostProcessor:這個類就是實現bean注入,但是是實現JSR-250 註解、@Resource,@EJB、@WebServiceRef,@WebServiceContext,@PostConstrusct、@PreDestory這些註解實現。
- AutowiredAnnotationBeanPostProcessor:實現 @Autowired、@Value注入,並且支援JSR-330's @Inject,主要分析這個類就可以知道bean 注入的。
AutowiredAnnotationBeanPostProcessor分析
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
在初始化時就將支援註解加入集合中,再使用掃描器去掃描方法、構造器、欄位,如果有這些註解就進行注入。
看下怎麼判斷是否需要注入的
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao);
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
}
AccessibleObject 是Method、Field、Constructor 父類。
postProcessProperties 如何實現bean注入的
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//獲取需要注入欄位,方法
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs); //注入
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
//下面就行獲取InjectionMetadata
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 快速從快取中獲取,如果沒有加鎖去解析,然後在結果放入快取中
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) { //雙重檢查
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
- InjectionMetadata 主要是集合bean需要被注入型別,因為已經解析過bean Class資訊了,相當於解析結果裝起來
看下如何去掃描方法、欄位的
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
//從給定註解中判斷class 是否攜帶這個註解
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
//遍歷所有Field,找出掃描的註解,特意標註不支援static 修飾field
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
// 獲取註解內 required 值
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
//獲取方法上橋接方法,因為泛型型別擦除,要對橋接方法進行安全檢查,防止在呼叫是出現異常
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
//獲取註解
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
//方法安全檢查
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) { //不支援靜態方法注入
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
// 這樣寫是為了後面加入排在佇列前面,父類屬性優先於子類
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class); //這裡寫得很好,向上解析父類,直到是Object 為止
return InjectionMetadata.forElements(elements, clazz);
}
邏輯非常簡單,就是根據給定註解去class獲取指定的註解,從而獲取到需要注入型別,但是幾行簡單的程式碼可以看出強大編碼能力,學習了?。
現在需要注入物件已經獲取到,看如何注入吧
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter(); //型別轉換器
Object value;
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
Object cachedFieldValue = null;
if (value != null || this.required) {
cachedFieldValue = desc;
// 將注入關係新增到容器中,方便bean銷燬時同步銷燬
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { //這些都是為了快取起來
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
return value;
}
}
主要核心是如從快取獲取到需要注入型別例項在beanFactory.resolveDependency
中
進入DefaultListableBeanFactory看下
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
//懶載入 掃描@Lazy註解,返回一個代理物件
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
@Lazy 使用註解修飾bean 或者Class,在容器初始化化時不會立刻建立,只要需要使用bean才會建立的。
根據型別Optional、ObjectFactory、Provider,還有懶載入情景不同的處理,這些處理本質都是要呼叫doResolveDependency方法初始化物件,無論那種物件都要 獲取原始物件然後再交給這些介面去包裝增強。
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//如果這個注入是通過構造器注入,可以從構造器解析快取中去獲取注入資訊點
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
//嘗試從註解中獲取預設值 @Value 的value
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
//多種混合型別處理,stream、collection、Map Array 這些
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
//根據型別獲取容器中bean名,返回map key就是bean名,value 初始從容器中獲取物件,如果沒有找到就會丟擲異常了
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) { //出現一個型別,不同例項,可以根據@Primary, @Priority、屬性名方式去配置
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { //沒有確定,丟擲異常
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) { //這裡其實就是從容器中獲取例項,如果這時候沒有初始化,就走上面初始化流程
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
這個方法簡單做個總結,先是處理 @Value 情況,然後通過findAutowireCandidates 通過型別去容器中獲取例項,如何例項還沒有初始化,就會呼叫上面那個初始化過程,將初始化物件返回。根據注入型別進行相應處理,像stream、Collection,這些混合型別都是直接新增進去。如果出現了一個型別多個bean情況,這時就是就是@Primary、@Priority這些註解來判斷或者根據屬性名去和beanName匹配,最後將bean物件返回。
這裡就簡單看完一個bean初始化流程了。
總結
現在知道了Bean例項化是由一個策略模式,使用反射攻擊類建立的,和BeanPostProcessor其實並沒有太多關係的。像我剛開始學spring時,老師就說@Autowired 和@Resources向比較,基於型別和beanName進行注入的,這樣說不完全正確的。他是通過型別去獲取bean,如果出現一個型別有多個beanName,才通過bean和屬性名進行注入。使用這麼多年Spring了,從來沒有使用過@DependsOn、@Primary、@Priority、@Lookup如果不看原始碼還不知道有這個特性呢。看完整個原始碼,對bean生命週期有了比較清晰 bean例項化-> 屬性注入-> 執行初始化方法-> 加入spring容器