《spring實戰》中給裝配下了一個定義:創建應用對象之間協作關係的行爲稱爲裝配。也就是說當一個對象的屬性是另一個對象時,實例化時,需要爲這個對象屬性進行實例化。這就是裝配。
如果一個對象只通過接口來表明依賴關係,那麼這種依賴就能夠在對象本身毫不知情的情況下,用不同的具體實現進行切換。但是這樣會存在一個問題,在傳統的依賴注入配置中,我們必須要明確要給屬性裝配哪一個bean的引用,一旦bean很多,就不好維護了。基於這樣的場景,spring使用註解來進行自動裝配,解決這個問題。自動裝配就是開發人員不必知道具體要裝配哪個bean的引用,這個識別的工作會由spring來完成。與自動裝配配合的還有“自動檢測”,這 個動作會自動識別哪些類需要被配置成bean,進而來進行裝配。這樣我們就明白了,自動裝配是爲了將依賴注入“自動化”的一個簡化配置的操作。
裝配分爲三種:byName, byType, constructor。
- byName就是會將與屬性的名字一樣的bean進行裝配。
- byType就是將同屬性一樣類型的bean進行裝配。
- constructor就是通過構造器來將類型與參數相同的bean進行裝配。
public interface AutowireCapableBeanFactory extends BeanFactory {
int AUTOWIRE_NO = 0;
int AUTOWIRE_BY_NAME = 1;
int AUTOWIRE_BY_TYPE = 2;
int AUTOWIRE_CONSTRUCTOR = 3;
}
byType的 @Autowired(spring提供的),@Inject(java ee提供)
@Autowired註解是byType類型的,這個註解可以用在屬性上面,setter方面上面以及構造器上面。使用這個註解時,就不需要在類中爲屬性添加setter方法了。但是這個屬性是強制性的,也就是說必須得裝配上,如果沒有找到合適的bean能夠裝配上,就會拋出異常。這時可以使用required=false來允許可以不被裝配上,默認值爲true。當required=true時,@Autowired要求必須裝配,但是在沒有bean能裝配上時,就會拋出異常:NoSuchBeanDefinitionException,如果required=false時,則不會拋出異常。
- @Inject必須是強制裝配的,沒有required屬性,也就是不能爲null,如果不存在匹配的bean,會拋出異常。
- 自動裝配時,裝配的bean必須是唯一與屬性進行吻合的,不能多也不能少,有且只有一個可以進行裝配的bean,才能自動裝配成功。否則會拋出異常。
byName的 @Qualifier(spring提供的),@Named(java ee提供),@Resource(java ee提供)
一種情況是同時有多個bean是一個類型的,也會拋出這個異常。此時需要進一步明確要裝配哪一個Bean,這時可以組合使用
@Qualifier註解使用byName進行裝配,這樣可以在多個類型一樣的bean中,明確使用哪一個名字的bean來進行裝配。@Qualifier註解起到了縮小自動裝配候選bean的範圍的作用。
@Autowired與@Qualifier是spring提供的 ,@Inject與@Named是java ee的。
constructor 的@Data @RequiredArgsConstructor @AllArgsConstructor
@Component
@Slf4j
@AllArgsConstructor
class NoNeedInspectValidator {
private final MaterialProxy materialProxy;
private final ResultVOBuilder resultVOBuilder;
}
- @Data
/**
* Generates getters for all fields, a useful toString method, and hashCode and equals implementations that check
* all non-transient fields. Will also generate setters for all non-final fields, as well as a constructor.
* <p>
* Equivalent to {@code @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode}.
* <p>
* Complete documentation is found at <a href="https://projectlombok.org/features/Data">the project lombok features page for @Data</a>.
*
* @see Getter
* @see Setter
* @see RequiredArgsConstructor
* @see ToString
* @see EqualsAndHashCode
* @see lombok.Value
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Data {
/**
* If you specify a static constructor name, then the generated constructor will be private, and
* instead a static factory method is created that other classes can use to create instances.
* We suggest the name: "of", like so:
*
* <pre>
* public @Data(staticConstructor = "of") class Point { final int x, y; }
* </pre>
*
* Default: No static constructor, instead the normal constructor is public.
*
* @return Name of static 'constructor' method to generate (blank = generate a normal constructor).
*/
String staticConstructor() default "";
}
根據源碼可以看到 註解@Data含有@RequiredArgsConstructor
- @RequiredArgsConstructor
/**
* Generates a constructor with required arguments.
* Required arguments are final fields and fields with constraints such as {@code @NonNull}.
* <p>
* Complete documentation is found at <a href="https://projectlombok.org/features/Constructor">the project lombok features page for @Constructor</a>.
* <p>
* Even though it is not listed, this annotation also has the {@code onConstructor} parameter. See the full documentation for more details.
*
* @see NoArgsConstructor
* @see AllArgsConstructor
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface RequiredArgsConstructor {
/**
* If set, the generated constructor will be private, and an additional static 'constructor'
* is generated with the same argument list that wraps the real constructor.
*
* Such a static 'constructor' is primarily useful as it infers type arguments.
*
* @return Name of static 'constructor' method to generate (blank = generate a normal constructor).
*/
String staticName() default "";
/**
* Any annotations listed here are put on the generated constructor.
* The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br>
* up to JDK7:<br>
* {@code @RequiredArgsConstructor(onConstructor=@__({@AnnotationsGoHere}))}<br>
* from JDK8:<br>
* {@code @RequiredArgsConstructor(onConstructor_={@AnnotationsGohere})} // note the underscore after {@code onConstructor}.
*
* @return List of annotations to apply to the generated constructor.
*/
AnyAnnotation[] onConstructor() default {};
/**
* Sets the access level of the constructor. By default, generated constructors are {@code public}.
*
* @return The constructor will be generated with this access modifier.
*/
AccessLevel access() default lombok.AccessLevel.PUBLIC;
/**
* Placeholder annotation to enable the placement of annotations on the generated code.
* @deprecated Don't use this annotation, ever - Read the documentation.
*/
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
@interface AnyAnnotation {}
}
根據源碼可以看到 Required arguments are final fields and fields with constraints such as {@code @NonNull}.
會生成一個包含常量,和標識了NotNull的變量的構造方法。生成的構造方法是私有的private
- @AllArgsConstructor
會生成一個包含所有變量的構造方法
區別:執行順序
Constructor >> @Autowired