Swagger

Swagger简介

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。SwaggerCore是OpenAPI规范的Java实现。
总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许 API 来始终保持同步。Swagger 让部署管理和使用功能强大的 API 从未如此简单。
开源的部分包括:

OpenAPI Specification:API规范,规定了如何描述一个系统的API
Swagger Codegen:用于通过API规范生成服务端和客户端代码
Swagger Editor:用来编写API规范
Swagger UI:用于展示API规范

Springfox-Swagger简介

一、由来

由于Spring的流行,Marty Pitt编写了一个基于Spring的组件swagger-springmvc,用于将swagger集成到springmvc中来。而springfox则是从这个组件发展而来,同时springfox也是一个新的项目,本文仍然是使用其中的一个组件springfox-swagger2。

pringfox-swagger2依然是依赖OSA规范文档,也就是一个描述API的json文件,而这个组件的功能就是帮助我们自动生成这个json文件,我们会用到的另外一个组件springfox-swagger-ui就是将这个json文件解析出来,用一种更友好的方式呈现出来。

Springfox是一个通过扫描代码提取代码中的信息,生成API文档的工具。API文档的格式不止Swagger的OpenAPI Specification,还有RAML,jsonapi,Springfox的目标同样包括支持这些格式。这就能解释那个swagger2的后缀了,这只是Springfox对Swagger的支持。

在Swagger的教程中,都会提到@Api、@ApiModel、@ApiOperation这些注解,这些注解其实不是Springfox的,而是Swagger的。springfox-swagger2这个包依赖了swagger-core这个包,而这些注解正是在这里面。但是,swagger-core这个包是只支持JAX-RS2的,并不支持常用的Spring MVC。这就是springfox-swagger的作用了,它将上面那些用于JAX-RS2的注解适配到了Spring MVC上。

二、配置流程

我们知道,我们的第一个任务就是生成一个满足OSA规范的json文件(当然,创建一个spring的项目就不说了)。对于这个任务,springfox为我们提供了一个Docket(摘要的意思)类,我们需要把它做成一个Bean注入到spring中,显然,我们需要一个配置文件,并通过一种方式(显然它会是一个注解)告诉程序,这是一个Swagger配置文件。

一个OSA规范文档需要许多信息来描述这个API,springfox允许我们将信息组合成一个ApiInfo的类,作为构造参数传给Docket(当然也可以不构造这个类,而直接使用null,但是你的这个API就太low了)。

接下来,我们要写控制器了,当然这不重要,不用springfox你依然要写控制器,重要的是要告诉springfox,这个控制器是一个需要他来收集API信息的控制器,不用说,这依然会采用注解的方式,同时,我们为了将配置文件与控制器结合起来,需要在配置文件中指明在什么位置收集可能是API的控制器的信息。

到这里,生成OSA规范的json文件的配置就结束了。虽然生成过程比我叙述的更复杂,但这些程序都会帮我们完成,我们可以通过类似http://localhost:8080/demo/v2/api-docs的路径来查看这个json文件。这个v2/api-docs就是springfox默认的生成文档的路径。

接下来,我们需要将它可视化显示出来,如果使用swagger-springmvc,我们需要单独去下载一个swagger ui的显示页面包,并将其中的路径改为上面的http://localhost:8080/demo/v2/api-docs,这里你就可以感受到,swagger ui就是在解析一个json文件了。你依然可以这么做,不过springfox专门提供了一个springfox-swagger-ui组件,不需要配置,我们只需要引入这个依赖的组件就可以看到最终的效果了,而这个路由会是http://localhost:8080/demo/swagger-ui.html。

