0

編集: おそらく、この質問をするためのより簡潔な方法は次のとおりです。Springは、独自のリスナー/ファクトリ/決定ロジックを提供することにより、注入時にあいまいな候補を解決する方法を提供しますか?


実際、おそらく、以下のメンバーフィールドの@Environmental修飾子は不要です。@Inject-ionがあいまいな場合...助けてください。実際、@ ResolveWith(EnvironmentalResolver.class)も大丈夫です。


Springが(アノテーションを使用して)依存性を注入しようとすると、そのインターフェイスを実装する複数のコンポーネントがある場合は、@Injectポイントを@Qualifierする必要があることを理解しています。

私がやりたいのは次のようなものです。

class MyFoo implements Foo {
    @Inject
    @Environmental
    private Bar bar;
}

@Environmental(Environment.Production)
class ProductionBar implements Bar {
}

@Environmental({Environment.Dev, Environment.Test})
class DevAndTestBar implements Bar {
}

私は、次のように(漠然と)見えるような、ある種のあいまいさの解決策を作成する必要があると思います。

class EnvironmentalBeanAmbiguityResolver {

    // set from configuration, read as a system environment variable, etc.
    private Environment currentEnvironment;

    public boolean canResolve(Object beanDefinition) {
        // true if definition has the @Environmental annotation on it
    }

    public Object resolve(Collection<Object> beans) {
        for (Object bean : beans) {
            // return bean if bean @Environmental.values[] contains currentEnvironment
        }
        throw new RuntimeException(...);
    }
}

これが役立つ例の1つは、エンドユーザーに連絡するサービスがあることです。今、私はAOPアスペクトをハックして、「MailSender」へのメソッド呼び出しの前に「Production」環境フラグをチェックし、設定されていない場合は、ユーザーの電子メールではなく電子メールを送信します。これをメール送信に固有のAOPアスペクトでラップする代わりに、現在の環境に基づいてサービスを区別できるようにします。上記で示したように、「本番」または「非本番」の問題である場合もあります。ただし、環境ごとの定義も機能します。

これはリージョンにも再利用できると思います...たとえば、@ Regionや@Regional(Region.UnitedStates)などです。

@Environmentalは実際には@Qualifierになると思いますが、環境に直接依存したい場合は(@Environmental(Production)Beanは@Environmental(Production)コラボレーターに直接依存する可能性が高いため、あいまいさはありません。下位レベルのアイテム---同じ@Regional(US)アイテムは、他の@Regional(US)アイテムに明示的に依存し、まだ理解されていないBeanAmbiguityResolverをバイパスします)

ありがとう。

4

1 に答える 1

0

私はこれを解決したと思います!

次のことを考慮してください。

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っぽい」かもしれませんが、私はそれがうまく機能しないかもしれないと思いました。私はそれをテストしていません。

于 2011-09-22T22:31:34.843 に答える