Spring 源碼中的擴展點分析

     Spring作爲開源的框架目前正被互聯網行業廣泛的使用,在我們在面試的過程中也經常會被問到。這篇博客記錄了我在學習spring的IOC容器中遇到的一些瑣碎的知識點,並對相關文檔進行參考,把它記錄下來,鞏固和學習,如有錯誤,歡迎指正。我們經常會被問 什麼是spring? 其實很多人都認爲spring就是IOC和AOP,其實不然,spring是產品,裏面包含很多技術,包括springcloud,springdata,springfremwork等等,IOC和AOP只是spring中核心技術的一部分。

目錄

一、spring IOC容器

1、基本內容

1.1、什麼是Spring IOC?

1.2、什麼是DI(依賴注入)

1.3、爲什麼要使用spring IOC

1.4、spring有幾種編程風格

1.5、Spring依賴注入方式有哪些

1.6、spring的自動裝配模式有哪些

1.7、自動裝配方式有哪些

1.8、自動裝配的優缺點

1.9、ApplicationContext 創建並初始化spring容器

2、spring的beans

2.1、單例和原型

2.2、Singleton的bean中引用了一個Prototype的bean的時候會出現Prototype失效的情況

2.3、spring生命週期回調有哪幾種方式,執行順序是什麼

2.4、當spring容器完成初始化之後,想執行某個方法,怎麼做

2.5、在spring源碼中生命週期初始化回調方法initializeBean做了哪些事情

3、spring註解的一些知識點

3.1、@Autowired註解和自動注入模式的關係

3.2、@Autowired和@Resource的區別

3.3、屬性是如何注入的

二、spring中的AOP

三、spring中的重要類

FactoryBean

beanDefintion

四、spring中的擴展點

4.1、BeanPostProcessor

4.2、AutowiredAnnotationBeanPostProcessor

4.3、CommonAnnotationBeanPostProcessor

4.4、BeanFactoryPostProcessor

4.5、BeanDefinitionRegistryPostProcessor

4.6、ConfigurationClassPostProcessor

五、解讀spring源碼中的知識點

5.1、jdk動態代理實現原理

5.2、cglib代理如何實現

5.3、spring中在哪些地方用到了動態代理

5.4、spring源碼中使用了哪些設計模式

5.5、spring中有哪些不能被代理的bean

5.6、FactoryBean和普通bean的區別?

5.7、如何把自己自定義的對象放到spring容器中

5.8、爲什麼Appconfig類是通過register(Appconfig.class);手動put到map當中呢?爲什麼不是掃描出來的呢?

5.9、爲什麼spring當中默認支持循環依賴?或者spring在哪裏體現了默認支持循環依賴?

5.10、spring事務不生效有哪些原因

5.11、推斷構造方法


一、spring IOC容器

1、基本內容

1.1、什麼是Spring IOC?

     首先IOC(Inversion of Control)就是控制反轉,官網說法是,IOC也被稱爲DI(依賴注入)。官網截圖如下:

Spring IOC是指:將對象的實例化反轉給spring容器,在傳統的開發模式中,當我們創建一個對象時,需要new或者newInstance等直接或者間接的方式調用構造方法創建這個對象,這樣對象的實例化控制權是由應用程序控制的。而反轉就是將這種權利反轉給spring容器,spring容器通過工廠模式爲程序員創建了所需的對象,程序員無需創建對象(只需要提供對象的類型即可),直接調用spring容器提供的對象就行了,這就是控制反轉。

1.2、什麼是DI(依賴注入)

依賴注入(DI)是指:spring 使用 java 對象的 set 方法或者帶參數的構造方法爲我們在創建所需對象時將其屬性自動設置所需要的值的過程,就是依賴注入的思想。

1.3、爲什麼要使用spring IOC

第一:對象的實例化不是一件簡單的事情,比如對象的關係比較複雜,依賴關係往往需要程序員去維護,這是一件非常頭疼的事;

第二:解耦,由容器去維護具體的對象;

第三:託管了類的產生過程,比如我們需要在類的產生過程中做一些處理,最直接的例子就是代理,如果有容器程序可以把這部分過程交給容器,應用程序則無需去關心類是如何完成代理的。

1.4、spring有幾種編程風格

     官網上說spring在1.0 使用xml配置方式,在2.5引入了註解 annotation(註解)配置方式,在3.0引入了javaconfig配置方式。官網說明如下:

