天天看點

看完讓你吊打面試官-@Autowired注解到底怎麼實作的?(上)1 @Autowired 幹嘛的?2 優雅地使用@Autowired3 @Autowired注解背後的秘密

1 @Autowired 幹嘛的?

用來執行依賴注入。每當一個Spring管理的bean發現有該注解時,會直接注入相應的另一個Spring管理的bean。

1.1 不同地方放置有不同作用

  • 屬性

    Spring将通過掃描自定義的package或通過在配置檔案中直接查找bean

  • 方法

使用 @Autowired 注解的每個方法都要用到依賴注入。但注意,簽名中呈現的所有對象都必須是Spring所管理的bean。

如果你有一個方法,比如setTest(Article article, NoSpringArticle noSpringArt),其中隻有一個參數 (Article article)是由Spring管理,那麼就将抛org.springframework.beans.factory.BeanCreationException異常。這是由于Spring容器裡并沒有指定的一個或多個參數所指向的bean,是以也就無法解析它們。

1.2 bean的注入方式

  • 名稱

    bean解析是通過bean名稱

  • 類型

    解析基于bean的類型

1.3 @Qualifier 協作

如下相同類型的bean

<bean name="article1" class="com.sss.Article">
    <property name="text" value="Content of the 1st Article" />
</bean>

<bean name="article2" class="com.sss.Article">
    <property name="text" value="Content of the 2nd Article" />
</bean>      

假如隻是一個簡單的@Autowired,Spring根本不知道你要注入哪個bean。這就需要

@Qualifier(value = "beanName")      

譬如,要從 

com.javaedge.Article

類型的bean中區分article1、article2:

@Qualifier(value="article1")
@Autowired
private Article firstArticle;

@Qualifier(value="article2")
@Autowired
private Article secondArticle;      

2 優雅地使用@Autowired

啟動自動注入

<context:annotation-config />      

放在應用程式上下文配置。可以使在遇到@Autowired注解時啟用依賴注入

  • bean
// beans first
public class Comment {

    private String content;

    public void setContent(String content) {
        this.content = content;
    }

    public String getContent() {
        return this.content;
    }

}

// sample controller
@Controller
public class TestController {

    @Qualifier(value="comment1")
    @Autowired
    private Comment firstComment;

    @Qualifier(value="comment2")
    @Autowired
    private Comment secondComment;

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String test() {
        System.out.println("1st comment text: "+firstComment.getText());
        System.out.println("2nd comment text: "+secondComment.getText());
        return "test";
    }

}

// no-Spring managed class
public class TestNoSpring {

    @Autowired
    private Comment comment;

    public void testComment(String content) {
        if (comment == null) {
            System.out.println("Comment's instance wasn't autowired because this class is not Spring-managed bean");
        } else {
            comment.setContent(content);
            System.out.println("Comment's content: "+comment.getContent());
        }
    }

}
      
  • 配置
<bean name="comment1" class="com.sss.exchanger.Comment">
    <property name="content" value="Content of the 1st comment" />
</bean>

<bean name="comment2" class="com.sss.exchanger.Comment">
    <property name="content" value="Content of the 2nd comment" />
</bean>      

自測發現TestController的注解字段正确地自動注入,而TestNoSpring的注解字段并沒有注入進去

1st comment text: Content of the 1st comment
2nd comment text: Content of the 2nd comment
Comment's instance wasn't autowired because this class is not Spring-managed bean      

因為TestNoSpring類不由Spring所管理,這就是為什麼Spring不能注入Comment執行個體的依賴。

3 @Autowired注解背後的秘密

應用程式上下文具有入口點,在Web應用程式中,是

dispatcherservlet

。容器(也就是該上下文)會在它那裡被啟動并且所有的bean都會被注入。

<context:annotation-config />

的定義

<xsd:element name="annotation-config">
        <xsd:annotation>
            <xsd:documentation><![CDATA[
    Activates various annotations to be detected in bean classes: Spring's @Required and
    @Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),
    JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's
    @PersistenceContext and @PersistenceUnit (if available). Alternatively, you may
    choose to activate the individual BeanPostProcessors for those annotations.
    Note: This tag does not activate processing of Spring's @Transactional or EJB 3's
    @TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>
    tag for that purpose.
    See javadoc for org.springframework.context.annotation.AnnotationConfigApplicationContext
    for information on code-based alternatives to bootstrapping annotation-driven support.
            ]]></xsd:documentation>
        </xsd:annotation>
    </xsd:element>
      

類内部的注解,如@Autowired、@Value、@Required、@Resource以及Web Serivce相關的注解,是容器對Bean對象執行個體化和依賴注入時,通過容器中注冊的Bean後置處理器處理這些注解的

是以配置了上面這個配置(<context:component-scan>假如有配置這個,那麼就可以省略<context:annotation-config />)後,将隐式地向Spring容器注冊AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor以及這4個專門用于處理注解的Bean後置處理器。

當 Spring 容器啟動時,AutowiredAnnotationBeanPostProcessor 将掃描 Spring 容器中所有 Bean

當發現 Bean 中擁有@Autowired 注解時就找到和其比對(預設按類型比對)的 Bean

并注入到對應的地方中去。