整合版本
注意Springfox和Spring存在版本对应关系,否则可能会整合失败,由于我是在已稳定运行的Spring4.1.3项目上整合Springfox,所以我在springfox源码库中(https://gitee.com/mirrors/springfox/blob/2.1.2/gradle/dependencies.gradle)或者去maven仓库中,找了个依赖的Spring版本跟Spring4.1.3接近的,是Springfox2.1.2。

若使用不当,springfox-swagger2在集成的时候可能会引入spring的相关jar,且与项目中的spring版本不一致,就会导致冲突,此时需要排除掉swagger中的spring依赖。

整合步骤

1.添加依赖pom.xml

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.1.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.1.2</version>
</dependency>
<dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.6.6</version>
</dependency>
<!-- FastJson的版本必须在1.2.10以上,不然访问/v2/api-docs返回为空 -->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.30</version>
</dependency>

2.添加静态资源 mvc.xml

<mvc:annotation-driven />

<!-- 静态资源配置 ,location必须是webapp根目录下的路径。注:WEB-INF文件夹里的内容是受保护的,即使在这里配置了还是不能直接访问 -->
<mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources/"/>
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>

3.添加配置类 SwaggerConfig.java

// 必须存在,要被Spring容器扫描到(@Component元注解)
@Configuration
// 必须存在,指示启用Swagger支持,Spring容器才会创建SpringMvcDocumentationConfiguration中定义的那些bean
@EnableSwagger2
// 必须存在,因为Swagger是基于MVC的,只从MVC容器中找需要的bean而不从Spring容器中找,所以需要开启mvc。
@EnableWebMvc
// 若Spring.xml中已配置了该扫描范围,则这里可不写
@ComponentScan(basePackages = {"com.xx"}
        , useDefaultFilters = false
        , includeFilters = {@Filter(type = FilterType.ANNOTATION, value = Controller.class)})
@Slf4j
public class SwaggerConfig {
    @PostConstruct
    public void init() {
        log.info("[swagger]开始初始化--->ok");
    }

    /**
     * 可以创建多个Docket-bean
     * @return
     */
    @Bean
    public Docket createRestApi() {
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                // Docket.enabled:是否暴露接口文档,默认为true,建议生产环境设置为false
                .enable(true)
                .apiInfo(apiInfo())
                // 对DocumentationContext的RequestHandlers(在Spring.xml + @ComponentScan中配置的扫描范围内)的默认ApiSelector为ApiSelector.DEFAULT。
                // 其中requestHandlerSelector属性=类上和方法上都没有@ApiIgnore;pathSelectors属性=任何路径都满足条件(always true),注:默认不管是否有@Api、@ApiOperation
                // 可以调用该方法创建一个ApiSelectorBuilder,从而新增自定义的ApiSelector,最终ApiSelector = ApiSelector.DEFAULT and (自定义的ApiSelector)
                .select()
                // 对DocumentationContext的RequestHandlers(在Spring.xml + @ComponentScan中配置的扫描范围内)新增自定义的ApiSelector
                //.apis(RequestHandlerSelectors.basePackage("com.hd.controller"))
                //.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .paths(PathSelectors.any())
                .build()
                ;
        return docket;
    }

    /**
     * api文档的描述信息,用于文档页面展示,可不配置
     * @return
     */
    private ApiInfo apiInfo() {
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("xx系统V1.0")
                .description("xx系统接口文档说明")
                .version("1.0")
                .build();
        return apiInfo;
    }
}


  1. 扫描配置类spring.xml
<context:component-scan base-package="com.xx" >
	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>

mvc.xml

<context:component-scan base-package="com.xx.**.controller" use-default-filters="false">
	<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>

常见问题
启动报错Cannot find cache named ‘models’ for CacheableOperation…
java.lang.IllegalArgumentException: Cannot find cache named ‘models’ for CacheableOperation[public com.google.common.base.Optional springfox.documentation.schema.DefaultModelProvider.modelFor(springfox.documentation.spi.schema.contexts.ModelContext)] caches=[models] | key=‘T(springfox.documentation.schema.ModelCacheKeys).modelContextKey(#modelContext)’ | keyGenerator=‘’ | cacheManager=‘’ | cacheResolver=‘’ | condition=‘’ | unless=‘’
at org.springframework.cache.interceptor.CacheAspectSupport.getCaches(CacheAspectSupport.java:161)
at org.springframework.cache.interceptor.CacheAspectSupport C a c h e O p e r a t i o n C o n t e x t . < i n i t > ( C a c h e A s p e c t S u p p o r t . j a v a : 384 ) a t o r g . s p r i n g f r a m e w o r k . c a c h e . i n t e r c e p t o r . C a c h e A s p e c t S u p p o r t . g e t O p e r a t i o n C o n t e x t ( C a c h e A s p e c t S u p p o r t . j a v a : 171 ) a t o r g . s p r i n g f r a m e w o r k . c a c h e . i n t e r c e p t o r . C a c h e A s p e c t S u p p o r t CacheOperationContext.<init>(CacheAspectSupport.java:384) at org.springframework.cache.interceptor.CacheAspectSupport.getOperationContext(CacheAspectSupport.java:171) at org.springframework.cache.interceptor.CacheAspectSupport CacheOperationContext.<init>(CacheAspectSupport.java:384)atorg.springframework.cache.interceptor.CacheAspectSupport.getOperationContext(CacheAspectSupport.java:171)atorg.springframework.cache.interceptor.CacheAspectSupportCacheOperationContexts.(CacheAspectSupport.java:350)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:181)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:60)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy D y n a m i c A d v i s e d I n t e r c e p t o r . i n t e r c e p t ( C g l i b A o p P r o x y . j a v a : 644 ) a t s p r i n g f o x . d o c u m e n t a t i o n . s c h e m a . D e f a u l t M o d e l P r o v i d e r DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644) at springfox.documentation.schema.DefaultModelProvider DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)atspringfox.documentation.schema.DefaultModelProvider E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIB$1.modelFor()
at springfox.documentation.spring.web.scanners.ApiModelReader.read(ApiModelReader.java:66)
at springfox.documentation.spring.web.scanners.ApiListingScanner.scan(ApiListingScanner.java:91)
at springfox.documentation.spring.web.scanners.ApiDocumentationScanner.scan(ApiDocumentationScanner.java:67)
at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.scanDocumentation(DocumentationPluginsBootstrapper.java:102)
at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.onApplicationEvent(DocumentationPluginsBootstrapper.java:88)
at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.onApplicationEvent(DocumentationPluginsBootstrapper.java:51)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:98)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:333)

