手动bean注册和配置顺序



我对spring的@Order注释有一个问题,似乎我无法让它在我的应用程序中工作。因此,我设法创建了一个测试类,它模仿了@Order对我的组件没有任何影响的相同行为。由于缺少bean类型的javax.sql.Datasource,下面的测试无法运行:

package com.so;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.datasource.AbstractDataSource;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class TestSpring {
   public static void main(String[] args) {
      Class<?>[] classes = new Class[]{AConf.class, ADAO.class, AService.class, RepoConf.class} ;
      AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(classes);
   }
   @Configuration
   @Order(Ordered.HIGHEST_PRECEDENCE + 100)
   public static class AConf {
      @Autowired
      AService aService;
   }
   @Repository
   @Order(Ordered.LOWEST_PRECEDENCE)
   public static class ADAO {
      @Autowired
      @Qualifier("myds")
      DataSource dataSource;
   }
   @Service
   @Order(Ordered.LOWEST_PRECEDENCE)
   public static class AService {
      @Autowired
      ADAO adao;
      @PostConstruct
      public void init() {
         System.out.println("service init");
      }
   }
//   @Component does not have any effect
   @Configuration
   @Order(Ordered.HIGHEST_PRECEDENCE)
   public static class RepoConf {
      @Autowired
      BeanFactory beanFactory;
      @PostConstruct
      public void init() {
         ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
         configurableBeanFactory.registerSingleton("myds", new AbstractDataSource() {
            @Override
            public Connection getConnection() throws SQLException {
               return null;
            }
            @Override
            public Connection getConnection(String username, String password) throws SQLException {
               return null;
            }
         });
      }
   }
}

手动bean注册有如下所述的风险:https://stackoverflow.com/a/11751503/1941560,尽管我无法找到@Order注释在哪些情况下工作。对于上述应用程序配置,我期望执行顺序如下;RepoConf, AConf, ADAO, AService .

一个奇怪的事情要注意的是,当我改变组件类声明的顺序(以RepoConf开始的数组):
Class<?>[] classes = new Class[]{RepoConf.class, AConf.class, ADAO.class, AService.class};

或将AConf类更改为:

   @Configuration
   @Order(Ordered.HIGHEST_PRECEDENCE + 100)
   public static class AConf {
      @Autowired
      RepoConf repoConf; // must be declared before aService
      @Autowired
      AService aService;
   }

应用程序按预期工作。有人能解释一下弹簧容器的行为以及我如何利用@Order注释吗?

我使用的springframework版本是4.2.1.RELEASE

根据@Order注释的JavaDoc文档判断,我认为它不是用来命令bean创建的:

注意:基于注释的排序支持特定类型的组件——例如,基于注释的AspectJ方面。另一方面,Spring容器中的排序策略是通常基于Ordered接口,以便允许每个实例的可编程配置顺序。

参考Spring框架文档,@Ordered注释似乎用于:

  • 注入到集合时的实例排序
  • 事件监听器的执行顺序
  • @Configuration类处理的排序,例如,如果你想通过名称覆盖bean。

从文档来看,@Order似乎不适合您的用例。

然而,从Spring文档中,我们可以看到depends-on,它强制在定义bean之前创建某些bean。它有一个相应的注释@DependsOn

看起来您的Spring Framework版本只是忽略了配置类上的@Order注释。这里没有什么奇怪的,因为注释应该只用于实现Ordered接口的类。而且,我从来没有在Spring框架参考文档中找到任何关于配置类的参考。

无论如何,你走在未知领域这里。官方文档中没有描述它,因此它是否工作取决于实现细节。这里发生的事情是(查看结果):

  • AnnotationConfigApplicationContext首先按声明顺序实例化配置类和它们的bean
  • 然后按照实例化顺序构建所有bean
当您在构建时在其配置类中注册数据源myds时,当repoConf任何其他使用它们的bean之前构建时,它恰好被及时注册以便自动连接到其他bean中。但是Spring框架文档从来没有保证过这一点,未来的版本可以使用不同的方法而不会破坏它们之间的契约。此外,Spring还更改了初始化顺序,允许在依赖依赖项的bean之前构造依赖项。 所以这里正确的方法是告诉Spring ADAO bean 依赖于配置RepoConf。扔掉所有在这里没有用的Order注释,换上一个@DependsOn注释。你的代码可以是:
package com.so;
...
public class TestSpring {
   public static void main(String[] args) {
      Class<?>[] classes = new Class[]{AConf.class, ADAO.class, AService.class, RepoConf.class} ;
      AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(classes);
   }
   @Configuration
   public static class AConf {
      @Autowired
      AService aService;
   }
   @DependsOn("repoConf")
   @Repository
   public static class ADAO {
      @Autowired
      @Qualifier("myds")
      DataSource dataSource;
   }
   @Service
   public static class AService {
      @Autowired
      ADAO adao;
      @PostConstruct
      public void init() {
         System.out.println("service init");
      }
   }
   @Configuration("repoConf")
   public static class RepoConf {
      @Autowired
      BeanFactory beanFactory;
      @PostConstruct
      public void init() {
         ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
         configurableBeanFactory.registerSingleton("myds", new AbstractDataSource() {
            @Override
            public Connection getConnection() throws SQLException {
               return null;
            }
            @Override
            public Connection getConnection(String username, String password) throws SQLException {
               return null;
            }
         });
      }
   }
}

@DependsOn确保repoConfADAO之前创建,使数据源可用于依赖注入。

最新更新