alibaba / jetcache

JetCache is a Java cache framework.
Apache License 2.0
5.15k stars 1.06k forks source link

key获取method.name报错 #407

Open BertOnline opened 4 years ago

BertOnline commented 4 years ago

2019-12-04 17:48:35.562 ERROR [http-nio-9000-exec-1] com.alicp.jetcache.anno.method.ExpressionUtil - error occurs when eval key "method.name" in public java.util.List mp.rec.gambling.web.cache.baseInfo.LeagueCache.getJcSportTypeList():EL1072E: An exception occurred whilst evaluating a compiled expression org.springframework.expression.spel.SpelEvaluationException: EL1072E: An exception occurred whilst evaluating a compiled expression at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:259) at com.alicp.jetcache.anno.method.SpelEvaluator.apply(ExpressionEvaluator.java:136) at com.alicp.jetcache.anno.method.ExpressionEvaluator.apply(ExpressionEvaluator.java:70) at com.alicp.jetcache.anno.method.ExpressionUtil.lambda$evalKey$5(ExpressionUtil.java:69) at com.alicp.jetcache.anno.method.ExpressionUtil.evalKey(ExpressionUtil.java:72) at com.alicp.jetcache.anno.method.CacheHandler.invokeWithCached(CacheHandler.java:223) at com.alicp.jetcache.anno.method.CacheHandler.doInvoke(CacheHandler.java:93) at com.alicp.jetcache.anno.method.CacheHandler.invoke(CacheHandler.java:85) at com.alicp.jetcache.anno.aop.JetCacheInterceptor.invoke(JetCacheInterceptor.java:80) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) at mp.rec.gambling.web.cache.baseInfo.LeagueCache$$EnhancerBySpringCGLIB$$9b5ef26f.getJcSportTypeList() at mp.rec.gambling.web.controller.BaseInfoController.getSportTypeList(BaseInfoController.java:45) at mp.rec.gambling.web.controller.BaseInfoController$$FastClassBySpringCGLIB$$b98bff33.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88) at mp.rec.gambling.web.aspect.LogAspect.printCostTimeAndReturn(LogAspect.java:49) at mp.rec.gambling.web.aspect.LogAspect.printCostTimeAndReturn(LogAspect.java:31) at mp.rec.gambling.web.aspect.ControllerLogAspect.logDefaultFeignApiCallInfo(ControllerLogAspect.java:35) at sun.reflect.GeneratedMethodAccessor303.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633) at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) at mp.rec.gambling.web.controller.BaseInfoController$$EnhancerBySpringCGLIB$$60e907b2.getSportTypeList() at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:678) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.IncompatibleClassChangeError: Found interface java.lang.reflect.Member, but class was expected at spel.Ex6.getValue(Unknown Source) at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:249) ... 74 common frames omitted

areyouok commented 4 years ago

信息不完整,你怎么写的,可能spel处理不了这种写法

BertOnline commented 4 years ago

image 偶发性的复现

areyouok commented 4 years ago

method.name改成method.name试试

具体代码你可以看SpelEvaluator,rootObject是CacheInvokeContext

chenxiaolei commented 4 years ago

也掉这个坑了,找了半天原因,终于找到问题的出处了

具体就是SpelCompilerMode的问题

SpelCompilerMode

OFF-编译器关闭;默认是关闭的
IMMEDIATE-即时生效模式,表达式会尽快的被编译。基本是在第一次求值后马上就会执行。如果编译表达式出错(往往都是因为上面提到的类型发生改变的情况)则表达式求值的调用点会抛出异常。
MIXED-混合模式,在混合模式中表达式会自动在解释器模式和编译器模式之间切换。在发生了几次解释处理后会切换到编译模式,如果编译模式哪里出错了(像上面提到的类型发生变化)则表达式会自动切换回解释器模式。过一段时间如果运用正常又会切换回编译模式。

编译器的局限性

在Srping4.1中基础的编译框架就已经有了。但框架还不支持编译所有类型的表达式。最初的设计初衷主要在于先集中优化比较耗性能且又经常使用的表达式。以下类型的表达式目前还不能被编译:

涉及到赋值的表达式
依赖于转换服务的表达式
使用到自定义解析器或者存取器的表达式
使用到选择器或者投影的表达式

更多类型的表达式将来都会被支持编译
Jetcache代码:

class SpelEvaluator implements Function<Object, Object> {

    private static ExpressionParser parser;
    private static ParameterNameDiscoverer parameterNameDiscoverer;

    static {
        try {
            //since spring 4.1
            Class modeClass = Class.forName("org.springframework.expression.spel.SpelCompilerMode");

            try {
                Constructor<SpelParserConfiguration> c = SpelParserConfiguration.class
                        .getConstructor(modeClass, ClassLoader.class);
                Object mode = modeClass.getField("IMMEOFFDIATE").get(null);
                SpelParserConfiguration config = c.newInstance(mode, SpelEvaluator.class.getClassLoader());
                parser = new SpelExpressionParser(config);
            } catch (Exception e) {
                throw new CacheException(e);
            }
        } catch (ClassNotFoundException e) {
            parser = new SpelExpressionParser();
        }
        parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
    }
    ...
}

把上面的IMMEOFFDIATE修改为OFF可解决此问题

...
重现如下:

public interface IEntity extends Serializable {
    Long getPrimaryKeyValue();
}

@Data
public Class Entity implements IEntity{
    private Long id;
    ...

    public Long getPrimaryKeyValue(){
        return id;
    }
}

@CacheInvalidate(key = "#entity.primaryKeyValue")
int updateEntity(Entity entity)

调用几次等SPEL使用编译器来解析就可以看到IncompatibleClassChangeError异常了
areyouok commented 4 years ago

@chenxiaolei 非常感谢你提供的信息