Spring Boot中@Autowired的配置属性为空

8
我有一个属性类。
@ConfigurationProperties(prefix = ShiroProperties.SHIRO_PREFIX)
public class ShiroProperties {
  public static final String SHIRO_PREFIX = "shiro";

  private String urlLogin;
  private String urlSuccessed;

和一个配置类

@Configuration
@EnableConfigurationProperties({ ShiroProperties.class })
public class ShiroConfig implements ApplicationContextAware {

  ApplicationContext applicationContext;
  @Autowired
  private ShiroProperties shiroProperties ;

shiroProperties为空,但我可以在ShiroConfig中找到其值

applicationContext.getBean(ShiroProperties.class)

我的Application类:

@SpringBootApplication
public class Bootstrap {
  public static void main(String[] args) {
    SpringApplication.run(Bootstrap.class, args);
  }
}

很奇怪,我在其他项目中使用类似的代码可以成功运行,但是在这个项目中却不行。


我不确定,但我认为你应该根据Spring Boot Externalized Configuration Documentation@Component 添加到 ShiroProperties. - Mickael
我之前看过,也试过了,但不起作用。无论如何,谢谢。 - Dean
我找到了这个奇怪问题的原因,如果添加了使用@Bean注释的LifecycleBeanPostProcessor类,则@Autowired将无法正常工作。LifecycleBeanPostProcessor类来自shiro。 - Dean
4个回答

1

我遇到了和@Dean说的同样的问题,我的解决方法是将LifecycleBeanPostProcessor bean放在另一个配置类中,并在另一个配置类中配置其他的Shiro,如下例所示:

@Configuration
public class ShiroLifecycleBeanPostProcessorConfig {

    /**
     * 
     * 
     * @return
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

}

主要的Shiro配置类:
@Configuration
@AutoConfigureAfter(value = ShiroLifecycleBeanPostProcessorConfig.class)
public class ShiroConfiguration {

    public static final String cacheFile = "encache.xml";
    private static final String active_cache_name = "activeSessionCache";

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 
     * 
     * @throws UnknownHostException
     */
    @Bean(name = "shiroFilter")
    @ConditionalOnMissingBean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager)
            throws UnknownHostException {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        shiroFilterFactoryBean.setSecurityManager(securityManager);

        shiroFilterFactoryBean.setLoginUrl(ShiroSecurityUrls.LOGIN_PAGE);
        // shiroFilterFactoryBean.setSuccessUrl(ShiroSecurityUrls.LOGIN_SUCCESS_URL);
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");

        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
        LogoutFilter logoutFilter = new LogoutFilter();
        logoutFilter.setRedirectUrl(ShiroSecurityUrls.LOGIN_PAGE);
        filters.put(DefaultFilter.logout.name(), logoutFilter);
        shiroFilterFactoryBean.setFilters(filters);

        Map<String, String> filterChainDefinitionManager = new LinkedHashMap<String, String>();

        filterChainDefinitionManager.put("/static/**", DefaultFilter.anon.name());
        filterChainDefinitionManager.put("/node_modules/**", DefaultFilter.anon.name());
        filterChainDefinitionManager.put("/pages/**", DefaultFilter.anon.name());

        filterChainDefinitionManager.put(ShiroSecurityUrls.LOGIN_PAGE, DefaultFilter.anon.name());
        filterChainDefinitionManager.put(ShiroSecurityUrls.LOGOUT_URL, DefaultFilter.logout.name());
        filterChainDefinitionManager.put(ShiroSecurityUrls.REGISTER_PROCESS_URL, DefaultFilter.anon.name());
        filterChainDefinitionManager.put("/**", DefaultFilter.user.name());

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);

        return shiroFilterFactoryBean;
    }

    /**
     * 
     * 
     * @throws UnknownHostException
     */
    @Bean(name = "securityManager")
    @DependsOn(value = { "ehCacheManager", "rememberMeManager", "sessionManager", "credentialsMatcher" })
    public DefaultWebSecurityManager securityManager(EhCacheManager ehCacheManager, RememberMeManager rememberMeManager,
            SessionManager sessionManager, CredentialsMatcher credentialsMatcher) throws UnknownHostException {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 1. Cache Support
        securityManager.setCacheManager(ehCacheManager);
        // 2. Session Support,inject the cacheManager from securitymanager
        securityManager.setSessionManager(sessionManager);
        // 3. Rememberme Support
        securityManager.setRememberMeManager(rememberMeManager);

        // 4. JDBC,LDAP Realm implements
        Collection<Realm> authorizingRealms = Lists.newArrayList(shiroDatabaseRealm(credentialsMatcher),
                shiroActiveDirectoryRealm(credentialsMatcher));
        securityManager.setRealms(authorizingRealms); // inject the cacheManager
                                                        // from securitymanager
        if (securityManager.getAuthenticator() instanceof ModularRealmAuthenticator) {
            ModularRealmAuthenticator modularRealmAuthenticator = (ModularRealmAuthenticator) securityManager
                    .getAuthenticator();
            modularRealmAuthenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
        }

        return securityManager;
    }
}

希望这段代码对你有所帮助,谢谢。

你好,感谢你的解决方案。我已经将框架更改为Spring Security,并且我知道实际问题是什么。使用public而不是private修饰的@Autowired属性将成功注入。 - Dean

0
通常情况下,AutowiredAnnotationBeanPostProcessor会在Spring加载FactoryBean类时设置由@Autowired注释的属性。如果以下工厂bean:
  1. ApplicationContextAwareProcessor
  2. ApplicationListenerDetector
  3. ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
  4. PostProcessorRegistrationDelegate$BeanPostProcessorChecker
  5. CommonAnnotationBeanPostProcessor
引用您的配置bean,由于尚未加载 AutowiredAnnotationBeanPostProcessor,因此创建后您的bean将无法进行自动装配。
例如,属性为null并抛出NullPointerException异常。
@Component
public class BeanFactoryTest {

@Autowired
private IdGenProperties properties;

@Bean
public SnowflakeServer snowflakeServer() {
    System.out.println(properties.getBaseUrl());
    return null;
}

@Bean(name = "conversionService")
public ConversionServiceFactoryBean getConversionService() {
    ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
    Set<Converter> converters = new HashSet<>();
    converters.add(new StringToDateConverter());
    bean.setConverters(converters);
    return bean;
}

public static class StringToDateConverter implements Converter<String, Date> 
{
    public Date convert(String source) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            return sdf.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
   }
}

0
这是另一个与您的应用程序相关的配置类,应该使用@Configuration注释进行装饰,以启用bean的创建和注入到上下文中,以便从其他类进行连接。

抱歉,我不明白你的意思。 - Dean
抱歉表述不清。我的意思是更新你的类为`@Configuration @ConfigurationProperties(prefix = ShiroProperties.SHIRO_PREFIX) public class ShiroProperties { public static final String SHIRO_PREFIX = "shiro"; private String urlLogin; private String urlSuccessed;}` - Ashwin Gupta

-1
尝试在您的ShiroProperties.class中添加@Component。
@Component
@ConfigurationProperties(prefix = ShiroProperties.SHIRO_PREFIX)
public class ShiroProperties {
  public static final String SHIRO_PREFIX = "shiro";

  private String urlLogin;
  private String urlSuccessed;
}

谢谢,它不起作用,添加“@Component”会抛出NoUniqueBeanDefinitionException异常,换句话说,“@ConfigurationProperties”已经在Spring上下文中创建了bean。 - Dean
尝试移除applicationContext.getBean(ShiroProperties.class); - Monzurul Shimul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接