1. 程式人生 > 實用技巧 >關於Spring中@Order 、@AutoConfigureBefore等與順序相關注解的使用誤區

關於Spring中@Order 、@AutoConfigureBefore等與順序相關注解的使用誤區

關於Spring中@Order 、@AutoConfigureBefore等與順序相關注解的誤區

1、@Order註解並非一定會給你的bean排序

​ @Order註解表示排序,但是它不能決定@Configuration或者是@Bean註解的例項化順序。決定Spring裡bean例項化或者注入順序的一般情況下是bean之間的依賴關係。這個依賴關係一般是類的建構函式的引數、類屬性或者@DependsOn註解來控制。

​ 以下是錯誤的演示,Test1Config和Test2Config兩個配置類的例項化,包括Apple和Orange的例項化都無法用@Order註解控制,調換順序後可以發現例項化的順序不會變化,因為他們之間並沒有依賴關係。

@Configuration
@Order(100)
public class Test1Config {
    public Test1Config() {
        System.out.println("Test1Config 構造");
    }

    @Bean
    public Apple apple(){
        System.out.println("準備new Apple ...");
        return new Apple();
    }
}

@Configuration
@Order(0)
public class Test2Config {

    public Test2Config() {
        System.out.println("Test2Config 構造");
    }

    @Bean
    public Orange orange(){
        System.out.println("準備new Orange ...");
        return new Orange();
    }
}

2、那麼如何控制配置類以及Bean的例項化順序呢?

​ 在實際專案中,我們確實有需要控制某幾個類的注入IOC容器的順序,一般如果有直接依賴關係可以用類屬性或者建構函式方式實現,一般推薦類屬性注入,因為Spring並沒有解決建構函式注入的迴圈依賴問題,所以沒有十分的把握不要採用建構函式注入。

​ 如果Bean之間其實沒有直接引用依賴關係,但是又要控制兩個Bean之間的注入順序,可以使用@DependsOn註解。比如上面的例子,假設Test2Config需要先例項化注入到IOC容器,可以採用如下方式:

@Configuration
@DependsOn("test2Config")
public class Test1Config {
    public Test1Config() {
        System.out.println("Test1Config 構造");
    }

    @Bean
    public Apple apple(){
        System.out.println("準備new Apple ...");
        return new Apple();
    }
}

3、那麼@Order註解如何正確使用?

​ @Order註解只會給Spring實現其排序功能的元件或者介面中發揮作用,又或者由開發者自定義其順序的實現。比如:Spring的介面CommandLineRunner就可以支援@Order註解,在我們實現多個CommandLineRunner介面的時候,如果對其執行順序有要求的時候,就可以使用@Order註解。

@Component
@Order(160)
public class AppleCommand implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("AppleCommand run ...");
    }
}
@Component
@Order(150)
public class OrangeCommand implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("OrangeCommand  run ...");
    }
}

調整兩段程式碼@Order的大小,可以調整其執行先後順序。

對於@Order註解,可以參考官方解釋,深刻理解其含義和應用。

NOTE: Since Spring 4.0, annotation-based ordering is supported for many kinds of components in Spring, even for collection injection where the order values of the target components are taken into account (either from their target class or from their @Bean method). While such order values may influence priorities at injection points, please be aware that they do not influence singleton startup order which is an orthogonal concern determined by dependency relationships and @DependsOn declarations (influencing a runtime-determined dependency graph).

4、@AutoConfigureBefore是給自動配置排序用的

​ @AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder這三個註解是給Springboot自動配置類排序使用的,注意是自動配置類,並非是普通的配置類。

​ Springboot的自動配置需要在jar包目錄下META-INF/spring.factories檔案中進行類名配置。類似:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wood.lib.autoconfigure.AXXXAutoConfiguration,\
com.wood.lib.autoconfigure.BXXXWebAutoConfiguration

注:自動配置類只能通過這種方式載入,確保它們定義在一個特殊的package中,特別是不能成為元件掃描的目標。

這樣你可以使用@AutoConfigureAfter@AutoConfigureBefore註解為配置類指定特定的順序。如下:

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(SecurityProperties.class)
@ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class })
@AutoConfigureAfter(BXXXWebAutoConfiguration.class)
public class AXXXAutoConfiguration {

	@Bean
	@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
	public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
			SecurityProperties securityProperties) {
		...
		return registration;
	}

    ... ...

}