Spring對註解(Annotation)處理源碼分析1——掃描和讀取Bean定義

1.Spring2.0之後的版本中,Spring也引入了基於註解(Annotation)方式的配置,註解(Annotation)JDK1.5中引入的一個新特性,用於簡化Bean的配置,某些場合能夠取代XML配置文件。開發人員對註解(Annotation)的態度也是蘿蔔青菜各有所愛,我的認爲註解能夠大大簡化配置,提升開發速度,同時也不能徹底取代XML配置方式,XML 方式更加靈活,而且發展的相對成熟,這種配置方式爲大多數 Spring 開發者熟悉;註解方式使用起來很是簡潔,可是尚處於發展階段,XML配置文件和註解(Annotation)能夠相互配合使用。java

應某些人員的要求,本文章就分析Spring對註解(Annotation)的解析過程,若是你對註解還不熟悉,請參考:http://blog.csdn.net/chjttony/archive/2010/11/22/6026079.aspx8之後的對於註解的簡單介紹和前一篇博客中轉載的對Spring註解基本知識介紹:http://blog.csdn.net/chjttony/archive/2011/03/29/6286144.aspx.web

Spring IoC容器對於類級別的註解和類內部的註解分如下兩種處理策略:編程

(1).類級別的註解:如@Component@Repository@Controller@Service以及JavaEE6@ManagedBean@Named註解,都是添加在類上面的類級別註解,Spring容器根據註解的過濾規則掃描讀取註解Bean定義類,並將其註冊到Spring IoC容器中。數據結構

(2).類內部的註解:如@Autowire@Value@Resource以及EJBWebService相關的註解等,都是添加在類內部的字段或者方法上的類內部註解,Spring IoC容器經過Bean後置註解處理器解析Bean內部的註解。app

下面將根據這兩種處理策略,分別分析Spring處理註解相關的源碼。ide

2.AnnotationConfigApplicationContext對註解Bean初始化:函數

Spring中,管理註解Bean定義的容器有兩個:AnnotationConfigApplicationContext AnnotationConfigWebApplicationContex。這兩個類是專門處理Spring註解方式配置的容器,直接依賴於註解做爲容器配置信息來源的IoC容器。 AnnotationConfigWebApplicationContextAnnotationConfigApplicationContextweb版本,二者的用法以及對註解的處理方式幾乎沒有什麼差異,所以本文將以AnnotationConfigApplicationContext爲例進行講解。源碼分析

 

AnnotationConfigApplicationContext的源碼以下:post

public class AnnotationConfigApplicationContext extends GenericApplicationContext {
	//建立一個讀取註解的Bean定義讀取器,並將其設置到容器中
	private final AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(this);
	//建立一個掃描指定類路徑中註解Bean定義的掃描器,並將其設置到容器中
	private final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this);
//默認構造函數,初始化一個空容器,容器不包含任何 Bean 信息,須要在稍後經過調用其register() //方法註冊配置類,並調用refresh()方法刷新容器,觸發容器對註解Bean的載入、解析和註冊過程
	public AnnotationConfigApplicationContext() {
	}
	//最經常使用的構造函數,經過將涉及到的配置類傳遞給該構造函數,以實現將相應配置類中的Bean
//自動註冊到容器中
	public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		register(annotatedClasses);
		refresh();
	}
//該構造函數會自動掃描以給定的包及其子包下的全部類,並自動識別全部的Spring Bean,將其
//註冊到容器中
	public AnnotationConfigApplicationContext(String... basePackages) {
		scan(basePackages);
		refresh();
	}
	//爲容器的註解Bean讀取器和註解Bean掃描器設置Bean名稱產生器
	public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
		this.reader.setBeanNameGenerator(beanNameGenerator);
		this.scanner.setBeanNameGenerator(beanNameGenerator);
	}
	//爲容器的註解Bean讀取器和註解Bean掃描器設置做用範圍元信息解析器
	public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
		this.reader.setScopeMetadataResolver(scopeMetadataResolver);
		this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
	}
	//爲容器註冊一個要被處理的註解Bean,新註冊的Bean,必須手動調用容器的
//refresh()方法刷新容器,觸發容器對新註冊的Bean的處理
	public void register(Class<?>... annotatedClasses) {
		this.reader.register(annotatedClasses);
	}
	//掃描指定包路徑及其子包下的註解類,爲了使新添加的類被處理,必須手動調用
	//refresh()方法刷新容器
	public void scan(String... basePackages) {
		this.scanner.scan(basePackages);
	}
}

  

 

