@Controller类中的Spring @Value注释不评估属性文件中的值

时间:2012-08-09 19:24:57

标签: spring properties

我是Spring的新手,并尝试使用注释为@Value("${loginpage.message}")注释的控制器内的@Controller注释注入一个带有值的字符串,并且我的字符串的值被评估为字符串"${loginpage.message}"而不是我的属性文件中的内容。

下面是我想要注入字符串'message'的控制器。

@Controller
public class LoginController extends BaseController {
    @Value("${loginpage.message}")
    private String message;

    @RequestMapping("/")
    public String goToLoginPage(Model model) {
        model.addAttribute("message", message);

        return "/login";
    }
}

我的应用程序上下文如下所示:

<context:property-placeholder location="classpath:properties/application.properties" />

<context:annotation-config />

<context:component-scan base-package="com.me.application" />

我的属性文件包含以下行:

loginpage.message=this is a test message

Spring必须在某个时刻获取值,因为每当我将@Value("${loginpage.message}")更改为不在@Value("${notInPropertiesFile}")之类的属性文件中的值时,我都会遇到异常。

5 个答案:

答案 0 :(得分:65)

似乎问题已经被问到Spring 3.0.5 doesn't evaluate @Value annotation from properties

Web应用程序根目录和servlet应用程序上下文之间的区别是Spring中混淆的主要原因之一,请参阅Difference between applicationContext.xml and spring-servlet.xml in Spring Framework

来自@Value javadoc:

  

注意@Value注释的实际处理由a执行   的BeanPostProcessor

来自Spring documentation:

  

BeanPostProcessor接口的范围是每个容器。这仅在您使用容器层次结构时才有意义。如果在一个容器中定义BeanPostProcessor,它将只对该容器中的bean执行操作。在一个容器中定义的Bean不会被另一个容器中的BeanPostProcessor进行后处理,即使两个容器都属于同一层次结构。

答案 1 :(得分:7)

是的,我遇到了与Spring 3相同的问题。它似乎不适用于Controllers。 为了解决这个问题,我用@Service创建了另一个bean并将其注入控制器。 它对我有用。希望这会对某人有所帮助,因为我花了一整天时间来弄明白。

答案 2 :(得分:3)

您可以@Autowire Environment然后environment.getProperty("name")。 见https://stackoverflow.com/a/15562319/632293

答案 3 :(得分:1)

如果使用@Value注释,则需要使用PropertySourcePlaceHolder,因为它可以从属性文件中提取值。如果您使用的是java配置库,则需要创建一个像这样的bean

@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
    return new PropertySourcesPlaceholderConfigurer();
}

或者,如果您使用的是基于xml,则相应地声明bean。

答案 4 :(得分:0)

我的春季项目有类似的问题,但特别是春季BATCH。我最初建立了如下配置

@Configuration
public class BatchConfig   
{
  @Bean
  public Job job(@Autowired Step stepMulti, @Autowired Step stepMultiDiff,  @Autowired Step stepMultiPolling
        ){

    Job job = jobBuilders.get("job")
                .start(init0())
                    .on("POLLING").to(stepMultiPolling)
                .from(init0()).on("*").to(stepMulti).next(stepMultiDiff).end()
                .build();
    return job;
  }

  @Bean
  public Step init0(){
    return stepBuilders.get("init0")
            .tasklet(new MyDecider())
            .build();
  }

  ...
}

使用MyDecider,如下所示

public class MyDecider implements StepExecutionListener , Tasklet{ 

  @Autowired ThreadPoolTaskScheduler taskScheduler;
  @Value("${read.chunk.size}") private Integer pagesize;

@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
    return RepeatStatus.FINISHED;
}

@Override
public ExitStatus afterStep(StepExecution exe) {
    String type = exe.getJobParameters().getString("mode");

    log.info("SPRING BATCH props:");
    log.info("    READ chunk size:  {}", pagesize);


    if (StringUtils.equals(type, "send")) {
        log.info("MODE batch SENDING...");

        if (taskScheduler !=null) taskScheduler.shutdown();
        else log.info("      Not able to stop scheduler (is null)");

        return new ExitStatus("SEND");
    } else  {
        log.info("MODE batch POLLING...");
        return new ExitStatus("POLLING");
    } 

}

但是通过这种方式,taskScheduler既没有连线,也没有注入页面大小;都是空的。感谢Boris回答,经过一番尝试后,我将BatchConfig更改为完全正常工作

...

@Bean
public Step init0(){
    return stepBuilders.get("init0")
            .tasklet(decider())
            .build();
}

@Bean
public Tasklet decider() {
    return new MyDecider();
}

...

原因:让MyDecider构造更接近BatchConfig中的Bean注释( decider()之一),让Spring知道必须正确注入MyDecider,并在application.property值中找到值,并使用了TaskScheduler(因为我也尝试过激活SpringScheduler,但是如果jar启动选项是'send',我想把它关掉)。

注意:使用选项模式=“发送”弹出批处理作业采用stepMulti而不是stepMultiPolling,因为MyDecider退出状态是SEND而不是POLLING;但这只是本主题的解释,所以我跳过了进一步的细节。

希望这个春季批案可以对某人有所帮助!