1. 程式人生 > >Java:學習@Autowired

Java:學習@Autowired

原貼收藏在IT老兵驛站

前言

使用SpringMVC,現在不可避免要接觸註解,會遇到@Autowired,查詢了google,找到這篇文章,摘錄下來,做一些筆記。為什麼這樣呢?因為至少來說,以當前的理解,自己來寫,不太可能超越這篇文章,我也不想像很多人那樣搞所謂“二次原創”,其實不還是抄襲,只是針對了判定抄襲的規則來做文章,不耍這樣的小聰明,沒有意義。

本篇選取主要的部分翻譯一下,具體的過程可以參考程式碼,本文的英文難度不高,可以嘗試著讀一讀。

正文

1. Overview

Starting with Spring 2.5, the framework introduced a new style of Dependency Injection driven by @Autowired

 Annotations. This annotation allows Spring to resolve and inject collaborating beans into your bean.

In this tutorial, we will look at how to enable autowiringvarious ways to wire in beansmaking beans optional, resolving bean conflicts using @Qualifier annotation along with potential exception scenarios.

Spring2.5之後,可以使用@Autowired 註解來實現DI(依賴注入),這個詞本身的英文意思就是自動裝配。

2. Enabling @Autowired Annotations

If you are using Java based configuration in your application you can enable annotation-driven injection by using AnnotationConfigApplicationContext to load your spring configuration as below:

1

2

3

@Configuration

@ComponentScan("com.baeldung.autowire.sample")

public class AppConfig {}

As an alternative, in Spring XML, it can be enabled by declaring it in Spring XML files like so: <context:annotation-config/>

想使用註解,現需要配置Spring可以支援註解,有兩種方式,一個是在程式碼中,一個是在XML中,這個涉及到另外一些知識點,作者這裡是假設讀者是知道這些的,不明白的話,需要去查一查。

3. Using @Autowired

Once annotation injection is enabled, autowiring can be used on properties, setters, and constructors.

可以用在屬性、setter方法和構造器上。

3.1. @Autowired on Properties

The annotation can be used directly on properties, therefore eliminating the need for getters and setters:

1

2

3

4

5

6

7

@Component("fooFormatter")

public class FooFormatter {

 

    public String format() {

        return "foo";

    }

}

1

2

3

4

5

6

7

@Component

public class FooService {

     

    @Autowired

    private FooFormatter fooFormatter;

 

}

In the above example, Spring looks for and injects fooFormatter when FooService is created.

如何用在屬性上。

3.2. @Autowired on Setters

The @Autowired annotation can be used on setter methods. In the below example, when the annotation is used on the setter method, the setter method is called with the instance of FooFormatter when FooServiceis created:

1

2

3

4

5

6

7

8

9

public class FooService {

 

    private FooFormatter fooFormatter;

 

    @Autowired

    public void setFooFormatter(FooFormatter fooFormatter) {

            this.fooFormatter = fooFormatter;

    }

}

如何用在方法上。

3.3. @Autowired on Constructors

The @Autowired annotation can also be used on constructors. In the below example, when the annotation is used on a constructor, an instance of FooFormatter is injected as an argument to the constructor when FooService is created:

1

2

3

4

5

6

7

8

9

public class FooService {

 

    private FooFormatter fooFormatter;

 

    @Autowired

    public FooService(FooFormatter fooFormatter) {

        this.fooFormatter = fooFormatter;

    }

}

如何用在構造器方法上。

4. @Autowired and Optional Dependencies

Spring expects @Autowired dependencies to be available when the dependent bean is being constructed. If the framework cannot resolve a bean for wiring, it will throw the below-quoted exception and prevent the Spring container from launching successfully:

1

2

3

4

5

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:

No qualifying bean of type [com.autowire.sample.FooDAO] found for dependency:

expected at least 1 bean which qualifies as autowire candidate for this dependency.

Dependency annotations:

{@org.springframework.beans.factory.annotation.Autowired(required=true)}

To avoid this from happening, a bean can optional be specified as below:

1

2

3

4

5

6

public class FooService {

 

    @Autowired(required = false)

    private FooDAO dataAccessor;

     

}

如果沒有找到響應的bean,又不想系統停止載入,參考上面的寫法。

5. Autowire Disambiguation