public class AnnotationConfigApplicationContext extends GenericApplicationContext { 

//建立一個讀取註解的Bean定義讀取器,並將其設置到容器中 private final AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(this); //建立一個掃描指定類路徑中註解Bean定義的掃描器,並將其設置到容器中 
private final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this); 
//默認構造函數,初始化一個空容器,容器不包含任何 Bean 信息,須要在稍後經過調用其register() 
//方法註冊配置類,並調用refresh()方法刷新容器,觸發容器對註解Bean的載入、解析和註冊過程 
public AnnotationConfigApplicationContext() { } 
//最經常使用的構造函數,經過將涉及到的配置類傳遞給該構造函數,以實現將相應配置類中的Bean 
//自動註冊到容器中 
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { register(annotatedClasses); refresh(); } 
//該構造函數會自動掃描以給定的包及其子包下的全部類,並自動識別全部的Spring Bean,將其 
//註冊到容器中 public AnnotationConfigApplicationContext(String... basePackages) { scan(basePackages); refresh(); } 
//爲容器的註解Bean讀取器和註解Bean掃描器設置Bean名稱產生器 public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { this.reader.setBeanNameGenerator(beanNameGenerator); this.scanner.setBeanNameGenerator(beanNameGenerator); } 
//爲容器的註解Bean讀取器和註解Bean掃描器設置做用範圍元信息解析器 public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) { 
this.reader.setScopeMetadataResolver(scopeMetadataResolver); this.scanner.setScopeMetadataResolver(scopeMetadataResolver); 
} 
//爲容器註冊一個要被處理的註解Bean,新註冊的Bean,必須手動調用容器的 
//refresh()方法刷新容器,觸發容器對新註冊的Bean的處理 public void register(Class<?>... annotatedClasses) { 
this.reader.register(annotatedClasses); 
} 
//掃描指定包路徑及其子包下的註解類,爲了使新添加的類被處理,必須手動調用 
//refresh()方法刷新容器 public void scan(String... basePackages) { this.scanner.scan(basePackages); } }

經過對AnnotationConfigApplicationContext的源碼分析,咱們瞭解到Spring對註解的處理分爲兩種方式:this

(1).直接將註解Bean註冊到容器中:

能夠在初始化容器時註冊;也能夠在容器建立以後手動調用註冊方法向容器註冊,而後經過手動刷新容器,使得容器對註冊的註解Bean進行處理。

(2).經過掃描指定的包及其子包下的全部類:

在初始化註解容器時指定要自動掃描的路徑,若是容器建立之後向給定路徑動態添加了註解Bean,則須要手動調用容器掃描的方法,而後手動刷新容器,使得容器對所註冊的Bean進行處理。

接下來,將會對兩種處理方式詳細分析其實現過程。

3.AnnotationConfigApplicationContext註冊註解Bean

當建立註解處理容器時,若是傳入的初始參數是具體的註解Bean定義類時,註解容器讀取並註冊。

 

(1).AnnotationConfigApplicationContext經過調用註解Bean定義讀取器AnnotatedBeanDefinitionReaderregister方法向容器註冊指定的註解Bean,註解Bean定義讀取器向容器註冊註解Bean的源碼以下:

//註冊多個註解Bean定義類
public void register(Class<?>... annotatedClasses) {
		for (Class<?> annotatedClass : annotatedClasses) {
			registerBean(annotatedClass);
		}
	}
	//註冊一個註解Bean定義類
	public void registerBean(Class<?> annotatedClass) {
		registerBean(annotatedClass, null, (Class<? extends Annotation>[]) null);
	}
	//Bean定義讀取器註冊註解Bean定義的入口方法
	public void registerBean(Class<?> annotatedClass, Class<? extends Annotation>... qualifiers) {
		registerBean(annotatedClass, null, qualifiers);
	}
	//Bean定義讀取器向容器註冊註解Bean定義類
	public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
		//根據指定的註解Bean定義類,建立Spring容器中對註解Bean的封裝的數據結構
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
		//解析註解Bean定義的做用域,若@Scope("prototype"),則Bean爲原型類型;
		//若@Scope("singleton"),則Bean爲單態類型
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		//爲註解Bean定義設置做用域
		abd.setScope(scopeMetadata.getScopeName());
		//爲註解Bean定義生成Bean名稱
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
		//處理註解Bean定義中的通用註解
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		//若是在向容器註冊註解Bean定義時,使用了額外的限定符註解,則解析限定符註解。
	//主要是配置的關於autowiring自動依賴注入裝配的限定條件,即@Qualifier
