私はこれを解決したと思います!
次のことを考慮してください。
public interface Ambiguity {
public boolean isSatisfiedBy(BeanDefinitionHolder holder);
}
@Target({ METHOD, CONSTRUCTOR, FIELD })
@Retention(RUNTIME)
public @interface Ambiguous {
Class<? extends Ambiguity> value();
}
@Target(TYPE)
@Retention(RUNTIME)
public @interface Environmental {
public static enum Environment {
Development, Testing, Production
};
Environment[] value() default {};
}
@Named
public class EnvironmentalAmbiguity implements Ambiguity {
/* This can be set via a property in applicationContext.xml, which Spring
can use place holder, environment variable, etc. */
Environment env = Environment.Development;
@Override
public boolean isSatisfiedBy(BeanDefinitionHolder holder) {
BeanDefinition bd = holder.getBeanDefinition();
RootBeanDefinition rbd = (RootBeanDefinition) bd;
Class<?> bc = rbd.getBeanClass();
Environmental env = bc.getAnnotation(Environmental.class);
return (env == null) ? false : hasCorrectValue(env);
}
private boolean hasCorrectValue(Environmental e) {
for (Environment env : e.value()) {
if (env.equals(this.env)) {
return true;
}
}
return false;
}
}
@Named
public class MySuperDuperBeanFactoryPostProcessor implements
BeanFactoryPostProcessor, AutowireCandidateResolver {
private DefaultListableBeanFactory beanFactory;
private AutowireCandidateResolver defaultResolver;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg)
throws BeansException {
if (arg instanceof DefaultListableBeanFactory) {
beanFactory = (DefaultListableBeanFactory) arg;
defaultResolver = beanFactory.getAutowireCandidateResolver();
beanFactory.setAutowireCandidateResolver(this);
return;
}
throw new FatalBeanException(
"BeanFactory was not a DefaultListableBeanFactory");
}
@Override
public Object getSuggestedValue(DependencyDescriptor descriptor) {
return defaultResolver.getSuggestedValue(descriptor);
}
@Override
public boolean isAutowireCandidate(BeanDefinitionHolder holder,
DependencyDescriptor descriptor) {
Ambiguity ambiguity = getAmbiguity(descriptor);
if (ambiguity == null) {
return defaultResolver.isAutowireCandidate(holder, descriptor);
}
return ambiguity.isSatisfiedBy(holder);
}
private Ambiguity getAmbiguity(DependencyDescriptor descriptor) {
Ambiguous ambiguous = getAmbiguousAnnotation(descriptor);
if (ambiguous == null) {
return null;
}
Class<? extends Ambiguity> ambiguityClass = ambiguous.value();
return beanFactory.getBean(ambiguityClass);
}
private Ambiguous getAmbiguousAnnotation(DependencyDescriptor descriptor) {
Field field = descriptor.getField();
if (field == null) {
MethodParameter methodParameter = descriptor.getMethodParameter();
if (methodParameter == null) {
return null;
}
return methodParameter.getParameterAnnotation(Ambiguous.class);
}
return field.getAnnotation(Ambiguous.class);
}
}
ここで、インターフェイスMyInterfaceと、それを実装する2つのクラスがある場合、次のようにMyFooInterfaceとMyBarInterfaceを実行します。
public interface MyInterface {
public String getMessage();
}
@Named
@Environmental({ Environment.Testing, Environment.Production })
public class MyTestProdInterface implements MyInterface {
@Override
public String getMessage() {
return "I don't always test my code, but when I do, I do it in production!";
}
}
@Named
@Environmental(Environment.Development)
public class DevelopmentMyInterface implements MyInterface {
@Override
public String getMessage() {
return "Developers, developers, developers, developers!";
}
}
@Inject MyInterfaceを実行したい場合、予想されるのと同じ複数のBean定義エラーが発生します。しかし、@ Ambiguous(EnvironmentalAmbiguity.class)を追加すると、EnvironmentalAmbiguityは、どのBean定義が満たされているかを示します。
別のアプローチは、リストを使用して、それらすべてを調べて、特定のBean定義に満足しているかどうかを確認することでした。これは、依存関係に@Ambiguousアノテーションが必要ないことを意味します。それはもっと「IoCっぽい」かもしれませんが、私はそれがうまく機能しないかもしれないと思いました。私はそれをテストしていません。