By default, Spring resolves @Autowired entries by type. If more than one beans of the same type are available in the container, the framework will throw a fatal exception indicating that more than one bean is available for autowiring.

 @Autowired是根據型別來進行裝備的。但是會存在同一型別內有多個備選bean,這個時候,框架會丟擲一個致命錯誤----這種問題倒是暫時還沒有遇到過,下面講述了三種解決方案。

5.1. Autowiring by @Qualifier

The @Qualifier annotation can be used to hint at and narrow down the required bean:

1

2

3

4

5

6

7

@Component("fooFormatter")

public class FooFormatter implements Formatter {

 

    public String format() {

        return "foo";

    }

}

1

2

3

4

5

6

7

@Component("barFormatter")

public class BarFormatter implements Formatter {

 

    public String format() {

        return "bar";

    }

}

1

2

3

4

5

6

public class FooService {

     

    @Autowired

    private Formatter formatter;

 

}

Since there are two concrete implementations of Formatter available for the Spring container to inject, Spring will throw a NoUniqueBeanDefinitionException exception when constructing the FooService:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException:

No qualifying bean of type [com.autowire.sample.Formatter] is defined:

expected single matching bean but found 2: barFormatter,fooFormatter

This can be avoided by narrowing the implementation using a @Qualifier annotation:

1

2

3

4

5

6

7

public class FooService {

     

    @Autowired

    @Qualifier("fooFormatter")

    private Formatter formatter;

 

}

By specifying the @Qualifier with the name of the specific implementation, in this case as fooFormatter, we can avoid ambiguity when Spring finds multiple beans of the same type.

Please note that the value of the @Qualifier annotation matches with the name declared in the @Component annotation of our FooFormatter implementation.

使用@Qualifier 註解來標識誰是合格的。

5.2. Autowiring by Custom Qualifier

Spring allows us to create our own @Qualifier annotation. To create a custom Qualifier, define an annotation and provide the @Qualifier annotation within the definition as below:

1

2

3

4

5

6

7

8

9

@Qualifier

@Target({

  ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})

@Retention(RetentionPolicy.RUNTIME)

public @interface FormatterType {

     

    String value();

 

}

Once defined, the FormatterType can be used within various implementations to specify custom value:

1

2

3

4

5

6

7

8

@FormatterType("Foo")

@Component

public class FooFormatter implements Formatter {

 

    public String format() {

        return "foo";

    }

}

1

2

3

4

5

6

7

8

@FormatterType("Bar")

@Component

public class BarFormatter implements Formatter {

 

    public String format() {

        return "bar";

    }

}

Once the implementations are annotated, the custom Qualifier annotation can be used as below:

1

2

3

4

5

6

7

8

@Component

public class FooService {

     

    @Autowired

    @FormatterType("Foo")

    private Formatter formatter;

     

}

The value specified in the @Target annotation restrict where the qualifier can be used to mark injection points.

In the above code snippet, the qualifier can be used to disambiguate the point where Spring can inject the bean into a field, a method, a type, and a parameter.

5.3. Autowiring by Name

As a fallback Spring uses the bean name as a default qualifier value.

So by defining the bean property name, in this case as fooFormatter, Spring matches that to the FooFormatter implementation and injects that specific implementation when FooService is constructed:

1

2

3

4

5

6

public class FooService {

     

    @Autowired

    private Formatter fooFormatter;

     

}

使用名字來自動裝配。

6. Conclusion

Although both @Qualifier and bean name fallback match can be used to narrow down to a specific bean, autowiring is really all about injection by type and this is how best to use this container feature.

The source code of this tutorial can be found in the GitHub project – this is an Eclipse based project, so it should be easy to import and run as it is.

總結

老外的文章講的真清楚,他們會對讀者負責,很認真地把所有問題講清楚,不像很多國人,哪怕是很多好像挺有名的教授出的書,都是“言簡意賅”,看著好費勁,給人一種高高在上的感覺。當年讀清華嚴蔚敏出的《資料結構》,讀著就非常費勁,後來看大師出的《演算法導論》,反而容易理解,中國人怎麼總就是這麼高傲呢。

參考

https://www.baeldung.com/spring-autowire

https://stackoverflow.com/questions/1018797/can-you-use-autowired-with-static-fields 介紹了靜態域能不能自動裝配