//註解,Spring自動依賴注入裝配默認是按類型裝配,若是使用@Qualifier則按名稱
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
//若是配置了@Primary註解,設置該Bean爲autowiring自動依賴注入裝//配時的首選
				if (Primary.class.equals(qualifier)) {
					abd.setPrimary(true);
				}
				//若是配置了@Lazy註解,則設置該Bean爲非延遲初始化,若是沒有配置,
				//則該Bean爲預實例化
				else if (Lazy.class.equals(qualifier)) {
					abd.setLazyInit(true);
				}
				//若是使用了除@Primary和@Lazy之外的其餘註解,則爲該Bean添加一
//個autowiring自動依賴注入裝配限定符,該Bean在進autowiring
//自動依賴注入裝配時,根據名稱裝配限定符指定的Bean
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		//建立一個指定Bean名稱的Bean定義對象,封裝註解Bean定義類數據
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		//根據註解Bean定義類中配置的做用域,建立相應的代理對象
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	//向IoC容器註冊註解Bean類定義對象	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

//註冊多個註解Bean定義類 public void register(Class<?>... annotatedClasses) { for (Class<?> annotatedClass : annotatedClasses) { registerBean(annotatedClass); } } //註冊一個註解Bean定義類 public void registerBean(Class<?> annotatedClass) { registerBean(annotatedClass, null, (Class<? extends Annotation>[]) null); } //Bean定義讀取器註冊註解Bean定義的入口方法 public void registerBean(Class<?> annotatedClass, Class<? extends Annotation>... qualifiers) { registerBean(annotatedClass, null, qualifiers); } //Bean定義讀取器向容器註冊註解Bean定義類 public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) { //根據指定的註解Bean定義類,建立Spring容器中對註解Bean的封裝的數據結構 AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); //解析註解Bean定義的做用域,若@Scope("prototype"),則Bean爲原型類型; //若@Scope("singleton"),則Bean爲單態類型 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); //爲註解Bean定義設置做用域 abd.setScope(scopeMetadata.getScopeName()); //爲註解Bean定義生成Bean名稱 String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); //處理註解Bean定義中的通用註解 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); //若是在向容器註冊註解Bean定義時,使用了額外的限定符註解,則解析限定符註解。 //主要是配置的關於autowiring自動依賴注入裝配的限定條件,即@Qualifier //註解,Spring自動依賴注入裝配默認是按類型裝配,若是使用@Qualifier則按名稱 if (qualifiers != null) { for (Class<? extends Annotation> qualifier : qualifiers) { //若是配置了@Primary註解,設置該Bean爲autowiring自動依賴注入裝//配時的首選 if (Primary.class.equals(qualifier)) { abd.setPrimary(true); } //若是配置了@Lazy註解,則設置該Bean爲非延遲初始化,若是沒有配置, //則該Bean爲預實例化 else if (Lazy.class.equals(qualifier)) { abd.setLazyInit(true); } //若是使用了除@Primary和@Lazy之外的其餘註解,則爲該Bean添加一 //個autowiring自動依賴注入裝配限定符,該Bean在進autowiring //自動依賴注入裝配時,根據名稱裝配限定符指定的Bean else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } //建立一個指定Bean名稱的Bean定義對象,封裝註解Bean定義類數據 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); //根據註解Bean定義類中配置的做用域,建立相應的代理對象 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); //向IoC容器註冊註解Bean類定義對象 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); } 

 

從上面的源碼咱們能夠看出,註冊註解Bean定義類的基本步驟:

a,須要使用註解元數據解析器解析註解Bean中關於做用域的配置。

b,使用AnnotationConfigUtilsprocessCommonDefinitionAnnotations方法處理註解Bean定義類中通用的註解。

c,使用AnnotationConfigUtilsapplyScopedProxyMode方法建立對於做用域的代理對象。

d,經過BeanDefinitionReaderUtils向容器註冊Bean

下面咱們繼續分析這3步的具體實現過程

(2).AnnotationScopeMetadataResolver解析做用域元數據:

AnnotationScopeMetadataResolver經過processCommonDefinitionAnnotations方法解析註解Bean定義類的做用域元信息,即判斷註冊的Bean是原生類型(prototype)仍是單態(singleton)類型,其源碼以下:

