1. 程式人生 > >Spring原始碼分析(十五)Spring中常用註解使用以及原始碼分析

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.
        }
    }