web-dev-qa-db-ja.com

@ControllerクラスのSpring @Valueアノテーションがプロパティファイル内の値に評価されない

私はSpringを初めて使用し、@Controller注釈で注釈されたコントローラ内で@Value("${loginpage.message}")注釈を使用して値を文字列に挿入しようとしていますが、私の文字列の値は文字列"${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

@Value("${loginpage.message}")のようなプロパティファイルにない値に@Value("${notInPropertiesFile}")を変更するたびに例外が発生するため、Springはある時点で値を取得する必要があります。

54
Chris

質問はすでに尋ねられているようです Spring 3.0.5はプロパティから@Valueアノテーションを評価しません

Webアプリのルートコンテキストとサーブレットアプリケーションコンテキストの違いは、Springの混乱の主な原因の1つです。 Spring FrameworkのapplicationContext.xmlとspring-servlet.xmlの違い

@Value javadocから:

@Valueアノテーションの実際の処理はBeanPostProcessorによって実行されることに注意してください

春のドキュメント: から

BeanPostProcessorインターフェースは、コンテナーごとにスコープされます。これは、コンテナ階層を使用している場合にのみ関係します。 1つのコンテナでBeanPostProcessorを定義すると、そのコンテナ内のBeanに対してのみ処理が行われます。 1つのコンテナで定義されたBeanは、両方のコンテナが同じ階層の一部であっても、別のコンテナのBeanPostProcessorによって後処理されません。

66
Boris Treukhov

はい、Spring 3でも同じ問題があります。Controllers内では動作しないようです。この問題を解決するために、@ Serviceで別のBeanを作成し、それをコントローラーに挿入しました。うまくいきました。私がそれを理解するために一日中過ごしたので、これが誰かに役立つことを願っています。

7

_@Autowire Environment_を実行してからenvironment.getProperty("name")を実行できます。 https://stackoverflow.com/a/15562319/63229 を参照してください

3
jediz

プロパティファイルから値を抽出できるため、@ Valueアノテーションを使用している場合は、PropertySourcePlaceHolderを使用する必要があります。 Java config baseを使用している場合、このようなBeanを作成する必要があります

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

または、xmlベースを使用している場合は、それに応じてBeanを宣言します。

2
AbdusSalam

私は私の春のプロジェクトで同様の問題を抱えていましたが、具体的には春のバッチの問題でした。私は最初に次のように設定を構築しました

@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();
}

...

理由:BatchConfigのBeanアノテーション(decider()の1つ)にMyDecider構造を近づけて、application.property値で見つかった値を使用してMyDeciderを適切に挿入する必要があることをspringに理解させ、ワイヤードTaskSchedulerを使用します(SpringSchedulerのアクティブ化も試みましたが、jar開始オプションが「送信」の場合はオフにしたかったため)。

注:オプションmode = "send"を使用すると、Spring BatchジョブはstepMultiPollingではなくstepMultiに移行します。これは、MyDeciderの終了ステータスがSENDであり、ポーリングではないためです。しかし、これはこのトピックの単なる説明なので、詳細は省略します。

この春のバッチケースが誰かに役立つことを願っています!

0