//解析註解Bean定義類中的做用域元信息
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
		ScopeMetadata metadata = new ScopeMetadata();
		if (definition instanceof AnnotatedBeanDefinition) {
			AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
			//從註解Bean定義類的屬性中查找屬性爲」Scope」的值,即@Scope註解的值
			// annDef.getMetadata().getAnnotationAttributes方法將Bean
//中全部的註解和註解的值存放在一個map集合中
			Map<String, Object> attributes =
	annDef.getMetadata().getAnnotationAttributes(this.scopeAnnotationType.getName());
			//將獲取到的@Scope註解的值設置到要返回的對象中
			if (attributes != null) {
				metadata.setScopeName((String) attributes.get("value"));
				//獲取@Scope註解中的proxyMode屬性值,在建立代理對象時會用到
				ScopedProxyMode proxyMode = (ScopedProxyMode) attributes.get("proxyMode");
				//若是@Scope的proxyMode屬性值爲null、DEFAULT或者NO
				if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
					//設置proxyMode爲NO
					proxyMode = this.defaultProxyMode;
				}
				//爲返回的元數據設置proxyMode
				metadata.setScopedProxyMode(proxyMode);
			}
		}
		//返回解析的做用域元信息對象
		return metadata;
	}

//解析註解Bean定義類中的做用域元信息 public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) { ScopeMetadata metadata = new ScopeMetadata(); if (definition instanceof AnnotatedBeanDefinition) { AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition; //從註解Bean定義類的屬性中查找屬性爲」Scope」的值,即@Scope註解的值 // annDef.getMetadata().getAnnotationAttributes方法將Bean //中全部的註解和註解的值存放在一個map集合中 Map<String, Object> attributes = annDef.getMetadata().getAnnotationAttributes(this.scopeAnnotationType.getName()); //將獲取到的@Scope註解的值設置到要返回的對象中 if (attributes != null) { metadata.setScopeName((String) attributes.get("value")); //獲取@Scope註解中的proxyMode屬性值,在建立代理對象時會用到 ScopedProxyMode proxyMode = (ScopedProxyMode) attributes.get("proxyMode"); //若是@Scope的proxyMode屬性值爲null、DEFAULT或者NO if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) { //設置proxyMode爲NO proxyMode = this.defaultProxyMode; } //爲返回的元數據設置proxyMode metadata.setScopedProxyMode(proxyMode); } } //返回解析的做用域元信息對象 return metadata; } 

 

上述代碼中的annDef.getMetadata().getAnnotationAttributes方法就是獲取對象中指定類型的註解的值。

(3).AnnotationConfigUtils處理註解Bean定義類中的通用註解:

AnnotationConfigUtils類的processCommonDefinitionAnnotations在向容器註冊Bean以前,首先對註解Bean定義類中的通用Spring註解進行處理,源碼以下:

 

//處理Bean定義中通用註解
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
//若是Bean定義中有@Primary註解,則爲該Bean設置爲autowiring自動依賴注入//裝配的首選對象
		if (abd.getMetadata().isAnnotated(Primary.class.getName())) {
			abd.setPrimary(true);
		}
		//若是Bean定義中有@Lazy註解,則將該Bean預實例化屬性設置爲@lazy註解的值
		if (abd.getMetadata().isAnnotated(Lazy.class.getName())) {
			Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value");
			abd.setLazyInit(value);
		}
		//若是Bean定義中有@ DependsOn註解,則爲該Bean設置所依賴的Bean名稱,
//容器將確保在實例化該Bean以前首先實例化所依賴的Bean
 if (abd.getMetadata().isAnnotated(DependsOn.class.getName())) {
			String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value");
			abd.setDependsOn(value);
		}
	}

//處理Bean定義中通用註解 static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) { //若是Bean定義中有@Primary註解,則爲該Bean設置爲autowiring自動依賴注入//裝配的首選對象 if (abd.getMetadata().isAnnotated(Primary.class.getName())) { abd.setPrimary(true); } //若是Bean定義中有@Lazy註解,則將該Bean預實例化屬性設置爲@lazy註解的值 if (abd.getMetadata().isAnnotated(Lazy.class.getName())) { Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value"); abd.setLazyInit(value); } //若是Bean定義中有@ DependsOn註解,則爲該Bean設置所依賴的Bean名稱, //容器將確保在實例化該Bean以前首先實例化所依賴的Bean if (abd.getMetadata().isAnnotated(DependsOn.class.getName())) { String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value"); abd.setDependsOn(value); } } 

 

