58

我是 Spring 的新手,并尝试使用带有@Value("${loginpage.message}")注释的控制器内部的注释来注入带有值的字符串,@Controller并且我的字符串的值被评估为字符串"${loginpage.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}"),我都会遇到异常。

4

6 回答 6

68

似乎已经问过这个问题Spring 3.0.5 不会从属性中评估 @Value 注释

Web 应用程序根和 servlet 应用程序上下文之间的区别是 Spring 中最容易混淆的来源之一,请参阅 Spring Framework 中 applicationContext.xml 和 spring-servlet.xml 之间的区别

@Valuejavadoc :

请注意,@Value 注释的实际处理是由 BeanPostProcessor 执行的

来自Spring 文档:

BeanPostProcessor 接口的范围是每个容器。这仅在您使用容器层次结构时才相关。如果您在一个容器中定义一个 BeanPostProcessor,它只会在该容器中的 bean 上工作。在一个容器中定义的 Bean 不会由另一个容器中的 BeanPostProcessor 进行后处理,即使两个容器是同一层次结构的一部分。

于 2012-08-09T20:24:43.580 回答
7

是的,我在 Spring 3 中遇到了同样的问题。它似乎在控制器中不起作用。为了解决这个问题,我使用 @Service 创建了另一个 bean 并将其注入到控制器中。它确实对我有用。希望这对我花了一整天时间弄清楚的人有所帮助。

于 2013-06-04T09:58:53.100 回答
3

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

于 2016-04-01T16:05:56.907 回答
3

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

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

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

于 2016-10-16T14:22:40.597 回答
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 也没有注入 pagesize ;两者都为空。感谢鲍里斯的回答,经过一番尝试,我将 BatchConfig 更改为以下完美工作

...

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

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

...

原因:让 MyDecider 构造更接近 BatchConfig 中的 Bean 注释( decisionr ()之一),让 spring 明白必须正确注入 MyDecider,在 application.property 值中找到值,并与使用的 TaskScheduler 连接(因为我试过也有 SpringScheduler 激活,但如果 jar 启动选项是“发送”,我想关闭它)。

注意:使用选项 mode="send" 春季批处理作业采用 stepMulti 而不是 stepMultiPolling,因为 MyDecider 退出状态是 SEND 而不是 POLLING;但这只是这个主题的解释,所以我跳过更多细节。

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

于 2017-04-24T10:23:43.377 回答
0

我很抱歉问这个显而易见的问题,但是你怎么知道 @Value 注释不起作用?Spring 工作方式的问题之一是 Bean 的预处理是在构建 Bean 之后进行的。

因此,如果您使用调试器在构造函数中检查 Bean,您将看不到正在设置的字段。您可以在 Bean 中添加一个名为 audit() 的方法,并使用 @PostConstruct 对其进行注释,如果您在其中放置日志语句,在其上放置断点,您应该会看到带有 @Value 值的字段。

如果你这样做了,但你仍然看不到你的 @Value 字段,那么你甚至可能没有扫描过 Bean。你认为实现 Bean 的类仍然是一个 Java 类,它可以被实例化,并且如果它没有被预处理,它的字段将被分配为空。

为了确保您的 Bean 正在被扫描,这些类应该至少具有 @Component,并且您需要将类的包添加到 @ComponentScan。

@ComponentScan(basePackages = { "com.example.springboot", "org.bilbo.baggins" })

如果您没有 main() 方法的源代码,通常可以在其中找到 @ComponentScan,那么您可以在同一个包中添加一个 @Configuration 类,并在其中添加一个 @ComponentScan。

在此示例中,我将 @ComponentScan 作为注释掉的行放在错误的位置(它应该替换 @ImportResources)。

package com.example.springboot;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

// @ComponentScan(basePackages = { "com.example.springboot", "org.bilbo.baggins" })
@Configuration
@ImportResource({"classpath*:applicationContext.xml"})
public class Configurer {
}

我这样做是为了展示如何使用 XML 文件:applicationContext.xml。这包含一个组件扫描并创建一个 Bean。

(注意:声明只扫描一个包,component-scan 似乎是累积的。)

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/sc
hema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/
beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema
/context/spring-context.xsd">

    <context:annotation-config />

    <context:component-scan base-package="org.bilbo.baggins" />
          <bean id="applicationProperties"
                      class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
                    <property name="location" value="classpath:application.properties" />
          </bean>
</beans>

在 XML 文件中构建一个 bean 很有用,这样您就可以列出它并证明您已经加载了 XML 文件。您可以使用该方法列出 beanString[] beanNames = ctx.getBeanDefinitionNames();

于 2021-12-17T19:34:19.490 回答