1.5、Spring依賴注入方式有哪些

      查看spring官方文檔可知,注入方式有兩種:

      1、Constructor-based Dependency Injection(構造方法注入)

      官方文檔詳見:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-constructor-injection

      2、Setter-based Dependency Injection(基於setter的注入方式)

      官方文檔詳見:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-setter-injection

1.6、spring的自動裝配模式有哪些

Spring的自動注入模型有四種:

no(默認)無自動裝配。

byName:按照名稱進行裝配,<bean id="dao" name="dao" class="">   spring會根據name的名字進行裝配(默認 id 和name相同),在類中,name的值要與set方法一致  :例如: name="zlu"    setter的方法應該爲setZlu()  才能進行自動裝配。

byType:按類型進行裝配,spring會找 依賴的屬性的接口或者父類下的實現類或者子類,進行注入,例如: private IndexDao dao;    spring會找實現了IndexDao接口的類進行注入。

Constructor類似於byType,但適用於構造函數參數。如果容器中沒有一個構造函數參數類型的bean,則會引發致命錯誤,使用Constructor的方式,系統會推斷構造方法,選擇參數最多的構造方法,解析構造方法的參數(每個參數表示一個依賴項)去找bean。

1.7、自動裝配方式有哪些

  有兩種方式:在XML中有如下兩種配置方式,按照setter的名字對應:

spring也提供了相應的api:

1.8、自動裝配的優缺點

    優點:

   (1) 自動裝配可以顯著減少指定屬性或構造函數參數的需要(減少依賴的注入的配置)

   (2) 當對象發生改變會自動更新配置。例如,如果需要向類添加依賴項,在容器中添加bean即可。

詳細信息查看官方文檔:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-autowire

    缺點:(但是這些缺點對於我來說不能算作缺點)

(1) property和constructor-arg設置中的顯式依賴項能夠覆蓋自動裝配(xml中配置的依賴能夠使自動裝配無效)。

(2)自動裝配不如顯式注入精確,無法明確記錄Spring管理對象之間的關係。

(3) 可能無法爲可能從Spring容器生成文檔的工具提供連線信息。

(4)容器中的多個bean定義可以匹配setter方法或構造函數參數指定的類型以進行自動裝配。對於數組,集合或Map實例,這不

一定是個問題。但是,對於期望單個值的依賴關係,這種模糊性不是任意解決的。如果沒有可用的唯一bean定義,則拋出異常。

詳細信息查看官方文檔:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-autowired-exceptions

1.9、ApplicationContext 創建並初始化spring容器

ApplicationContext可以通過ClassPathXmlApplicationContext和AnnotationConfigApplicationContext創建並初始化容器。

代碼如圖:

//java config的方式
ApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);
//xml的方式
ApplicationContext context1 = new ClassPathXmlApplicationContext("spring.xml");

2、spring的beans

2.1、單例和原型

  官方參考文檔;https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-scope。我們用的最多的是: singleton:單例(默認),每次獲取的hashcode相同; prototype:原型:每次獲取的hashcode不同。單例的對象在spring創建和初始化的時候實例化的,spring會將對象放入到一個單例池中(源碼中的singletonMap中)緩存起來,在使用時直接去map中獲取即可,原型的對象是在getBean的時候實例化的。

2.2、Singleton的bean中引用了一個Prototype的bean的時候會出現Prototype失效的情況

原因是:假設A是單例的,B是原型的,A依賴了B,那麼雖然被依賴的對象B是prototype的,但是A對象是singleton的,在運行的過程中 這個A對象只是實例化了一次,因此只有一次機會設置B,每次需要時,容器不能爲A提供B的實例。

解決方案:就是放棄控制反轉,每次調用B時,爲B創建新的實例。

     1、在service類中新寫一個方法,在方法上添加@Lookup  ,代碼如下:

@Service
@Scope(value = "singleton")
public class IndexServiceImpl  {

    @Autowired
    private IndexDao dao;

    public void query(){
        System.out.println("service:"+this.hashCode());
        getDao().test();
    }

    @Lookup()
    public IndexDao getDao() {
        return null;
    }
}

 (注意:Spring提供了一個名爲@Lookup的註解,這是一個作用在方法上的註解,被其標註的方法會被重寫,然後根據其返回值的類型,容器調用BeanFactory的getBean()方法來返回一個bean。源碼中  在實例化的過程中,會將加了@LookUp的方法放到MethodOverrides set中,beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);生成實例策略時會判斷,如果set裏面有值,則return instantiateWithMethodInjection(bd, beanName, owner);進入這個方法,cglib代理)

     2、實現接口ApplicationContextAware

     官方參考:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-method-injection