根据错误日志打断点发现,Springfox确实会使用到缓存,并定义有springfox.documentation.annotations.Cacheable,全局查找发现会用到4个缓存:
在这里插入图片描述
所以需要我们先定义好这4个缓存,可以通过JavaConf方式也可以通过xml方式。
方式一、JavaConf方式:

@Bean
public CacheManager cacheManager() {
    SimpleCacheManager cacheManager = new SimpleCacheManager();
    List<Cache> caches = new ArrayList<Cache>();
    caches.add(new ConcurrentMapCache("models"));
    cacheManager.setCaches(caches);
    return cacheManager;
}

方式二、xml方式:我的项目是基于ehcache实现缓存的,spring.xml中有如下配置:

<!-- 启用缓存注解功能,这个是必须的,否则注解不会生效 -->
<cache:annotation-driven cache-manager="cacheManager" />
<!-- cacheManager工厂类,指定ehcache.xml的位置 -->
<bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">  
    <property name="configLocation" value="classpath:ehcache-setting.xml"></property>  
</bean>
<!-- 声明cacheManager -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">  
    <property name="cacheManager" ref="cacheManagerFactory"></property> 
</bean>

所以我需要在ehcache.xml中新增这4个缓存:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
	<diskStore path="/app/application/ehcacheDir" />
	<!-- 设定缓存的默认数据过期策略 -->
	<!-- 
	timeToLiveSeconds=x:缓存自创建日期起能够存活的最长时间,单位为秒(s);
	timeToIdleSeconds=y:缓存创建以后,最后一次访问缓存的日期至失效之时的时间间隔y,单位为秒(s);
	只有在eternal为false时,这2个属性才有效。timeToLiveSeconds必须大于timeToIdleSeconds才有意义。一个缓存的最长存活时间为timeToLiveSeconds!
	 -->
	<defaultCache maxElementsInMemory="10000" eternal="false"
		overflowToDisk="true" timeToIdleSeconds="10" timeToLiveSeconds="20"
		diskPersistent="false" diskExpiryThreadIntervalSeconds="120" />
		
	<!-- springfox-swagger启动报错说找不到这些cache -->
	<cache name="models" maxElementsInMemory="1000" eternal="false"
		   overflowToDisk="true" timeToIdleSeconds="1800" timeToLiveSeconds="86400"
		   diskPersistent="true" diskExpiryThreadIntervalSeconds="120"/>
	<cache name="modelDependencies" maxElementsInMemory="1000" eternal="false"
		   overflowToDisk="true" timeToIdleSeconds="1800" timeToLiveSeconds="86400"
		   diskPersistent="true" diskExpiryThreadIntervalSeconds="120"/>
	<cache name="modelProperties" maxElementsInMemory="1000" eternal="false"
		   overflowToDisk="true" timeToIdleSeconds="1800" timeToLiveSeconds="86400"
		   diskPersistent="true" diskExpiryThreadIntervalSeconds="120"/>
	<cache name="operations" maxElementsInMemory="1000" eternal="false"
		   overflowToDisk="true" timeToIdleSeconds="1800" timeToLiveSeconds="86400"
		   diskPersistent="true" diskExpiryThreadIntervalSeconds="120"/>
