【问题标题】:SpelEvaluationException: Attempted to call method on null context objectSpelEvaluationException:试图在空上下文对象上调用方法
【发布时间】:2021-09-03 07:04:39
【问题描述】:

我正在尝试做一个简单的缓存任务。我有一个Holiday 对象,它有两个字段:referenceDateisHoliday。然后,我有一个方法可以向 rest api 发出 HTTP 请求,以检查日期是否为假期。我想要实现的是:如果当前缓存的Holiday 对象与作为参数传递的对象具有相同的referenceDate,则返回缓存的值。我有一个特定的类来执行该检查。代码如下:

假期班

@AllArgsConstructor
@Getter
public class Holiday {
    public LocalDate referenceDate;
    public boolean isHoliday;
}

CacheService 类

@DomainService
public class CacheService {

    @Autowired
    private CacheManager cacheManager;

    public boolean isReferenceDateCached(final LocalDate referenceDate){
        final Holiday holiday = (Holiday) cacheManager.getCache("holiday").get("holidaycheck");
        return(holiday.getReferenceDate().equals(referenceDate));
    }
}

HolidatInfraService 类

@AllArgsConstructor
@Service
@Slf4j
public class HolidayInfraService {

    @Autowired
    private final CacheService cacheService;

    @Cacheable(value = "holiday", key = "holidaycheck", condition = "#cacheService.isReferenceDateCached(#holidayDateToCheck)")
    public Holiday isHoliday(final LocalDate holidayDateToCheck) {
        //some code to call a rest api
    }

}

这是我在尝试holidayInfraService.isHoliday(someDate) 时从单元测试中得到的错误:

org.springframework.expression.spel.SpelEvaluationException: EL1011E: Method call: Attempted to call method isReferenceDateCached(java.time.LocalDate) on null context object

从这个异常消息看来,cacheService 是空的。但是,当我调试代码并进入isHoliday 时,cacheService 不为空。也许注释运行时它还没有自动装配?这也是我第一次与 SPEL 合作,所以也许那里也有一些东西。如果事实上cacheService 还没有自动连接,是否有解决方法?

【问题讨论】:

    标签: spring spring-boot java-11 spring-el


    【解决方案1】:

    试试

    @Cacheable(value = "holiday", key = "holidaycheck", condition = "#{cacheService.isReferenceDateCached(#holidayDateToCheck)}")
    public Holiday isHoliday(final LocalDate holidayDateToCheck) {
        //some code to call a rest api
    }
    

    【讨论】:

      【解决方案2】:

      因为您使用的是 @Cacheable(...) 注释,所以 Spring 将使用上下文类 MethodBasedEvaluationContext 评估该 SpEL 表达式。这会将根对象设置为CacheExpressionRootObject,并将使用该根对象执行属性查找。

      由于您试图引用 bean 上的属性,最简单的解决方案是直接在 SpEL 表达式中引用该 bean。这是通过@(例如@myBeanName)完成的。然后 Spring 将在 ApplicationContext 中查找具有该名称的 bean。请记住,没有明确名称定义的 bean 将使用类名的较低驼峰式命名。例如,名称为 MyBeanName 的类将具有 myBeanName 的 bean 名称。

      尝试将您的 condition= 块更改为

      @Cacheable(value = "holiday", key = "holidaycheck", condition = "@cacheService.isReferenceDateCached(#holidayDateToCheck)")
      public Holiday isHoliday(final LocalDate holidayDateToCheck) {
          //some code to call a rest api
      }
      

      【讨论】:

      • Ben,这导致了另一个错误:org.springframework.expression.spel.SpelEvaluationException:EL1008E:在“org.springframework.cache.interceptor”类型的对象上找不到属性或字段“cacheService”。 CacheExpressionRootObject' - 可能不公开或无效?收到此错误后,我尝试将变量设置为 public 修饰符,但没有任何改变
      • @William 好的,我担心这也会发生。当您使用@PreAuthorize 尝试类似的事情时,就会发生这种情况。您是否尝试过直接引用 CacheService bean?试试condition = "@CacheService.isReferenceDateCached(#holidayDateToCheck)。这将在 ApplicationContext 中查找 bean 并使用它。
      • @William 我编辑了我的答案以使用 bean 参考策略
      • 非常感谢!就是这样。我将进一步研究运算符#、{、@ 等等...谢谢!
      【解决方案3】:

      在SpEL的MethodBasedEvaluationContext中访问方法变量,需要使用#,但是类变量不需要#。属性查找将自动查找不带 # 符号的属性的 getter。所以,你的 SpEL 应该是

      cacheService.isReferenceDateCached(#holidayDateToCheck)
      

      如果此 SpEL 不起作用,请尝试为 cacheService 创建 getter 方法。

      【讨论】:

      • 嗨,Geobreze。您的回答也导致了关于修饰符的不同错误。这是我在尝试您的解决方案时遇到的异常:org.springframework.expression.spel.SpelEvaluationException:EL1008E:在“org.springframework.cache.interceptor.CacheExpressionRootObject”类型的对象上找不到属性或字段“cacheService” - 可能不公开还是无效?
      • 你试过添加getCacheService公共方法吗?
      猜你喜欢
      • 2023-01-16
      • 2017-03-02
      • 2016-09-21
      • 2017-07-15
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多