简体   繁体   English

如何在Spring中按条件提供默认bean?

[英]How to provide a default bean in Spring by condition?

I'd like to provide a default bean by a custom jar. 我想通过自定义jar提供一个默认bean。 Only if the user implements a specific abstract class the default bean injection should be skipped. 仅当用户实现特定的abstract类时,才应跳过默认的bean注入。

The following setup already works fine, except one thing: any injected classes within the default wired class are null ! 以下设置已经正常工作,除了一件事: default有线类中的任何注入类都是null What might I be missing? 我可能会失踪什么?

@Configration
public class AppConfig {
    //use the default service if the user does not provide an own implementation
    @Bean
    @Conditional(MissingServiceBean.class)
    public MyService myService() {
        return new MyService() {};
    }
}


@Component
public abstract class MyService {
    @Autowired
    private SomeOtherService other;

    //default impl of the method, that may be overridden
    public void run() {
        System.out.println(other); //null! Why?
    }
}

public class MissingServiceBean implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getBeanFactory().getBeansOfType(MyService.class).isEmpty();
    }
}

The MyService bean is created and can also be injected. MyService bean已创建,也可以注入。 But contained classes are null. 但是包含的类是null。

If I remove the @Conditioanl annotation everything works as expected. 如果我删除@Conditioanl注释,一切都按预期工作。

Your simplest possibility is the usage of the @Primary annotation. 最简单的可能性是使用@Primary注释。 You define your interface/abstract class and build a default implementation. 您可以定义接口/抽象类并构建默认实现。 Until here thats the basic spring autowiring. 直到这里,这是基本的春天自动装配。

Now you create another implementation with @Primary and make it available in the application context. 现在,您使用@Primary创建另一个实现,并使其在应用程序上下文中可用。 Spring will now pick up the primary implementation for the autowiring. Spring现在将获得自动装配的主要实现。


Another possibilty in Spring 4.1+ would be to autowire an ordered List<Intf> and ask the interface with a supports(...) call to fetch the current implementation for whatever parameter you give into supports . Spring 4.1+中的另一个可能性是自动装配一个有序的List<Intf>并询问接口是否有一个supports(...)调用来获取当前实现,无论你给supports什么参数。 You give the default implementation a low priority and the more detailed ones a higher priority. 您将默认实现设置为low priority ,将更详细的实现设置为更高优先级。 Like this you can even build a more detailed default behavior. 像这样,您甚至可以构建更详细的默认行为。 I'm using this approach for several configurations to handle different classes with default and specific implementations. 我正在使用这种方法进行多种配置来处理具有默认和特定实现的不同类。

One example would be during permission evaluation where we have a default config for the base classes, another higher one for domain classes, and a even higher possible one for specific domain entities. 一个例子是在权限评估期间,我们有基类的默认配置,域类的另一个更高的配置,以及特定域实体的更高可能配置。 The permission evaluator goes through the list and checks each implementation if it supports that class and delegates to the implementation in that case. 权限评估程序遍历列表并检查每个实现是否支持该类,并在该情况下委托实现。

I dont have the code here but i could share it later if desired to make that more clear. 我没有这里的代码,但我可以稍后分享,如果希望更清楚。

Change your code to the following: 将您的代码更改为以下内容:

public abstract class MyService {

    private final SomeOtherService other;

    public MyService(SomeOtherService other) {
       this.other = other;
    }

    //default impl of the method, that may be overridden
    public void run() {
        System.out.println(other);
    }
}

@Configration
public class AppConfig {

    @Autowired
    private SomeOtherService other;

    //use the default service if the user does not provide an own implementation
    @Bean
    @Condition(MissingServiceBean.class)
    public MyService myService() {
        return new MyService(other) {};
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM