首页 > 解决方案 > 在 Spring 上下文中使用 LocalDate 并避免 CGLib 问题

问题描述

我有一份用 Spring Boot Batch 2.2.2 编写的小作业。它需要一个日期作为参数,并且由于几个组件需要该日期,我将它作为一个 bean 放置在 Spring 上下文中:

@Bean
@StepScope
public Date processingDate(){
if(isEmpty(applicationArguments.getSourceArgs())){
  throw new IllegalArgumentException("No parameter received - expecting a date to be passed as a command line parameter.");
}

SimpleDateFormat sdf = new SimpleDateFormat(EXPECTED_DATE_FORMAT);
String expectedDateFromCommandLine=applicationArguments.getSourceArgs()[0];

try {

  return sdf.parse(expectedDateFromCommandLine);

} catch (ParseException e) {
  throw new IllegalArgumentException("Expecting the parameter date to have this format : "+ EXPECTED_DATE_FORMAT,e);
}
}

它运作良好,没有问题。

现在我正在做一些重构,并认为我应该使用 LocalDate 而不是 Date,因为现在从 Java 8 开始推荐它。

@Bean
@StepScope
public LocalDate processingDate(){

    if(isEmpty(applicationArguments.getSourceArgs())){
        throw new IllegalArgumentException("No parameter received - expecting a date to be passed as a command line parameter.");
    }

    String expectedDateFromCommandLine=applicationArguments.getSourceArgs()[0];

    return LocalDate.parse(expectedDateFromCommandLine, DateTimeFormatter.ofPattern(EXPECTED_DATE_FORMAT));

}

但是,Spring 不喜欢它:

Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class java.time.LocalDate: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class java.time.LocalDate
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:208)

我知道在幕后,Spring 用一些代理和所有的东西做了一些魔法。但是必须有一种简单的方法来实现这一切,对吧?

标签: javaspring-bootspring-batch

解决方案


来自StepScope的 Javadoc :

Marking a @Bean as @StepScope is equivalent to marking it as @Scope(value="step", proxyMode=TARGET_CLASS)

现在代理模式TARGET_CLASS意味着代理将是 CGLIB 代理(请参阅ScopedProxyMode#TARGET_CLASS),这意味着将为代理创建 bean 类型的子类。由于您声明了一个类型LocalDate为最终类的步骤范围 bean,因此 Spring(Batch)无法创建代理,因此出现错误。

LocalDate我看不到有一个 step 作用域bean的附加值。步骤范围 bean 对于后期绑定来自步骤/作业执行上下文的作业参数或属性很有用。但是,如果您真的希望该 bean 具有步进范围,您可以尝试另一种代理模式,例如:

@Scope(value = "step", proxyMode = ScopedProxyMode.DEFAULT)

推荐阅读