代碼如下:

@Service
@Scope(value = "singleton")
public class IndexServiceImpl1 implements ApplicationContextAware {

    ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }

    public void query(){
        System.out.println("service:"+this.hashCode());
        ((IndexDao)applicationContext.getBean("indexDaoImpl")).test();
    }
}

2.3、spring生命週期回調有哪幾種方式,執行順序是什麼

  參考文檔:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-lifecycle

Spring中實現生命週期的回調有三種方式,一種是註解@PostConstruct和 @PreDestroy,一種是實現接口,InitializingBean,重寫afterPropertiesSet()方法,實現接口DisposableBean,重寫destroy()方法,還有一種是通過spring提供的xml裏面配置一個default-init-method="init"或者      default-destroy-method=“destory”標籤,指明方法。這三種方式都能實現spring生命週期的回調,但是他們有一個執行順序,是註解最先,接口第二,xml指定是第三,爲什麼呢?因爲spring處理生命週期回調是基於spring的生命週期來的,有源碼得知,spring先通過一個後置處理器(InitDestroyAnnotationBeanPostProcessor)拿到這個註解解析執行,然後再執行invokeInitMethods方法,在invokeInitMethods方法裏面依次執行接口方法(判斷bean是否實現了InitializingBean接口)和xml方法

2.4、當spring容器完成初始化之後,想執行某個方法,怎麼做

採用生命週期回調。(spring源碼)在bean屬性注入之後(就是bean被初始化之後立馬執行bean的初始化回調方法) 進行生命週期回調。

2.5、在spring源碼中生命週期初始化回調方法initializeBean做了哪些事情

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()) {
			//執行加了@PostContrustot 註解的方法
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		try {
			//執行bean的生命週期回調的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()) {
			//執行後置處理器的after方法 在這裏 進行aop形成代理
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}

3、spring註解的一些知識點

3.1、@Autowired註解和自動注入模式的關係

@Autowired(是spring包中提供的註解)與自動注入模型沒有關係,它屬於手動裝配,先根據類型(注意 這個類型不是自動注入模型中的byType模型)找,找不到再根據名稱(注意 這個名稱不是自動注入模型中的byName模型)找,找到了則注入,沒有找到則異常,與byType和byName無關

可以通過代碼進行驗證:

程序中通過獲取自動裝配模型 得到結果爲0,咋源碼中得知 0代表 不採用自動裝配。源碼說明如下:

3.2、@Autowired和@Resource的區別

(1)提供者不一樣  @Autowired是spring包中提供的註解,@Resource是jdk中提供的註解;

(2)解析類不一樣 @Autowired是由後置處理器AutowiredAnnotationBeanPostProcessor解析,@Resource是由後置處理器CommonAnnotationBeanPostProcessor解析

(3)功能不一樣 @Autowired是先根據類型找,在根據name找,@Resource是先根據name找,找不到再根據type找。

3.3、屬性是如何注入的

首先屬性注入在spring源碼中是在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean方法中執行的。

源碼如下:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	   //註釋無關代碼
       PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

		/**
		 * 自動注入模型,當自動注入模式爲byType或者byName時進入這個判斷,
		 * 加了@Autowire註解的 不進入這個判斷,證明了@Autowire不屬於自動注入模型
		 */
		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();
			if (hasInstAwareBpps) {
				//根據不同的BeanPostProcessor(策略),完成不同註解的解析,進行屬性注入,在循環依賴
				//的時候,進行屬性注入還會getBean一下
				/**
				 * 循環所有的BeanPostProcessors後置處理器,判斷是否是InstantiationAwareBeanPostProcessor的實現類,
				 * AutowiredAnnotationBeanPostProcessor後置處理器和CommonAnnotationBeanPostProcessor後置處理器
				 * 都實現了這個接口。所以如果屬性加了@Autowired註解和@Resource註解,則進入這個判斷
				 */
				for (BeanPostProcessor bp : getBeanPostProcessors()) {
					if (bp instanceof InstantiationAwareBeanPostProcessor) {
						InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
						/**
						 * 屬性注入
						 */
						pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvs == null) {
							return;
						}
					}
				}
			}

		if (pvs != null) {
			// 註釋 5.5 解析參數,如果是引用對象,將會進行提前加載
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

@Autowired屬性注入一般有以下幾種情況:

// (1)  OrderDao是一個具體類
@Autowired
private OrderDao orderDao;

// (2)  I是一個接口 有多個實現類,orderDao是其中一個
@Autowired
private I orderDao;

// (3)  List集合封裝接口I
@Autowired
private List<I> list;

 接下來通過斷點的方式進入postProcessPropertyValues方法:

@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
		//findAutowiringMetadata()方法這裏獲取注入元數據信息
		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;
	}

