常用的自動裝配註解@Autowired @RequiredArgsConstructor @AllArgsConstructor

javafanwk發表於2019-06-11

      《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 &#64;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 &#64;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


 

相關文章