(4).AnnotationConfigUtils根據註解Bean定義類中配置的做用域爲其應用相應的代理策略:

AnnotationConfigUtils類的applyScopedProxyMode方法根據註解Bean定義類中配置的做用域@Scope註解的值,爲Bean定義應用相應的代理模式,主要是在Spring面向切面編程(AOP)中使用。源碼以下

 

//根據做用域爲Bean應用引用的代碼模式
static BeanDefinitionHolder applyScopedProxyMode(
			ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
		//獲取註解Bean定義類中@Scope註解的proxyMode屬性值
		ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
		//若是配置的@Scope註解的proxyMode屬性值爲NO,則不該用代理模式
		if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
			return definition;
		}
//獲取配置的@Scope註解的proxyMode屬性值,若是爲TARGET_CLASS,則返
//回true,若是爲INTERFACES,則返回false
		boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
		//爲註冊的Bean建立相應模式的代理對象
		return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
	}

//根據做用域爲Bean應用引用的代碼模式 static BeanDefinitionHolder applyScopedProxyMode( ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) { //獲取註解Bean定義類中@Scope註解的proxyMode屬性值 ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode(); //若是配置的@Scope註解的proxyMode屬性值爲NO,則不該用代理模式 if (scopedProxyMode.equals(ScopedProxyMode.NO)) { return definition; } //獲取配置的@Scope註解的proxyMode屬性值,若是爲TARGET_CLASS,則返 //回true,若是爲INTERFACES,則返回false boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS); //爲註冊的Bean建立相應模式的代理對象 return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass); }  

 

這段爲Bean引用建立相應模式的代理,若是在Spring面向切面編程(AOP)中涉及到再詳細分析,這裏不作深刻的分析。

(5).BeanDefinitionReaderUtils向容器註冊Bean

BeanDefinitionReaderUtils向容器註冊載入的Bean咱們在第4篇博客中已經分析過主要是校驗Bean定義而後將Bean添加到容器中一個管理Bean定義的HashMap中,這裏就不作分析。

4.AnnotationConfigApplicationContext掃描指定包及其子包下的註解Bean

當建立註解處理容器時,若是傳入的初始參數是註解Bean定義類所在的包時,註解容器將掃描給定的包及其子包,將掃描到的註解Bean定義載入並註冊。

 

(1).Spring中經常使用的註解:

 

a.Component註解:

  1. @Target(ElementType.TYPE)  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. @Documented  
  4. public @interface Component {  
  5.     String value() default "";  
  6. }  
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Component { String value() default ""; } 

 

b.Service註解:

  1. @Target({ElementType.TYPE})  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. @Documented  
  4. @Component  
  5. public @interface Service {  
  6.     String value() default "";  
  7. }  
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Service { String value() default ""; } 

 

c.Controller註解:

  1. @Target({ElementType.TYPE})  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. @Documented  
  4. @Component  
  5. public @interface Controller {  
  6.     String value() default "";  
  7. }  
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { String value() default ""; }

 

d.Repository註解:

 

  1. @Target({ElementType.TYPE})  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. @Documented  
  4. @Component  
  5. public @interface Repository {  
  6.     String value() default "";  
  7. }  
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Repository { String value() default ""; } 

 

經過分析Spring4個經常使用的註解源碼,咱們看到:@Service@Controller@Repository註解都添加了一個@Component註解,所以他們都屬於@Component

註解。

(2).ClassPathBeanDefinitionScanner掃描給定的包及其子包:

AnnotationConfigApplicationContext經過調用類路徑Bean定義掃描器ClassPathBeanDefinitionScanner掃描給定包及其子包下的全部類,主要源碼以下:

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
//建立一個類路徑Bean定義掃描器
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
		this(registry, true);
	}
//爲容器建立一個類路徑Bean定義掃描器,並指定是否使用默認的掃描過濾規則。
//即Spring默認掃描配置:@Component、@Repository、@Service、@Controller
//註解的Bean,同時也支持JavaEE6的@ManagedBean和JSR-330的@Named註解
	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
//調用父類ClassPathScanningCandidateComponentProvider構造方法設置過濾規則
		super(useDefaultFilters);
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		//爲容器設置加載Bean定義的註冊器
		this.registry = registry;
		//若是註冊器是資源加載器,則爲容器設置資源加載器
		if (this.registry instanceof ResourceLoader) {
			setResourceLoader((ResourceLoader) this.registry);
		}
	}