再次進入findAutowiringMetadata方法,再從這個方法進入buildAutowiringMetadata方法,在這個方法中找打所有加了Autowired註解並且符合要求的field和method放在list集合中:

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				//查找這個對象中有沒有加了@Autowired註解的屬性
				AnnotationAttributes ann = findAutowiredAnnotation(field);
				if (ann != null) {
					//如果存在  這個屬性不能是Static類型的,因爲Autowired註解不支持
					//static類型的屬性
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isWarnEnabled()) {
							logger.warn("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
					//獲取這個autowired註解裏的Required 是什麼狀態
					boolean required = determineRequiredStatus(ann);
					//將這個加了Autowired註解的屬性加入list集合中
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				//獲取這個對象中 所有的方法上面的@Autowired註解
				AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					//如果有註解,首先不能是static類型的
					if (Modifier.isStatic(method.getModifiers())) {
						if (logger.isWarnEnabled()) {
							logger.warn("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					//Autowired註解只能用於帶有參數的方法
					if (method.getParameterCount() == 0) {
						if (logger.isWarnEnabled()) {
							logger.warn("Autowired annotation should only be used on methods with parameters: " +
									method);
						}
					}
					//獲取這個autowired註解裏的Required 是什麼狀態
					boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					//將這個加了Autowired註解的方法加入list集合中
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});
			//將上面兩個currElements的數據放入一個集合中
			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);
		//封裝
		return new InjectionMetadata(clazz, elements);
	}

 接下來進入metadata.inject方法進行真正的屬性注入:

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		//獲取對象中加了@Autowired註解的元數據集合
		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);
				}
				//注入
				element.inject(target, beanName, pvs);
			}
		}
	}

通過斷點進入element.inject方法:

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		 Field field = (Field) this.member;
		Object value;
		if (this.cached) {
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}else {
			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();
			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) {
					//如果加了autowired註解的field的required=true,則進入
					if (value != null || this.required) {
						this.cachedFieldValue = desc;
						//註冊依賴的bean
						registerDependentBeans(beanName, autowiredBeanNames);
						/**
						 * 如果只有一個bean的名字,那麼獲取這個beanName判斷
						 * 在bean的工廠中是否存在,如果存在並且跟這個file的類型匹配,
						 * 說明spring工廠中存在這個類,可以進行注入
						 */
						if (autowiredBeanNames.size() == 1) {
							String autowiredBeanName = autowiredBeanNames.iterator().next();
						if (beanFactory.containsBean(autowiredBeanName) &&
									beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
									this.cachedFieldValue = new ShortcutDependencyDescriptor(
										desc, autowiredBeanName, field.getType());
								}
							}
						}else {
							this.cachedFieldValue = null;
						}
						this.cached = true;
					}
				}
			}
			if (value != null) {
				//重要
				ReflectionUtils.makeAccessible(field);
				//真正的注入就是通過java的field.set方法將屬性注入進來
				field.set(bean, value);
			}
		}
	}

 進入doResolveDependency方法能夠獲取符合條件的屬性集合:

