Spring原始碼分析(十五)Spring中常用註解使用以及原始碼分析
從Java5.0開始,Java開始支援註解。Spring做為Java生態中的領軍框架,從2.5版本後也開始支援註解。相比起之前使用xml來配置Spring框架,使用註解提供了更多的控制Spring框架的方式。
現在越來越多的專案也都在使用註解做相關的配置,但Spring的註解非常多,相信很多註解大家都沒有使用過。本文就儘量全面地概括介紹一下Spring中常用的註解。
JAVA註解瞭解一下
[email protected]
此註解用於bean的setter方法上。表示此屬性是必須的,必須在配置階段注入,否則會丟擲BeanInitializationExcepion。
相關程式碼:
RequiredAnnotationBeanPostProcessor
public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
@Override
public PropertyValues postProcessPropertyValues (
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
if (!this.validatedBeanNames.contains(beanName)) {
//如果是是用的工廠方法 例如<bean id ="a" factory-bean="testAnnotFactory" factory-method="getAnnotInstance" />形式;會直接跳過不檢查
//如果配置了 <meta key="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.skipRequiredCheck"
value="true" />則也跳過不檢查
if (!shouldSkip(this.beanFactory, beanName)) {
List<String> invalidProperties = new ArrayList<String>();
for (PropertyDescriptor pd : pds) {
//如果是set方法並且有Require註解,則丟擲異常
if (isRequiredProperty(pd) && !pvs.contains(pd.getName())) {
invalidProperties.add(pd.getName());
}
}
if (!invalidProperties.isEmpty()) {
throw new BeanInitializationException(buildExceptionMessage(invalidProperties, beanName));
}
}
this.validatedBeanNames.add(beanName);
}
return pvs;
}
}
RequiredAnnotationBeanPostProcessor最終是實現了InstantiationAwareBeanPostProcessor介面的postProcessPropertyValues方法;
就是在populateBean()方法裡面被呼叫的
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
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 (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
//所以的屬性準備就緒 進行填充
applyPropertyValues(beanName, mbd, bw, pvs);
}
使用說明:
1. 只能作用於setter方法上面
2. 被@Require修飾了之後,該屬性必須要被設定值
3. 如果該類使用了工廠方式則跳過驗證
關於factory-bean factory-method 瞭解一下
<bean id ="testAnnotFactory" class="src.testannot.TestAnnotFactory"/>
<bean id ="a" factory-bean="testAnnotFactory" factory-method="getAnnotInstance" />
public class TestAnnotFactory {
public TestAnnot getAnnotInstance(){
return new TestAnnot();
}
}
public class TestAnnot {
private String needRequire;
public String getNeedRequire() {
return needRequire;
}
@Required
public void setNeedRequire(String needRequire) {
this.needRequire = needRequire;
}
}
上面的情況下 會跳過驗證
4. 如果配置了屬性skipRequiredCheck也會跳過驗證
<bean class="src.testannot.TestAnnot" >
<meta
key="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.skipRequiredCheck"
value="true" />
</bean>
5 . 配置檔案中要引入下面的後置處理器才會生效
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
[email protected]
在傳統的spring注入方式中,我們對類變數都要求實現get與set的方法。在pring 2.5 引入了 @Autowired 註釋,它可以對類成員變數、方法及建構函式進行標註,完成自動裝配的工作。 通過 @Autowired的使用來消除 set ,get方法。不過在引及@Autowired註釋後,要在spring的配置檔案 applicationContext.xml中加入:如下程式碼
<!-- 該 BeanPostProcessor 將自動對標註 @Autowired 的 Bean 進行注入 -->
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
看看註解的描述
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
@Autowire使用瞭解一下
怎麼使用,點選上面的連結講解的很清楚 ,我們來看下原始碼的實現
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
}
[email protected]
此註解是和@Autowired一起使用的。使用此註解可以讓你對注入的過程有更多的控制。@Qualifier可以被用在單個構造器或者方法的引數上。當上下文有幾個相同型別的bean, 使用@Autowired則無法區分要繫結的bean,此時可以使用@Qualifier來指定名稱。
他們的使用跟@Resource差不多
/*@Autowired
@Qualifier(value = "t2")*/
@Resource(name = "t2")
public TestAnnot testAnnot;
都是根據名稱來注入
[email protected] @Bean
@Configuration標註在類上,相當於把該類作為spring的xml配置檔案中的beans>,作用為:配置spring容器(應用上下文)
@Bean標註在方法上(返回某個例項的方法),等價於spring的xml配置檔案中的bean>,作用為:註冊bean物件
@Configuration註解、@Bean註解以及配置自動掃描、bean作用域
[email protected] @Lazy
@ComponentScan 指定Spring掃描註解的package。如果沒有指定包,那麼預設會掃描此配置類所在的package。
@Lazy 此註解使用在Spring的元件類上。預設的,Spring中Bean的依賴一開始就被建立和配置。如果想要延遲初始化一個bean,那麼可以在此類上使用Lazy註解,表示此bean只有在第一次被使用的時候才會被建立和初始化。此註解也可以使用在被@Configuration註解的類上,表示其中所有被@Bean註解的方法都會延遲初始化。
@Component(value = "ttt")
@Lazy
public class TTT {
}
或者
@Bean(name = "ttt")
@Lazy
public TTT getTTT(){
return new TTT();
}
[email protected]
此註解使用在欄位、構造器引數和方法引數上。@Value可以指定屬性取值的表示式,支援通過#{}使用SpringEL來取值,也支援使用${}來將屬性來源中(Properties檔案、本地環境變數、系統屬性等)的值注入到bean的屬性中。此註解值的注入發生在AutowiredAnnotationBeanPostProcessor類中。
AutowiredAnnotationBeanPostProcessor可以解析 @Autowired和@Value
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.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}