//調用類路徑Bean定義掃描器入口方法
public int scan(String... basePackages) {
		//獲取容器中已經註冊的Bean個數
		int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
		//啓動掃描器掃描給定包
		doScan(basePackages);
		//註冊註解配置(Annotation config)處理器
		if (this.includeAnnotationConfig) {
	AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
		}
		//返回註冊的Bean個數
		return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
	}
//類路徑Bean定義掃描器掃描給定包及其子包
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		//建立一個集合,存放掃描到Bean定義的封裝類
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
		//遍歷掃描全部給定的包
		for (String basePackage : basePackages) {
			//調用父類ClassPathScanningCandidateComponentProvider的方法
//掃描給定類路徑,獲取符合條件的Bean定義
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			//遍歷掃描到的Bean
			for (BeanDefinition candidate : candidates) {
				//獲取Bean定義類中@Scope註解的值,即獲取Bean的做用域
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				//爲Bean設置註解配置的做用域
				candidate.setScope(scopeMetadata.getScopeName());
				//爲Bean生成名稱
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			//若是掃描到的Bean不是Spring的註解Bean,則爲Bean設置默認值,
//設置Bean的自動依賴注入裝配屬性等
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				//若是掃描到的Bean是Spring的註解Bean,則處理其通用的Spring註解
				if (candidate instanceof AnnotatedBeanDefinition) {
	//處理註解Bean中通用的註解,在分析註解Bean定義類讀取器時已經分析過	AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
			//根據Bean名稱檢查指定的Bean是否須要在容器中註冊,或者在容器中衝突
if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					//根據註解中配置的做用域,爲Bean應用相應的代理模式
					definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					//向容器註冊掃描到的Bean
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}						
		}
		return beanDefinitions;
	}