@Nullable
	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的名字,不設置的話一般爲空
			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());
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}
			/**
			 * 如果field類型是數組,list或者map的話,就去找符合條件的所有bean
			 * 封裝到set集合中,直接返回
			 */
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}
			//如果filed不是上面幾種類型,則說明注入的bean只有一個,直接去匹配
			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) {
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(type, matchingBeans);
					}
					else {
						// In case of an optional Collection/Map, silently ignore a non-unique case:
						// possibly it was meant to be an empty collection of multiple regular beans
						// (before 4.3 in particular when we didn't even look for collection beans).
						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);
		}
	}

	@Nullable
	private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
		//獲取加了autowired註解的屬性類型
		Class<?> type = descriptor.getDependencyType();
		/**
		 * 如果是數組類型的,則進入這個判斷,找到所有符合條件的bean,放到set集合中
		 */
		if (type.isArray()) {
			Class<?> componentType = type.getComponentType();
			ResolvableType resolvableType = descriptor.getResolvableType();
			Class<?> resolvedArrayType = resolvableType.resolve();
			if (resolvedArrayType != null && resolvedArrayType != type) {
				type = resolvedArrayType;
				componentType = resolvableType.getComponentType().resolve();
			}
			if (componentType == null) {
				return null;
			}
			//查找符合條件的bean
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
					new MultiElementDescriptor(descriptor));
			if (matchingBeans.isEmpty()) {
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			Object result = converter.convertIfNecessary(matchingBeans.values(), type);
			if (getDependencyComparator() != null && result instanceof Object[]) {
				Arrays.sort((Object[]) result, adaptDependencyComparator(matchingBeans));
			}
			return result;
		}
		/**
		 * 如果是集合類型的,則進入下面這個判斷,根據集合中的對象類型查找符合條件的bean
		 * 放到set集合中
		 */
		else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
			Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
			if (elementType == null) {
				return null;
			}
			//根據集合中的對象類型查找符合條件的bean,如果對象類型爲接口,則去找所有的接口實現類
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
					new MultiElementDescriptor(descriptor));
			if (matchingBeans.isEmpty()) {
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			Object result = converter.convertIfNecessary(matchingBeans.values(), type);
			if (getDependencyComparator() != null && result instanceof List) {
				((List<?>) result).sort(adaptDependencyComparator(matchingBeans));
			}
			return result;
		}
		/**
		 * 如果是map類型的,則進入下面這個判斷,根據集合中的對象類型查找符合條件的bean
		 * 放到set集合中
		 */
		else if (Map.class == type) {
			ResolvableType mapType = descriptor.getResolvableType().asMap();
			Class<?> keyType = mapType.resolveGeneric(0);
			if (String.class != keyType) {
				return null;
			}
			Class<?> valueType = mapType.resolveGeneric(1);
			if (valueType == null) {
				return null;
			}
			//根據集合中的對象類型查找符合條件的bean,根據key和value去匹配spring容器中的bean
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
					new MultiElementDescriptor(descriptor));
			if (matchingBeans.isEmpty()) {
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			return matchingBeans;
		}
		else {
			return null;
		}
	}

 總結:

首先判斷註解是@Autowired 還是@Resource,如果是前者,則使用AutowiredAnnotationBeanPostProcessor後置初期器處理,如果是後者,則使用CommonAnnotationBeanPostProcessor後置處理器處理,用前者舉例,首先去獲取注入的屬性的類型,將其beanmane存放在set集合中,判斷如果set的長度如果爲1,則用beanName去容器中匹配,返回true,通過field.set注入,例如:

@Autowired

       private OrderDao orderDao;

如果是接口的形式:則找到所有實現了這個接口的類,放到map<beanName,Class>中,如果map的長度大於1,說明根據類型找會找出多個,有衝突,那麼就 去循環這個map,找出與這個與依賴的 這個名稱palyDao有沒有相同beanName,如果有,則取出,實例化,通過field.set注入。如果找不到,則報錯,注意被注入的屬性不能是static的,否則不會生效,例如:

@Autowired

private I palyDao;

如果是List類型,spring會拿到這個field的類型List判斷是不是Array,在判斷是不是Collection並且類型是接口,如果是則獲取這個list的類型com.zlu.aspect.I I,拿到之後將這個接口的所有實現類用Map<String, Object>存放起來,用Set<String>將所有的map.keySet 存放起來,然後將這寫類全部注入進來:field.set(bean, value),例如:

@Autowired

private List<I> list;

二、spring中的AOP

三、spring中的重要類

  • FactoryBean

  • beanDefintion

四、spring中的擴展點

spring容器中有一些擴展點在再spring創建bean的生命週期中扮演着重要的角色。spring中有兩個重要的擴展點的接口,分別是BeanPostProcessor和BeanFactoryPostProcessor。他們下面有很多實現類,承擔着不同的任務。

4.1、BeanPostProcessor

BeanPostProcessor是Spring擴展點之一,BeanPostProcessor是一個接口,程序員可以通過實現它,插手bean的實例化過程,在bean創建前後,在bean被spring管理之前,做一些事情。在源碼中使用了很多BeanPostProcessor的實現類做一些事情,例如使用AutowiredAnnotationBeanPostProcessor解析@Autowired註解,在實例化之後做屬性注入;使用CommonAnnotationBeanPostProcessor解析其他如@Resource 註解,在實例化之後做屬性注入;使AbstractAutoProxyCreator完成aop功能,以及完成動態代理功能,解析@PostConstruct註解等等。

