spring在运行时从属性中选择bean实现

eivnm1vs  于 2021-08-25  发布在  Java
关注(0)|答案(3)|浏览(364)

我知道这个问题几乎和这个答案中解决的问题一样,但它对我不起作用,我的设置也有点不同。
我想在foorepository接口的两种实现之间进行选择。为此,我创建了repositorymanager配置。理论上,由于排除条件,在运行时应该只存在一个bean。
在所有情况下 "postgres.active" 属性设置为false。

@Configuration
public class RepositoryManager {

   @Bean(name = "repositoryQualifier")
   @ConditionalOnProperty(
           value="postgres.active",
           havingValue = "true")
   public FooRepository managedRepository(PostgresRepository postgresRepository){
       return postgresRepository;
   }

   @Bean(name = "repositoryQualifier")
   @ConditionalOnProperty(
           value="postgres.active",
           havingValue = "false")
   public FooRepository managedRepository(RedisRepository redisRepository){
       return  redisRepository;
   }
}
@RestController
public class BarService{

    private final FooRepository repository;

    @Autowired
    public BarService(
            @Qualifier("repositoryQualifier") final FooRepository repository,
    ) {
        this.repository = repository;
    }
}

当我尝试运行此示例时,spring抛出以下错误:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying
bean of type 'org.test.FooRepository' available: expected 
at least 1 bean which qualifies as autowire candidate. Dependency annotations: 
{@org.springframework.beans.factory.annotation.Qualifier(value="repositoryQualifier")

如果我对其中一个bean进行注解,并从未注解的bean中删除该条件,它将找到该bean,因此在定位包或bean时不应该出现问题。我绝望了,我已经挣扎了6个小时了

vc6uscn9

vc6uscn91#

PostgresRepositoryRedisRepository 是或实现的子类 FooRepository 对吧??请尝试一下,如果它没有在 @Bean 注解-它也可以作为一个选项使用 @ConditionalOnExpression 相反,但ofc您的方式基本上也可以正常工作,例如:

@Configuration
public class RepositoryManager {

   @Bean
   @ConditionalOnExpression("${postgres.active}")
   public FooRepository managedRepository(PostgresRepository postgresRepository){
       return postgresRepository;
   }

   @Bean
   @ConditionalOnExpression("!${postgres.active}")
   public FooRepository managedRepository(RedisRepository redisRepository){
       return  redisRepository;
   }
}

@RestController
public class BarService{

    private final FooRepository repository;

    @Autowired
    public BarService(final FooRepository repository,
    ) {
        this.repository = repository;
    }
}
e37o9pze

e37o9pze2#

可以尝试使用bean名称:

@Autowired
    public BarService(@Qualifier("repositoryQualifier") FooRepository managedRepository) {
repository = managedRepository;
}

另外,为什么两个方法使用相同的限定符名称?请尝试更改第二个方法的名称。

qni6mghb

qni6mghb3#

作为您可以使用的选项 @ConditionalOnProperty 在您的组件上方,例如:

@Repository
@ConditionalOnProperty(value = "postgres.active", havingValue = "true")
public class PostgresRepository implements FooRepository {

    @Override
    public void save() {
        System.out.println("PostgresRepository saving...");
    }
}

@Repository
@ConditionalOnProperty(value = "postgres.active", havingValue = "false")
public class RedisRepository implements FooRepository {

    @Override
    public void save() {
        System.out.println("RedisRepository saving...");
    }
}

然后在控制器中简单地使用它:

@RestController
public class ConditionalController {

    private final FooRepository fooRepository;

    public ConditionalController(FooRepository fooRepository) {
        this.fooRepository = fooRepository;
    }

    @Autowired
    private ApplicationContext applicationContext;

    @GetMapping("/check-conditional-on-property")
    public void test() {

        fooRepository.save();

        boolean isPosRepoInContext = applicationContext.containsBean("postgresRepository");
        boolean isRedRepoInContext = applicationContext.containsBean("redisRepository");

        System.out.println("Is postgresRepository in context: " + isPosRepoInContext);
        System.out.println("Is redisRepository in context:  " + isRedRepoInContext);
    }
}

我认为用相同的bean名称为不同的目的创建两个不同的bean来检查一个bean是否在上下文中不是一个好主意。正如您所看到的,您可以自动连线 ApplicationContext 用于测试目的并进行检查。

相关问题