我对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
确保repoConf
在ADAO
之前创建,使数据源可用于依赖注入。