……
}

  
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider { //建立一個類路徑Bean定義掃描器 public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) { this(registry, true); } //爲容器建立一個類路徑Bean定義掃描器,並指定是否使用默認的掃描過濾規則。 //即Spring默認掃描配置:@Component、@Repository、@Service、@Controller //註解的Bean,同時也支持JavaEE6的@ManagedBean和JSR-330的@Named註解 public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) { //調用父類ClassPathScanningCandidateComponentProvider構造方法設置過濾規則 super(useDefaultFilters); Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); //爲容器設置加載Bean定義的註冊器 this.registry = registry; //若是註冊器是資源加載器,則爲容器設置資源加載器 if (this.registry instanceof ResourceLoader) { setResourceLoader((ResourceLoader) this.registry); } } //調用類路徑Bean定義掃描器入口方法 public int scan(String... basePackages) { //獲取容器中已經註冊的Bean個數 int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); //啓動掃描器掃描給定包 doScan(basePackages); //註冊註解配置(Annotation config)處理器 if (this.includeAnnotationConfig) { AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } //返回註冊的Bean個數 return this.registry.getBeanDefinitionCount() - beanCountAtScanStart; } //類路徑Bean定義掃描器掃描給定包及其子包 protected Set<BeanDefinitionHolder> doScan(String... basePackages) { //建立一個集合,存放掃描到Bean定義的封裝類 Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>(); //遍歷掃描全部給定的包 for (String basePackage : basePackages) { //調用父類ClassPathScanningCandidateComponentProvider的方法 //掃描給定類路徑,獲取符合條件的Bean定義 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); //遍歷掃描到的Bean for (BeanDefinition candidate : candidates) { //獲取Bean定義類中@Scope註解的值,即獲取Bean的做用域 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); //爲Bean設置註解配置的做用域 candidate.setScope(scopeMetadata.getScopeName()); //爲Bean生成名稱 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); //若是掃描到的Bean不是Spring的註解Bean,則爲Bean設置默認值, //設置Bean的自動依賴注入裝配屬性等 if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } //若是掃描到的Bean是Spring的註解Bean,則處理其通用的Spring註解 if (candidate instanceof AnnotatedBeanDefinition) { //處理註解Bean中通用的註解,在分析註解Bean定義類讀取器時已經分析過 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } //根據Bean名稱檢查指定的Bean是否須要在容器中註冊,或者在容器中衝突 if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); //根據註解中配置的做用域,爲Bean應用相應的代理模式 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); //向容器註冊掃描到的Bean registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; } …… } 

 

類路徑Bean定義掃描器ClassPathBeanDefinitionScanner主要經過findCandidateComponents方法調用其父類ClassPathScanningCandidateComponentProvider類來掃描獲取給定包及其子包下的類。

(3).ClassPathScanningCandidateComponentProvider掃描給定包及其子包的類:

ClassPathScanningCandidateComponentProvider類的findCandidateComponents方法具體實現掃描給定類路徑包的功能,主要源碼以下

 

public class ClassPathScanningCandidateComponentProvider implements ResourceLoaderAware {
//保存過濾規則要包含的註解,即Spring默認的@Component、@Repository、@Service、//@Controller註解的Bean,以及JavaEE6的@ManagedBean和JSR-330的@Named註解
private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>();
//保存過濾規則要排除的註解
private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();
//構造方法,該方法在子類ClassPathBeanDefinitionScanner的構造方法中被調用
public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters) {
		//若是使用Spring默認的過濾規則,則向容器註冊過濾規則
		if (useDefaultFilters) {
			registerDefaultFilters();
		}
	}
//向容器註冊過濾規則
protected void registerDefaultFilters() {
//向要包含的過濾規則中添加@Component註解類,注意Spring中@Repository
//@Service和@Controller都是Component,由於這些註解都添加了@Component註解
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		//獲取當前類的類加載器
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
		try {
			//向要包含的過濾規則添加JavaEE6的@ManagedBean註解
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
			logger.info("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
		}
		try {
			//向要包含的過濾規則添加@Named註解
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
			logger.info("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}
//掃描給定類路徑的包
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		//建立存儲掃描到的類的集合
		Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
		try {
			//解析給定的包路徑,this.resourcePattern=」 **/*.class」,
	//ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX=「classpath:」
	//resolveBasePackage方法將包名中的」.」轉換爲文件系統的」/」
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + "/" + this.resourcePattern;
			//將給定的包路徑解析爲Spring資源對象
			Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			//遍歷掃描到的資源
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {
//爲指定資源獲取元數據讀取器,元信息讀取器經過彙編(ASM)讀//取資源元信息
						MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
						//若是掃描到的類符合容器配置的過濾規則
						if (isCandidateComponent(metadataReader)) {
							//經過彙編(ASM)讀取資源字節碼中的Bean定義元信息
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							//設置Bean定義來源於resource
							sbd.setResource(resource);
							//爲元數據元素設置配置資源對象
							sbd.setSource(resource);
							//檢查Bean是不是一個可實例化的對象
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}
//判斷元信息讀取器讀取的類是否符合容器定義的註解過濾規則
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		//若是讀取的類的註解在排除註解過濾規則中,返回false
		for (TypeFilter tf : this.excludeFilters) {
			if (tf.match(metadataReader, this.metadataReaderFactory)) {
				return false;
			}
		}
		//若是讀取的類的註解在包含的註解的過濾規則中,則返回ture
		for (TypeFilter tf : this.includeFilters) {
			if (tf.match(metadataReader, this.metadataReaderFactory)) {
				return true;
			}
		}
		//若是讀取的類的註解既不在排除規則,也不在包含規則中,則返回false
		return false;
	}
……
}

public class ClassPathScanningCandidateComponentProvider implements ResourceLoaderAware { //保存過濾規則要包含的註解,即Spring默認的@Component、@Repository、@Service、//@Controller註解的Bean,以及JavaEE6的@ManagedBean和JSR-330的@Named註解 private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>(); //保存過濾規則要排除的註解 private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>(); //構造方法,該方法在子類ClassPathBeanDefinitionScanner的構造方法中被調用 public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters) { //若是使用Spring默認的過濾規則,則向容器註冊過濾規則 if (useDefaultFilters) { registerDefaultFilters(); } } //向容器註冊過濾規則 protected void registerDefaultFilters() { //向要包含的過濾規則中添加@Component註解類,注意Spring中@Repository //@Service和@Controller都是Component,由於這些註解都添加了@Component註解 this.includeFilters.add(new AnnotationTypeFilter(Component.class)); //獲取當前類的類加載器 ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); try { //向要包含的過濾規則添加JavaEE6的@ManagedBean註解 this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false)); logger.info("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip. } try { //向要包含的過濾規則添加@Named註解 this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false)); logger.info("JSR-330 'javax.inject.Named' annotation found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } } //掃描給定類路徑的包 public Set<BeanDefinition> findCandidateComponents(String basePackage) { //建立存儲掃描到的類的集合 Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>(); try { //解析給定的包路徑,this.resourcePattern=」 **/*.class」, //ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX=「classpath:」 //resolveBasePackage方法將包名中的」.」轉換爲文件系統的」/」 String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + "/" + this.resourcePattern; //將給定的包路徑解析爲Spring資源對象 Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath); boolean traceEnabled = logger.isTraceEnabled(); boolean debugEnabled = logger.isDebugEnabled(); //遍歷掃描到的資源 for (Resource resource : resources) { if (traceEnabled) { logger.trace("Scanning " + resource); } if (resource.isReadable()) { try { //爲指定資源獲取元數據讀取器,元信息讀取器經過彙編(ASM)讀//取資源元信息 MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); //若是掃描到的類符合容器配置的過濾規則 if (isCandidateComponent(metadataReader)) { //經過彙編(ASM)讀取資源字節碼中的Bean定義元信息 ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); //設置Bean定義來源於resource sbd.setResource(resource); //爲元數據元素設置配置資源對象 sbd.setSource(resource); //檢查Bean是不是一個可實例化的對象 if (isCandidateComponent(sbd)) { if (debugEnabled) { logger.debug("Identified candidate component class: " + resource); } candidates.add(sbd); } else { if (debugEnabled) { logger.debug("Ignored because not a concrete top-level class: " + resource); } } } else { if (traceEnabled) { logger.trace("Ignored because not matching any filter: " + resource); } } } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to read candidate component class: " + resource, ex); } } else { if (traceEnabled) { logger.trace("Ignored because not readable: " + resource); } } } } catch (IOException ex) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); } return candidates; } //判斷元信息讀取器讀取的類是否符合容器定義的註解過濾規則 protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { //若是讀取的類的註解在排除註解過濾規則中,返回false for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return false; } } //若是讀取的類的註解在包含的註解的過濾規則中,則返回ture for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return true; } } //若是讀取的類的註解既不在排除規則,也不在包含規則中,則返回false return false; } …… } 

 

5.AnnotationConfigWebApplicationContext載入註解Bean定義:

AnnotationConfigWebApplicationContextAnnotationConfigApplicationContextWeb版,它們對於註解Bean的註冊和掃描是基本相同的,可是AnnotationConfigWebApplicationContext對註解Bean定義的載入稍有不一樣,AnnotationConfigWebApplicationContext注入註解Bean定義源碼以下:

//載入註解Bean定義資源
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
		//爲容器設置註解Bean定義讀取器
		AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(beanFactory);
		//爲容器設置類路徑Bean定義掃描器
		ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
		//獲取容器的Bean名稱生成器
		BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
		//獲取容器的做用域元信息解析器
		ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
		//爲註解Bean定義讀取器和類路徑掃描器設置Bean名稱生成器
		if (beanNameGenerator != null) {
			reader.setBeanNameGenerator(beanNameGenerator);
			scanner.setBeanNameGenerator(beanNameGenerator);
		}
//爲註解Bean定義讀取器和類路徑掃描器設置做用域元信息解析器
		if (scopeMetadataResolver != null) {
			reader.setScopeMetadataResolver(scopeMetadataResolver);
			scanner.setScopeMetadataResolver(scopeMetadataResolver);
		}
		//獲取容器定義的Bean定義資源路徑
		String[] configLocations = getConfigLocations();
		//若是定位的Bean定義資源路徑不爲空
		if (configLocations != null) {
			for (String configLocation : configLocations) {
				try {
					//使用當前容器的類加載器加載定位路徑的字節碼類文件
					Class<?> clazz = getClassLoader().loadClass(configLocation);
					if (logger.isInfoEnabled()) {
						logger.info("Successfully resolved class for [" + configLocation + "]");
					}
					reader.register(clazz);
				}
				catch (ClassNotFoundException ex) {
					if (logger.isDebugEnabled()) {
						logger.debug("Could not load class for config location [" + configLocation +
								"] - trying package scan. " + ex);
					}
					//若是容器類加載器加載定義路徑的Bean定義資源失敗,則啓用
//容器類路徑掃描器掃描給定路徑包及其子包中的類
					int count = scanner.scan(configLocation);
					if (logger.isInfoEnabled()) {
						if (count == 0) {
							logger.info("No annotated classes found for specified class/package [" + configLocation + "]");
						}
						else {
							logger.info("Found " + count + " annotated classes in package [" + configLocation + "]");
						}
					}
				}
			}
		}
	}
 
相關文章
相關標籤/搜索