我們自己編寫一個類實現BeanPostProcessor來實現簡單的jdk代理,簡單代碼如下:

@Component
public class MyPostProsser implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		//如果是AOP的話,相當於返回的是代理
		Object cc = Proxy.newProxyInstance(MyPostProsser.class.getClassLoader(),
				bean.getClass().getInterfaces(), new MyInvocationHandler(bean));
		return cc;
	}
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

4.2、AutowiredAnnotationBeanPostProcessor

 AutowiredAnnotationBeanPostProcessor實現了BeanPostProcessor,在spring進行屬性注入的過程中,完成了對@Autowired註解的解析,找到加了@Autowired的field和method,放到集合中,等待進行注入。

4.3、CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor實現了BeanPostProcessor,在spring進行屬性注入的過程中,完成了對@Resources註解的解析,找到加了@Resources的field和method,放到集合中,等待進行注入。

4.4、BeanFactoryPostProcessor

程序員可以通過實現它,修改應用程序上下文的內部bean工廠、讀取bean的定義,覆蓋或添加屬性,例如:

//@Component
public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		//獲取bd
		GenericBeanDefinition aa = (GenericBeanDefinition) beanFactory.getBeanDefinition("zluService1");
		//設置自動注入模型的類型
		aa.setAutowireMode(2);
		System.out.println(aa.getAutowireMode());
		//設置bean對應的類
		aa.setBeanClass(ZluService.class);

	}
}

4.5、BeanDefinitionRegistryPostProcessor

4.6、ConfigurationClassPostProcessor

五、解讀spring源碼中的知識點

5.1、jdk動態代理實現原理

JDK動態代理是通過方法newProxyInstance實現的,具體方法如下:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

參數說明:

ClassLoader loader:動態加載一個類,類加載器定義代理類,獲取類加載器後,可以通過這個加載器,在程序運行時,將生成的代理類加載到JVM即Java虛擬機中,以便運行時需要。

Class<?>[] interfaces:接口數組 ,代理類要實現的接口列表,以便於生成的代理類可以具有代理類接口中的所有方法。

InvocationHandler h:在這裏面,代理類要實現接口,並重寫裏面的方法,在invoke方法裏面實現具體邏輯。

InvocationHandler裏面有一個invoke方法實現具體代理邏輯,如下:

public Object invoke(Object proxy, Method method, Object[] args)   

參數說明:

 Object proxy:生成的代理對象,在這裏不是特別的理解這個對象,但是個人認爲是已經在內存中生成的proxy對象。

Method method:被代理的對象中被代理的方法的一個抽象,method.invoke方法能夠實現被代理的類的真正邏輯。

Object[] args:被代理方法中的參數。這裏因爲參數個數不定,所以用一個對象數組來表示。

5.2、cglib代理如何實現

實際上,會生成一個代理類,這個代理類繼承了目標對象,重寫了目標對象裏面的方法,在方法的前後執行代理邏輯。

例如,我們寫一個目標類:

//目標類
public class E {
   public void cglibMethod(){
      System.out.println("target ");
   }
}

然後再寫一個執行代理邏輯的類:

/**
 * 真正實現代理邏輯的類,必須實現MethodInterceptor接口,重寫intercept方法
 * 在intercept方法中編寫代理邏輯
 */
public class MyMethodInterceptor implements MethodInterceptor {
   @Override
   public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
      System.out.println("cglib");
      //執行目標方法
       methodProxy.invokeSuper(o,objects);
      return null;
   }
}

 然後編寫測試程序:

//測試
public class Test {
   public static void main(String[] args) throws IllegalAccessException, InstantiationException {
      Enhancer enhancer = new Enhancer();
      //增強父類 cglib是基於繼承的
      enhancer.setSuperclass(E.class);
      enhancer.setUseFactory(false);
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      //攔截器 對目標對象進行攔截 重要
      enhancer.setCallback(new MyMethodInterceptor());
      E subclass = (E) enhancer.create();
      subclass.cglibMethod();
   }
}

最終Cglib產生的代理類類似如下 :

/**
 * 假設這是cglib的代理類(這是生成的)
 */
