Springboot中使用@Configruation和@Bean一起将Bean注册到ioc容器中,而@Value常用于将yml配置文件中的配置信息注入到类的成员变量中。当@Configruation、@Bean和@Value出现在同一个类中时,@Bean会比@Value先执行,这会导致当@Bean注解的方法中用到@Value注解的成员变量时,无法注入(null)的情况。例如在为Feign创建配置类,以实现Feign的权限验证时,需要将yml文件中的用户名和密码注入到配置类的成员变量中,@Bean注解方法则依赖于用户名和密码产生Bean的实例。

@Configuration
public class FeignConfig implements BeanFactoryPostProcessor {
  @Value("${spring.cloud.config.username}")
  private static String username;

  @Value("${spring.cloud.config.username}")
  private static String password;

  @Bean
  public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
    //这时username和password无法被及时注入
    return new BasicAuthRequestInterceptor(username, password);
  }
}

解决方法

第一种:

直接在@Bean方法的参数上使用@Value注入username和password

@Configuration
public class FeignConfig implements BeanFactoryPostProcessor {


  @Bean
  public BasicAuthRequestInterceptor basicAuthRequestInterceptor(@Value("${spring.cloud.config.username}") String username,
      @Value("${spring.cloud.config.password}") String password) {
    //这时username和password可以注入
    return new BasicAuthRequestInterceptor(username, password);
  }
}

第二种:

重新写一个用户名和密码的类AuthConfig,然后用@AutoWired通过注入AuthConfig的对象来实现用户名和密码的注入,同样要在方法的参数上注入。

@Component
public class AuthConfig {
  @Value("${spring.cloud.config.username}")
  private String username;

  @Value("${spring.cloud.config.password}")
  private String password;

   //...省略getter和setter方法
}

@Configuration
public class FeignConfig implements BeanFactoryPostProcessor {


  @Bean
  public BasicAuthRequestInterceptor basicAuthRequestInterceptor(@Autowired AuthConfig authConfig) {
    return new BasicAuthRequestInterceptor(authConfig.getUsername(), authConfig.getPassword());
  }
}

这两种方法的思路应该都是利用Springboot对依赖关系的解析,当一个类对另一个类有明显依赖关系时,会改变bean加载的优先级?待深入研究

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