是否可以在Spring中设置实例化的顺序?
我不想使用@DependsOn
而我不想使用Ordered
界面。我只需要一个实例化的命令。
@Order
注释的以下用法不起作用:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
/**
* Order does not work here
*/
public class OrderingOfInstantiation {
public static class MyBean1 {{
System.out.println(getClass().getSimpleName());
}}
public static class MyBean2 {{
System.out.println(getClass().getSimpleName());
}}
@Configuration
public static class Config {
@Bean
@Order(2)
public MyBean1 bean1() {
return new MyBean1();
}
@Bean
@Order(1)
public MyBean2 bean2() {
return new MyBean2();
}
}
public static void main(String[] args) {
new AnnotationConfigApplicationContext(Config.class);
}
}
仍然以字典顺序对豆进行实例化。
为什么它在这里不起作用?
我还可以依赖词典顺序吗?
更新
我想任何允许提供创作顺序的解决方案。
目标是以正确的顺序在配置级别填充集合。 Depends on
- 与任务不匹配。关于为什么Spring不喜欢有序实例化的任何“解释” - 也与该任务不匹配。
订单意味着订单:)
答案 0 :(得分:7)
来自@Order
javadoc
注意:仅支持基于注释的排序仅适用于特定类型的组件 - 例如,对于基于注释的AspectJ方面。另一方面,Spring容器中的排序策略通常基于Ordered接口,以便允许以编程方式配置每个实例。
所以我猜Spring在创建bean时不会遵循@Order()
。
但是如果你只想填充馆藏,也许这对你来说已经足够了:
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Configuration
public class OrderingOfInstantiation {
public static void main(String[] args) {
new AnnotationConfigApplicationContext(OrderingOfInstantiation.class);
}
@Component
@CollectionOrder(collection = "myBeans", order = 1)
public static class MyBean1 {{
System.out.println(getClass().getSimpleName());
}}
@Component
@CollectionOrder(collection = "myBeans", order = 2)
public static class MyBean2 {{
System.out.println(getClass().getSimpleName());
}}
@Configuration
public static class CollectionsConfig {
@Bean
List<Object> myBeans() {
return new ArrayList<>();
}
}
// PopulateConfig will populate all collections beans
@Configuration
public static class PopulateConfig implements ApplicationContextAware {
@SuppressWarnings("unchecked")
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Multimap<String, Object> beansMap = MultimapBuilder.hashKeys().arrayListValues().build();
// get all beans
applicationContext.getBeansWithAnnotation(CollectionOrder.class)
.values().stream()
// get CollectionOrder annotation
.map(bean -> Pair.of(bean, bean.getClass().getAnnotation(CollectionOrder.class)))
// sort by order
.sorted((p1, p2) -> p1.getRight().order() - p2.getRight().order())
// add to multimap
.forEach(pair -> beansMap.put(pair.getRight().collection(), pair.getLeft()));
// and add beans to collections
beansMap.asMap().entrySet().forEach(entry -> {
Collection collection = applicationContext.getBean(entry.getKey(), Collection.class);
collection.addAll(entry.getValue());
// debug
System.out.println(entry.getKey() + ":");
collection.stream()
.map(bean -> bean.getClass().getSimpleName())
.forEach(System.out::println);
});
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface CollectionOrder {
int order() default 0;
String collection();
}
}
它不会更改实例化顺序,但您将获得有序集合。
答案 1 :(得分:6)
如果要确保在另一个bean之前创建特定的bean,可以使用@DependsOn注释。
@Configuration
public class Configuration {
@Bean
public Foo foo() {
...
}
@Bean
@DependsOn("foo")
public Bar bar() {
...
}
}
请记住,这不会设置顺序,它只保证在“bar”之前创建bean“foo”。 JavaDoc for @DependsOn
答案 2 :(得分:0)
您可以通过首先消除类MyBean1
和MyBean2
上的静态来强制执行排序,在几乎所有情况下都不需要使用Spring,因为Spring的默认设置是实例化每个bean的单个实例(类似于Singleton)。
诀窍是将MyBean1
和MyBean2
声明为@Bean
并强制执行顺序,通过从bean1的初始化中调用bean2的bean初始化方法,创建从bean1到bean2的隐式依赖项方法。
例如:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
/**
* Order does not work here
*/
public class OrderingOfInstantiation {
interface MyBean{
default String printSimpleName(){
System.out.println(getClass().getSimpleName());
}
}
public class MyBean1 implments MyBean{
public MyBean1(){ pintSimpleName(); }
}
public class MyBean2 implments MyBean{
public MyBean2(){ pintSimpleName(); }
}
public class MyBean3 implments MyBean{
public MyBean3(){ pintSimpleName(); }
}
public class MyBean4 implments MyBean{
public MyBean4(){ pintSimpleName(); }
}
public class MyBean5 implments MyBean{
public MyBean5(){ pintSimpleName(); }
}
@Configuration
public class Config {
@Bean
MyBean1 bean1() {
//This will cause a a dependency on bean2
//forcing it to be created before bean1
bean2();
return addToAllBeans(new MyBean1());
}
@Bean
MyBean2 bean2() {
//This will cause a a dependency on bean3
//forcing it to be created before bean2
bean3();
//Note: This is added just to explain another point
//Calling the bean3() method a second time will not create
//Another instance of MyBean3. Spring only creates 1 by default
//And will instead look up the existing bean2 and return that.
bean3();
return addToAllBeans(new MyBean2());
}
@Bean
MyBean3 bean3(){ return addToAllBeans(new MyBean3()); }
@Bean
MyBean4 bean4(){ return addToAllBeans(new MyBean4()); }
@Bean
MyBean5 bean5(){ return addToAllBeans(new MyBean5()); }
/** If you want each bean to add itself to the allBeans list **/
@Bean
List<MyBean> allBeans(){
return new ArrayList<MyBean>();
}
private <T extends MyBean> T addToAllBeans(T aBean){
allBeans().add(aBean);
return aBean;
}
}
public static void main(String[] args) {
new AnnotationConfigApplicationContext(Config.class);
}
}