public class XXXCglib extends E{
   MyMethodInterceptor my;
   @Override
   public void cglibMethod() {
      my.intercept();
   }
}

5.3、spring中在哪些地方用到了動態代理

5.4、spring源碼中使用了哪些設計模式

  • 簡單的工廠模式,又叫做靜態工廠方法(StaticFactory Method)模式。簡單工廠模式的實質是由一個工廠類根據傳入的參數,動態決定應該創建哪一個產品類。

spring中的BeanFactory就是簡單工廠模式的體現,Spring使用工廠模式可以通過 BeanFactory或 ApplicationContext創建 bean 對象,比如ApplicationContext的實現類AnnotationConfigApplicationContext、ClassPathXmlApplicationContext通過javaconfig或者xml創建和初始化spring容器。

  •        單例的設計模式,通過使用註解@Scope(value="singleton")實現單例模式,在spring容器中默認使用單例模式,在spring源碼中會解析加了這個註解的bean,在創建bean後,將它保存到singletonObjects(ConcurrentHashMap)的單例池中,在下次使用時,直接獲取即可。
  •        代理設計模式,spring中使用到了JDK動態代理和cglib代理。

對於AppConfig這個配置類,加了@Configuration和不加這個註解,都能創建和初始化spring容器,但是卻有一些差別。在spring處理bean的工廠的後置處理器的時候,對於上了@Configuration的配置類設置full標誌,把沒有帶上@Configuration,但是帶上了@Component @ComponentScan @Import @ImportResource等註解的配置類設置爲lite標誌。spring會對加了full標誌的配置類進行cglib代理,如果配置類裏面加了@Bean註解的方法多次new同一個對象,只能創建一次,反之創建多次。

總結:保證單例,對方法進行調用的時候,spring會記錄一下當前創建bean的方法,如果在方法內部還調用了另外的方法,spring會將兩個方法進行比對,當前創建bean的方法和當前執行的方法 是否一樣,如果一樣,則調用父類去創建bean(superinovke()),如果不一樣,則會調用自己的邏輯去創建bean,就是getBean)。

Spring AOP 就是基於動態代理的,如果要代理的對象,實現了某個接口,那麼Spring AOP會使用JDK Proxy,去創建代理對象,而對於沒有實現接口的對象,就無法使用 JDK Proxy 去進行代理了,這時候Spring AOP會使用Cglib ,這時候Spring AOP會使用 Cglib 生成一個被代理對象的子類來作爲代理。

  •        策略模式,spring源碼中多次使用到了這個模式,例如:在spring完成屬性注入的時候,去遍歷所有的bean的後置處理器BeanPostProcessor,根據不同的策略完成不同的註解解析。  BeanPostProcessor的後置處理器的實現類分別執行不同的策略,CommonAnnotationBeanPostProcessor 主要處理@Resource註解的,AutowiredAnnotationBeanPostProcessor主要處理@Autowired註解 等等。

5.5、spring中有哪些不能被代理的bean

5.6、FactoryBean和BeanFactory的區別?

BeanFactory 是Bean 工廠是工廠模式的一個實現,提供了控制反轉功能,用來把應用的配置和依賴從正真的應用代碼中分離。常用的 BeanFactory 實現有 DefaultListableBeanFactory 、 XmlBeanFactory 、 ApplicationContext 等。
XMLBeanFactory,最常用的就是 org.springframework.beans.factory.xml.XmlBeanFactory ,它根據 XML 文件中的定義加載 beans。該容器從 XML 文件讀取配置元數據並用它去創建一個完全配置的系統或應用。

FactoryBean是spring中提供的一個接口,可以通過實現它,重寫getObject方法來返回真正的對象,而不是FactoryBean本身,如果要獲取FactoryBean對象,請在id前面加一個&符號來獲取。

5.7、如何把自己自定義的對象放到spring容器中

  • 實現FactoryBean ,重寫getObject方法,使用FactoryBean主要是因爲項目總引入了第三方jar包,或者擴展第三方而言的。
  • 註解@Bean,是程序員爲了進行零配置這麼寫。
  • 註冊一個bean,這種寫法比較雞肋,例如:

5.8、爲什麼Appconfig類是通過register(Appconfig.class);手動put到map當中呢?爲什麼不是掃描出來的呢?

因爲他無法掃描自己,一般類是spring通過解析Appconfig上的@ComponentScan註解然後被掃描到,所以無法掃描自己,

