问题描述:
在JFinal中使用了CacheInterceptor,对一些常用的数据进行缓存。CacheInterceptor使用Ehcache作为底层的缓存实现,Ehcache支持持久化,但是在配置了Ehcache持久化之后,会出现无法序列化的问题。
报错信息:
20:59:46.724 [http-nio-8080-exec-71] ERROR net.sf.ehcache.store.disk.DiskStorageFactory call - Disk Write of /api/v3/works/allActivity failed: java.io.NotSerializableException: org.apache.tomcat.util.net.jsse.JSSESupport at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) ~[?:1.8.0_144] at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) ~[?:1.8.0_144] at java.util.HashMap.internalWriteEntries(HashMap.java:1785) ~[?:1.8.0_144] at java.util.HashMap.writeObject(HashMap.java:1362) ~[?:1.8.0_144] at sun.reflect.GeneratedMethodAccessor1867.invoke(Unknown Source) ~[?:?] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028) ~[?:1.8.0_144] at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496) ~[?:1.8.0_144] at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) ~[?:1.8.0_144] at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) ~[?:1.8.0_144] at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) ~[?:1.8.0_144] at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441) ~[?:1.8.0_144] at net.sf.ehcache.Element.writeObject(Element.java:875) ~[ehcache-2.10.5.jar:2.10.5] at sun.reflect.GeneratedMethodAccessor1871.invoke(Unknown Source) ~[?:?] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028) ~[?:1.8.0_144] at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496) ~[?:1.8.0_144] at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) ~[?:1.8.0_144] at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) ~[?:1.8.0_144] at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) ~[?:1.8.0_144] at net.sf.ehcache.util.MemoryEfficientByteArrayOutputStream.serialize(MemoryEfficientByteArrayOutputStream.java:97) ~[ehcache-2.10.5.jar:2.10.5] at net.sf.ehcache.store.disk.DiskStorageFactory.serializeElement(DiskStorageFactory.java:403) ~[ehcache-2.10.5.jar:2.10.5] at net.sf.ehcache.store.disk.DiskStorageFactory.write(DiskStorageFactory.java:385) ~[ehcache-2.10.5.jar:2.10.5] at net.sf.ehcache.store.disk.DiskStorageFactory$DiskWriteTask.call(DiskStorageFactory.java:477) [ehcache-2.10.5.jar:2.10.5] at net.sf.ehcache.store.disk.DiskStorageFactory$PersistentDiskWriteTask.call(DiskStorageFactory.java:1071) [ehcache-2.10.5.jar:2.10.5] at net.sf.ehcache.store.disk.DiskStorageFactory$IndexWriteTask.call(DiskStorageFactory.java:1108) [ehcache-2.10.5.jar:2.10.5] at net.sf.ehcache.store.disk.DiskStorageFactory.unbind(DiskStorageFactory.java:921) [ehcache-2.10.5.jar:2.10.5] at net.sf.ehcache.store.disk.DiskStore.dispose(DiskStore.java:664) [ehcache-2.10.5.jar:2.10.5] at net.sf.ehcache.store.CacheStore.dispose(CacheStore.java:342) [ehcache-2.10.5.jar:2.10.5] at net.sf.ehcache.Cache.dispose(Cache.java:2588) [ehcache-2.10.5.jar:2.10.5] at net.sf.ehcache.CacheManager.shutdown(CacheManager.java:1548) [ehcache-2.10.5.jar:2.10.5] at com.jfinal.plugin.ehcache.EhCachePlugin.stop(EhCachePlugin.java:95) [jfinal-java8-3.4.jar:?] at com.jfinal.core.JFinal.stopPlugins(JFinal.java:115) [jfinal-java8-3.4.jar:?] at com.jfinal.core.JFinalFilter.destroy(JFinalFilter.java:91) [jfinal-java8-3.4.jar:?] at org.apache.catalina.core.ApplicationFilterConfig.release(ApplicationFilterConfig.java:314) [catalina.jar:9.0.1] at org.apache.catalina.core.StandardContext.filterStop(StandardContext.java:4523) [catalina.jar:9.0.1] at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5319) [catalina.jar:9.0.1] at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:257) [catalina.jar:9.0.1] at org.apache.catalina.core.ContainerBase.removeChild(ContainerBase.java:831) [catalina.jar:9.0.1] at org.apache.catalina.startup.HostConfig.undeploy(HostConfig.java:1427) [catalina.jar:9.0.1] at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1335) [catalina.jar:9.0.1] at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1642) [catalina.jar:9.0.1] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144] at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:287) [tomcat-coyote.jar:9.0.1] at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) [?:1.8.0_144] at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) [?:1.8.0_144] at org.apache.catalina.manager.ManagerServlet.check(ManagerServlet.java:1481) [catalina.jar:9.0.1] at org.apache.catalina.manager.ManagerServlet.deploy(ManagerServlet.java:729) [catalina.jar:9.0.1] at org.apache.catalina.manager.ManagerServlet.doPut(ManagerServlet.java:424) [catalina.jar:9.0.1] at javax.servlet.http.HttpServlet.service(HttpServlet.java:663) [servlet-api.jar:?] at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [servlet-api.jar:?] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [catalina.jar:9.0.1] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:9.0.1] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) [tomcat-websocket.jar:9.0.1] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:9.0.1] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:9.0.1] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) [catalina.jar:9.0.1] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [catalina.jar:9.0.1] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:592) [catalina.jar:9.0.1] at org.apache.catalina.valves.RequestFilterValve.process(RequestFilterValve.java:348) [catalina.jar:9.0.1] at org.apache.catalina.valves.RemoteAddrValve.invoke(RemoteAddrValve.java:52) [catalina.jar:9.0.1] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [catalina.jar:9.0.1] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [catalina.jar:9.0.1] at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:651) [catalina.jar:9.0.1] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [catalina.jar:9.0.1] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [catalina.jar:9.0.1] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:500) [tomcat-coyote.jar:9.0.1] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-coyote.jar:9.0.1] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754) [tomcat-coyote.jar:9.0.1] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1376) [tomcat-coyote.jar:9.0.1] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-coyote.jar:9.0.1] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_144] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_144] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:9.0.1] at java.lang.Thread.run(Thread.java:748) [?:1.8.0_144]
问题原因:
以上的报错信息就是说在进行序列化的时候, org.apache.tomcat.util.net.jsse.JSSESupport没有实现java.io.Serializable接口,导致序列化失败。
经过查看源码得知,在CacheInterceptor缓存数据时,会将request中的attribute也放到缓存中。
protected void cacheAction(String cacheName, String cacheKey, Controller controller) { HttpServletRequest request = controller.getRequest(); Map<String, Object> cacheData = new HashMap<String, Object>(); for (Enumeration<String> names=request.getAttributeNames(); names.hasMoreElements();) { String name = names.nextElement(); //将request中的attribute放入缓存中 cacheData.put(name, request.getAttribute(name)); } Render render = controller.getRender(); if (render != null) { cacheData.put(renderKey, createRenderInfo(render)); // cache RenderInfo } CacheKit.put(cacheName, cacheKey, cacheData); }
当开启ssl后,request.getAttributeNames()会额外取到5个参数
javax.servlet.request.ssl_session
javax.servlet.request.ssl_session_id
javax.servlet.request.ssl_session_mgr
javax.servlet.request.key_size
javax.servlet.request.cipher_suite
其中javax.servlet.request.ssl_session_mgr是org.apache.tomcat.util.net.jsse.JSSESupport类型的,无法序列化
解决方法:
写一个MyCacheInterceptor,重写cacheAction方法,如下:
@Override protected void cacheAction(String cacheName, String cacheKey, Controller controller) { HttpServletRequest request = controller.getRequest(); Map<String, Object> cacheData = new HashMap<>(); for (Enumeration<String> names = request.getAttributeNames(); names.hasMoreElements(); ) { String name = names.nextElement(); Object attribute = request.getAttribute(name); //只有可以序列化的属性才放入缓存中 if (attribute instanceof Serializable) { cacheData.put(name, attribute); } } Render render = controller.getRender(); if (render != null) { cacheData.put(renderKey, createRenderInfo(render)); // cache RenderInfo } CacheKit.put(cacheName, cacheKey, cacheData); }
其他:
CacheInterceptor中有一个useCacheDataAndRender,将缓存中的request属性写入最新的request中,不知道该操作有什么用处,如果不把javax.servlet.request.ssl_session_mgr对应的属性写入最新的reqeust中是否存在问题?波总如果看到了麻烦解答下,谢谢~~
参考:https://gitee.com/jfinal/jfinal/issues/10
上面的网址是“Tomcat 下开启ssl之后 renderJson()报错”的问题,也是由于reqeust中的不可序列化属性导致的,已经修复。