woo*_*ver 18 java spring spring-annotations
我有一个使用Spring进行依赖注入的系统.我使用基于注释的自动装配.通过组件扫描发现bean,即我的上下文XML包含:
<context:component-scan base-package="org.example"/>
Run Code Online (Sandbox Code Playgroud)
我在下面创建了一个简单的例子来说明我的问题.
有一个Zoo
是Animal
对象的容器.开发人员在开发过程Zoo
中不知道哪些Animal
对象将被包含Zoo
; Animal
Spring实例化的具体对象集在编译时是已知的,但是有各种构建配置文件导致各种Animal
s组,并且Zoo
在这些情况下代码不得更改.
其目的Zoo
是允许系统的其他部分(此处说明为ZooPatron
)Animal
在运行时访问对象集,而无需明确依赖某些Animal
s.
实际上,具体的Animal
类将全部由各种Maven工件贡献.我希望能够通过简单地依赖包含这些具体Animal
的各种工件来组装我的项目的分布,并且在编译时使所有内容都能正确地自动装配.
我试图通过让个人Animal
依赖于这个问题来解决这个问题(不成功)Zoo
,以便他们可以在Zoo
期间调用注册方法@PostConstruct
.这避免了Zoo
明确依赖于明确的Animal
s 列表.
这种方法的问题在于,只有当所有s已经注册时,Zoo
希望与其进行交互的客户.有一组有限的s在编译时是已知的,并且注册都发生在我的生命周期的Spring连接阶段,所以订阅模型应该是不必要的(即我不希望在运行时添加s)).Animal
Animal
Animal
Zoo
不幸的是,所有的客户都Zoo
依赖于Zoo
.这与Animal
s的关系完全相同Zoo
.因此,s和s 的@PostConstruct
方法以任意顺序调用.下面的示例代码说明了这一点 - 在调用时,没有注册,在所有注册时都是几毫秒.Animal
ZooPatron
@PostConstruct
ZooPatron
Animal
所以这里有两种类型的依赖,我在Spring中努力表达.Zoo
一旦所有Animal
s都在其中,客户只想使用它.(也许"方舟"会是一个更好的例子......)
我的问题基本上是:解决这个问题的最佳方法是什么?
@Component
public class Zoo {
private Set<Animal> animals = new HashSet<Animal>();
public void register(Animal animal) {
animals.add(animal);
}
public Collection<Animal> getAnimals() {
return animals;
}
}
public abstract class Animal {
@Autowired
private Zoo zoo;
@SuppressWarnings("unused")
@PostConstruct
private void init() {
zoo.register(this);
}
@Component
public static class Giraffe extends Animal {
}
@Component
public static class Monkey extends Animal {
}
@Component
public static class Lion extends Animal {
}
@Component
public static class Tiger extends Animal {
}
}
public class ZooPatron {
public ZooPatron(Zoo zoo) {
System.out.println("There are " + zoo.getAnimals().size()
+ " different animals.");
}
}
@Component
public class Test {
@Autowired
private Zoo zoo;
@SuppressWarnings("unused")
@PostConstruct
private void init() {
new Thread(new Runnable() {
private static final int ITERATIONS = 10;
private static final int DELAY = 5;
@Override
public void run() {
for (int i = 0; i<ITERATIONS; i++) {
new ZooPatron(zoo);
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
// nop
}
}
}
}).start();
}
}
public class Main {
public static void main(String... args) {
new ClassPathXmlApplicationContext("/context.xml");
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
There are 0 different animals.
There are 3 different animals.
There are 4 different animals.
There are 4 different animals.
... etc
Run Code Online (Sandbox Code Playgroud)
基本上答案是:不,你不能保证@PostConstruct
调用的顺序,不要在"外部"Spring或修改其行为.
这里真正的问题不是我想要对@PostConstruct
调用进行排序,这仅仅是错误表达依赖关系的症状.
如果消费者Zoo
依赖他,Zoo
反过来依赖于Animal
s,一切都正常.我的错误是我不想Zoo
依赖于明确的Animal
子类列表,因此引入了这种注册方法.正如答案中指出的那样,将自注册机制与依赖注入相结合将永远不会有不必要的复杂性.
答案是声明Zoo
依赖于一个集合的Animal
S,然后让春天来填充通过自动装配的集合.
因此,没有硬件列表的集合成员,它们是由Spring发现的,但依赖关系是正确表达的,因此@PostConstruct
方法按我想要的顺序发生.
谢谢你的出色答案.
相反,您可以将动物组@Inject
放入动物园。
@Component
public class Zoo {
@Inject
private Set<Animal> animals = new HashSet<Animal>();
// ...
}
Run Code Online (Sandbox Code Playgroud)
@PostConstruct
然后,只有在注射完所有动物后才应调用动物园。唯一的问题是系统中必须至少有一种动物,但这听起来不应该是一个问题。
归档时间: |
|
查看次数: |
16083 次 |
最近记录: |