在 Spring 上下文中使用 LocalDate 并避免 CGLib 问题
Using LocalDate in Spring context and avoid CGLib issue
我有一个用 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 通过一些代理和所有东西做了一些魔术。但是必须有一个简单的方法来实现这一点,对吗?
来自 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 类型的子 class .由于您正在声明类型为 LocalDate
的步骤作用域 bean,它是最终的 class,Spring(批处理)无法创建代理,因此出现错误。
我没有看到具有步骤范围 LocalDate
bean 的附加值。步骤作用域的 bean 对于来自 step/job 执行上下文的作业参数或属性的后期绑定很有用。但是,如果您真的希望该 bean 具有步进范围,您可以尝试另一种代理模式,例如:
@Scope(value = "step", proxyMode = ScopedProxyMode.DEFAULT)
我有一个用 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 通过一些代理和所有东西做了一些魔术。但是必须有一个简单的方法来实现这一点,对吗?
来自 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 类型的子 class .由于您正在声明类型为 LocalDate
的步骤作用域 bean,它是最终的 class,Spring(批处理)无法创建代理,因此出现错误。
我没有看到具有步骤范围 LocalDate
bean 的附加值。步骤作用域的 bean 对于来自 step/job 执行上下文的作业参数或属性的后期绑定很有用。但是,如果您真的希望该 bean 具有步进范围,您可以尝试另一种代理模式,例如:
@Scope(value = "step", proxyMode = ScopedProxyMode.DEFAULT)