</ehcache>

注意,这里将overflowToDisk和diskPersistent属性设置为true,可能会有问题,具体情况请看下面这个报错。

启动报错NotSerializableException,但能正常运行

[operations.data 2021-02-25 11:40:04.083] [ERROR] DiskStorageFactory D i s k W r i t e T a s k . c a l l : 488 D i s k W r i t e o f / e x e c / u p d a t e D r m S t a t u s / t r a t e g y N a m e . e x e c U p d a t e D r m S t a t u s . D e f a u l t G e n e r i c T y p e N a m i n g S t r a t e g y f a i l e d : j a v a . i o . N o t S e r i a l i z a b l e E x c e p t i o n : s p r i n g f o x . d o c u m e n t a t i o n . s e r v i c e . O p e r a t i o n a t j a v a . i o . O b j e c t O u t p u t S t r e a m . w r i t e O b j e c t 0 ( O b j e c t O u t p u t S t r e a m . j a v a : 1184 ) a t j a v a . i o . O b j e c t O u t p u t S t r e a m . w r i t e O b j e c t ( O b j e c t O u t p u t S t r e a m . j a v a : 348 ) a t j a v a . u t i l . A r r a y L i s t . w r i t e O b j e c t ( A r r a y L i s t . j a v a : 762 ) a t s u n . r e f l e c t . G e n e r a t e d M e t h o d A c c e s s o r 82. i n v o k e ( U n k n o w n S o u r c e ) a t s u n . r e f l e c t . D e l e g a t i n g M e t h o d A c c e s s o r I m p l . i n v o k e ( D e l e g a t i n g M e t h o d A c c e s s o r I m p l . j a v a : 43 ) a t j a v a . l a n g . r e f l e c t . M e t h o d . i n v o k e ( M e t h o d . j a v a : 498 ) a t j a v a . i o . O b j e c t S t r e a m C l a s s . i n v o k e W r i t e O b j e c t ( O b j e c t S t r e a m C l a s s . j a v a : 1028 ) a t j a v a . i o . O b j e c t O u t p u t S t r e a m . w r i t e S e r i a l D a t a ( O b j e c t O u t p u t S t r e a m . j a v a : 1496 ) a t j a v a . i o . O b j e c t O u t p u t S t r e a m . w r i t e O r d i n a r y O b j e c t ( O b j e c t O u t p u t S t r e a m . j a v a : 1432 ) a t j a v a . i o . O b j e c t O u t p u t S t r e a m . w r i t e O b j e c t 0 ( O b j e c t O u t p u t S t r e a m . j a v a : 1178 ) a t j a v a . i o . O b j e c t O u t p u t S t r e a m . d e f a u l t W r i t e F i e l d s ( O b j e c t O u t p u t S t r e a m . j a v a : 1548 ) a t j a v a . i o . O b j e c t O u t p u t S t r e a m . d e f a u l t W r i t e O b j e c t ( O b j e c t O u t p u t S t r e a m . j a v a : 441 ) a t n e t . s f . e h c a c h e . E l e m e n t . w r i t e O b j e c t ( E l e m e n t . j a v a : 875 ) a t s u n . r e f l e c t . G e n e r a t e d M e t h o d A c c e s s o r 86. i n v o k e ( U n k n o w n S o u r c e ) a t s u n . r e f l e c t . D e l e g a t i n g M e t h o d A c c e s s o r I m p l . i n v o k e ( D e l e g a t i n g M e t h o d A c c e s s o r I m p l . j a v a : 43 ) a t j a v a . l a n g . r e f l e c t . M e t h o d . i n v o k e ( M e t h o d . j a v a : 498 ) a t j a v a . i o . O b j e c t S t r e a m C l a s s . i n v o k e W r i t e O b j e c t ( O b j e c t S t r e a m C l a s s . j a v a : 1028 ) a t j a v a . i o . O b j e c t O u t p u t S t r e a m . w r i t e S e r i a l D a t a ( O b j e c t O u t p u t S t r e a m . j a v a : 1496 ) a t j a v a . i o . O b j e c t O u t p u t S t r e a m . w r i t e O r d i n a r y O b j e c t ( O b j e c t O u t p u t S t r e a m . j a v a : 1432 ) a t j a v a . i o . O b j e c t O u t p u t S t r e a m . w r i t e O b j e c t 0 ( O b j e c t O u t p u t S t r e a m . j a v a : 1178 ) a t j a v a . i o . O b j e c t O u t p u t S t r e a m . w r i t e O b j e c t ( O b j e c t O u t p u t S t r e a m . j a v a : 348 ) a t n e t . s f . e h c a c h e . u t i l . M e m o r y E f f i c i e n t B y t e A r r a y O u t p u t S t r e a m . s e r i a l i z e ( M e m o r y E f f i c i e n t B y t e A r r a y O u t p u t S t r e a m . j a v a : 97 ) a t n e t . s f . e h c a c h e . s t o r e . d i s k . D i s k S t o r a g e F a c t o r y . s e r i a l i z e E l e m e n t ( D i s k S t o r a g e F a c t o r y . j a v a : 403 ) a t n e t . s f . e h c a c h e . s t o r e . d i s k . D i s k S t o r a g e F a c t o r y . w r i t e ( D i s k S t o r a g e F a c t o r y . j a v a : 385 ) a t n e t . s f . e h c a c h e . s t o r e . d i s k . D i s k S t o r a g e F a c t o r y DiskWriteTask.call:488 Disk Write of /exec/updateDrmStatus/{trategyName}.execUpdateDrmStatus.DefaultGenericTypeNamingStrategy failed: java.io.NotSerializableException: springfox.documentation.service.Operation at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) at java.util.ArrayList.writeObject(ArrayList.java:762) at sun.reflect.GeneratedMethodAccessor82.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441) at net.sf.ehcache.Element.writeObject(Element.java:875) at sun.reflect.GeneratedMethodAccessor86.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) at net.sf.ehcache.util.MemoryEfficientByteArrayOutputStream.serialize(MemoryEfficientByteArrayOutputStream.java:97) at net.sf.ehcache.store.disk.DiskStorageFactory.serializeElement(DiskStorageFactory.java:403) at net.sf.ehcache.store.disk.DiskStorageFactory.write(DiskStorageFactory.java:385) at net.sf.ehcache.store.disk.DiskStorageFactory DiskWriteTask.call:488DiskWriteof/exec/updateDrmStatus/trategyName.execUpdateDrmStatus.DefaultGenericTypeNamingStrategyfailed:java.io.NotSerializableException:springfox.documentation.service.Operationatjava.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)atjava.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)atjava.util.ArrayList.writeObject(ArrayList.java:762)atsun.reflect.GeneratedMethodAccessor82.invoke(UnknownSource)atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)atjava.lang.reflect.Method.invoke(Method.java:498)atjava.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028)atjava.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)atjava.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)atjava.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)atjava.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)atjava.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441)atnet.sf.ehcache.Element.writeObject(Element.java:875)atsun.reflect.GeneratedMethodAccessor86.invoke(UnknownSource)atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)atjava.lang.reflect.Method.invoke(Method.java:498)atjava.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028)atjava.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)atjava.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)atjava.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)atjava.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)atnet.sf.ehcache.util.MemoryEfficientByteArrayOutputStream.serialize(MemoryEfficientByteArrayOutputStream.java:97)atnet.sf.ehcache.store.disk.DiskStorageFactory.serializeElement(DiskStorageFactory.java:403)atnet.sf.ehcache.store.disk.DiskStorageFactory.write(DiskStorageFactory.java:385)atnet.sf.ehcache.store.disk.DiskStorageFactoryDiskWriteTask.call(DiskStorageFactory.java:477)
at net.sf.ehcache.store.disk.DiskStorageFactory P e r s i s t e n t D i s k W r i t e T a s k . c a l l ( D i s k S t o r a g e F a c t o r y . j a v a : 1071 ) a t n e t . s f . e h c a c h e . s t o r e . d i s k . D i s k S t o r a g e F a c t o r y PersistentDiskWriteTask.call(DiskStorageFactory.java:1071) at net.sf.ehcache.store.disk.DiskStorageFactory PersistentDiskWriteTask.call(DiskStorageFactory.java:1071)atnet.sf.ehcache.store.disk.DiskStorageFactoryPersistentDiskWriteTask.call(DiskStorageFactory.java:1055)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值