Spring Framework ‐ Annotation - CCH0124/spring-sandbox GitHub Wiki
- @SpringBootApplication
- @RestController
- @Autowired
- @Value
- @Enable
- @Configuration
- @Bean
DI 相關註釋
- @Autowired
可以使用
@Autowired
來標記,Spring 將解析和注入的依賴項。
Constructor injection
@Controller
public class CarConstructorController {
private CarService carService;
@Autowired
CarConstructorController(CarService carService) {
this.carService = carService;
}
}
Setter injection
@Controller
public class CarSetterController {
private CarService carService;
@Autowired
void setCarService(CarService carService) {
this.carService = carService;
}
}
Field injection
@Controller
public class CarController {
@Autowired
private CarService carService;
public void get() {
carService.out();
System.out.println("Controller Layer");
}
}
Arg Injection
@Controller
public class CarArgController {
private CarService carService;
public CarArgController(@Autowired CarService carService) {
this.carService = carService;
}
}
- @Bean
在 Spring 中,構成應用程式主要架構,並由 Spring IoC 容器管理的物件稱為 Bean。 Bean 是 Spring IoC 容器實例化、組裝和管理的物件。
此註釋可作用於方法。@Bean
是一個實例化 Spring bean 的工廠方法
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
/**
* Alias for {@link #name}.
* <p>Intended to be used when no other attributes are needed, for example:
* {@code @Bean("customBeanName")}.
* @since 4.3.3
* @see #name
*/
@AliasFor("name")
String[] value() default {};
...
}
@Configuration
@ComponentScan(basePackageClasses = Vehicle.class)
public class Config {
@Bean
public Brand getBrand() {
return new Brand("volvo", 1844);
}
}
預設上產生的 Bean 與工廠方法具有相同的名稱。如果想以不同的方式命名它,可以使用 name 參數進行別名上的設定。
@Configuration
@ComponentScan(basePackageClasses = Vehicle.class)
public class Config {
@Bean("brand")
public Brand getBrand() {
return new Brand("volvo", 1844);
}
}
注意,所有用
@Bean
註解的方法都必須在@Configuration
類別中
- @Qualifier
他可用於變數上、方法或是參數上的註解。基本上和 @Autowired
是搭配的。
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
String value() default "";
}
透過 @Qualifier
和 @Autowired
來提供想要在不明確的情況下使用的 Bean。
假設定義 Vehicle
介面,並由 Bike
與 Car
來實作
@Component
public class Bike implements Vehicle{
@Override
public void printBrand() {
System.out.println("Addmotor");
}
}
@Component
public class Car implements Vehicle {
@Override
public void printBrand() {
System.out.println("Volvo");
}
}
如果 Spring 需要注入一個 Vehicle
的 Bean,它會得到多個符合的定義,會出現如下錯誤訊息。
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'carController': Unsatisfied dependency expressed through field 'vehicle': No qualifying bean of type 'org.annotation.qualifier.Vehicle' available: expected single matching bean but found 2: bike,car
在這種情況下,我們可以使用 @Qualifier
註解明確提供 Bean
的名稱,如下這也表示每次對 Vehicle
進行注入都需要搭配 @Qualifier
。
@Controller
public class BikeController {
@Autowired
@Qualifier("bike")
private Vehicle vehicle;
public void get() {
vehicle.printBrand();
System.out.println("Bike Controller Layer");
}
}
@Controller
public class CarController {
@Autowired
@Qualifier("car")
private Vehicle vehicle;
public void get() {
vehicle.printBrand();
System.out.println("Car Controller Layer");
}
}
- @Value
可以使用 @Value
將屬性值注入到 Bean 中,它可用於建構函式、setter 和 Field 注入等。可以使用 @Value
中的定義的字串來與外部配置進行關聯(如 .properties 或 .yaml 檔案)中定義的值。
@Value("${car.type}")
String carType;
.properties
檔案可以如下定義
car.type=Volvo
@Value
可以設定預設值、陣列、系統變數或是 Map 來進行配置,彈性非常大。
- @DependsOn
這個註解讓 Spring 在被註解的 Bean 之前初始化其他 Bean。通常,這種行為是自動且要基於 Bean 之間的明確依賴關係。只有當依賴關係是隱式的時,例如 JDBC 驅動程式載入或靜態變數初始化,我們才需要此註解。
- @Configuration
它表明該類別具有 @Bean
定義方法。因此 Spring 容器可以處理該類別並產生要在應用程式中使用的 Bean。用此註解可取代 xml 宣告方式。
- @Component
當使用基於註解的配置和類別路徑掃描時,Spring 框架將自動偵測這些類別以進行依賴注入,並由 Spring 容器進行管理。@Component
註解則是用來宣告一個普通的 Java 類別為Spring 中的物件(Bean)。
當 Spring 容器掃描到被 @Component
標記的類別時,會將其建立實例化並注入到 Spring 容器中,讓其他元件呼叫、依賴。以下的行為都是相同的,因為它們都是用 @Component
作為每個註釋的組合註釋
@Service
@Repository
@Controller
下面的 @Repository
包含了 @Component
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
/**
* Alias for {@link Component#value}.
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
另一個 @ComponentScan
,Spring 使用它將它們(@Component
)收集到其 ApplicationContext
中。而 @SpringBootApplication
是一個包含 @ComponentScan
的組合註釋,只要 @SpringBootApplication
類別位於專案的根目錄下,它就會預設掃描我們定義的每個 @Component
。前面提到是根目錄,如果不是可藉由配置 @ComponentScan
來尋找指定的任何套件。
與 @Bean 相比
@Component
是類別層級的註解,而@Bean
是方法層級的,所以@Component
只是當類別的原始程式碼可編輯時的一個選項。@Bean 是可以使用,但它更繁瑣。@Component
與 Spring 的自動偵測相容,但@Bean
需要手動類別實例化。- 使用
@Bean
,將 bean 的實例化與其類別定義分開。這就是為什麼可以用它來將第三方類別製作成 Spring bean。這也表示可以引入邏輯來決定 bean 使用幾個可能的實例選項中的哪一個。
- @Lazy
用來想要延遲初始化 bean 時。在某些情況下,需要在請求時而不是在應用程式啟動時建立 bean。此
@Lazy
的行為有所不同,取決於確切放置它的位置。可以把它放在:
- @Bean 的 Bean 工廠方法上,以延遲方法調用,延遲了 Bean 的創建
- @Configuration 的類別上,所有包含的 @Bean 方法都會受影響
- @Component 但不是 @Configuration 的類別上,此 Bean 將被延遲初始化
- @Autowired 的建構函式、setter 或變數上,延遲加載依賴本身
- @Primary
當定義多個相同類型的 bean 時。在這些情況下,注入將不成功,因為 Spring 不知道我們需要哪一個 bean。但可以用 @Qualifier
來決定使用哪一個。如果需要一種特定的 bean,而很少需要其他的 bean,可以使用 @Primary
來簡易配置。