因此在源碼中,當我們啓動spring時通過下面這個方法,纔會將AppConfig註冊到spring中,才能解析這個配置類上面的註解,從而掃描

ApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);

5.9、爲什麼spring當中默認支持循環依賴?或者spring在哪裏體現了默認支持循環依賴?

具體解析流程參見博客:https://blog.csdn.net/java_lyvee/article/details/101793774

總結:首先spring在單例的(非構造方法注入的情況下)情況下是默認支持循環引用的;在不做任何配置的情況下,兩個bean相互依賴是能初始化成功的;spring源碼中在創建bean的時候先創建這個bean的對象,創建對象完成之後通過判斷容器對象的allowCircularReferences屬性決定是否允許緩存這個臨時對象,如果能被緩存成功則通過緩存提前暴露這個臨時對象來完成循環依賴;而這個屬性默認爲true,所以說spring默認支持循環依賴的,但是這個屬性spring提供了api讓程序員來修改,所以spring也提供了關閉循環引用的功能;再就是spring完成這個臨時對象的生命週期的過程中當執行到注入屬性或者自動裝配的週期時候會通過getSingleton方法去得到需要注入的b對象;而b對象這個時候肯定不存在故而會創建b對象創建b對象成功後繼續b對象的生命週期,當執行到b對象的自動注入週期時候會要求注入a對象;調用getSingleton;從map緩存中得到a的臨時對象(因爲這個時候a在set集合中;a在進入第二個getSingleton方法的時候會將a添加到一個set集合中,標誌a正在創建,這個set集合非常有用),而且獲取的時候也會判斷是否允許循環引用,但是判斷的這個值是通過參數傳進來的,也就是spring內部調用的,spring源碼當中寫死了爲true,故而如果需要擴展spring、或者對spring二次開發的的時候程序員可以自定義這個值來實現自己的功能;不管放到緩存還是從緩存中取出這個臨時都需要判斷;而這兩次判斷spring源碼當中都是默認爲true;這裏也能再次說明spring默認是支持循環引用的;

然後面試中可以在說說兩次調用getSingleton的意義,正在創建的那個set集合有什麼用;最後在說說你在看spring循環引用的時候得出的aop實例化過程的新發現;就比較完美了。

兩次調用getSingleton的意義?

第一次調用getSingleton,是從單例池中獲取這個bean,第一次一般單例池中不存在,第二次調用getSingleton,bean真正實例化和初始化就是在這裏完成的。

正在創建的那個set集合有什麼用?

第一次創建a,a在進入第二個getSingleton方法之後,會在方法中將a添加到一個set集合中,標誌a正在創建,這個標誌非常有用,以爲當對象b第一次創建對象時,進行屬性注入的時候,會注入a對象,就會getBean(a),然後進入第一個getSingleton中 ,這個時候就會判斷當singletonObject單例池中不存在這個a對象,並且a正在創建這個標誌成立,纔會去獲取a的bean,如何獲取的?首先從看第三個緩存map中有沒有,沒有的話就去第二個singletonFactory工廠緩存中找,找到了就放到第三個緩存中,移除第二個工廠緩存。

spring循環引用的時候得出的aop實例化過程的新發現?

在創建bean的過程中,先會進行屬性注入,注入後會通過調用initializeBean方法初始化bean,這個方法中通過applyBeanPostProcessorsBeforeInitialization會先處理spring生命週期的回調,先執行加了@PostContrustot 註解的方法,再執行xml配置的init方法,最後執行applyBeanPostProcessorsAfterInitialization方法進行aop代理(解析切面,創建代理)

如何關閉循環依賴呢?

可已通過兩種方式,第一種,使用spring提供的api:

public class ZluTest {
	public static void main(String[] args) {
		//初始化容器
		AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext();
		DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
		//關閉循環依賴
		beanFactory.setAllowCircularReferences(false);
		context.register(AppConfig.class);
		context.refresh();
}

第二種,更改源碼,重寫getSingleton(beanName,false)方法,將裏面的allowEarlyReference置爲false,能夠關閉循環依賴,spring默認是開啓的,源碼如下: 

public Object getSingleton(String beanName) {
		//重點,一定要記住這裏傳的是一個true,表示允許循環依賴
		return getSingleton(beanName, true);
	}

或者也可以通過下面這種方式:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
    //關閉循環依賴
    setAllowCircularReferences(false);
    register(annotatedClasses);
    refresh();
}

5.10、spring事務不生效有哪些原因

5.11、推斷構造方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章