netty实现高性能文件服务器,通用文件服务组件(Netty实现版本)

本文所述文件服务组件在笔者此前一篇文章中已有阐述(基于netty的文件上传下载组件),不过本文将基于之前这个实现再次进行升级改造,利用基于注解的方式进行自动装配。

1. 简介

1.1 Netty简介

Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。关于其详细的介绍可以参考Netty官方网站。

Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.

Netty主要特点:

Unified API for various transport types - blocking and non-blocking socket(统一API)

Based on a flexible and extensible event model which allows clear separation of concerns(事件模型)

Highly customizable thread model - single thread, one or more thread pools such as SEDA(线程模型)

True connectionless datagram socket support (since 3.1)(无连接数据报文Socket支持)

1.2 组件功能介绍

该组件基于netty3.6.3实现,具有如下功能:文件上传,文件替换,文件删除,如果是图片的话,还可以生成缩略图等功能。使用简单,只需要引入commons-doc-client-netty,即可以实现文件的以上操作。

本组件分为三个module,分别为:

commons-doc-server-netty:Netty实现文件服务组件的服务端

commons-doc-common:Netty文件服务组件公共组件

commons-doc-client-netty:Netty文件服务组件的客户端

2. 服务端

2.1 功能简介

服务端组件实现以下功能:文件上传,文件替换,文件删除,如果是图片的话,还可以生成缩略图等功能。代码结构如下图所示,

1460000019853363?w=649&h=796

所有的文件服务都是基于接口DocServerProcessor进行的,主要有以下几个实现类:

UploadDocServerHandler实现文件上传服务

ReplaceDocServerHandler实现文件替换服务

DeleteDocServerHandler实现文件删除服务

CreateThumbPictureServerHandler实现创建图片缩略图服务

2.2 实现步骤

具体实现步骤以文件上传为例。

首先 org.fortune.doc.server.support.DocServerHandler类会持续监听客户端的请求,如果是文件处理动作,则会进入messageReceived方法进行相应的处理逻辑。该类定义了以下成员变量:

//http请求

private HttpRequest request;

//是否需要断点续传作业

private boolean readingChunks;

//接收到的文件内容

private final StringBuffer responseContent = new StringBuffer();

//解析收到的文件

private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //16384L

//post请求的解码类,它负责把字节解码成Http请求。

private HttpPostRequestDecoder decoder;

//请求参数

private RequestParam requestParams = new RequestParam();

该方法实现中,如果文件大小小于chunked的最小值,则直接进行文件上传操作。否则,需要进行分块处理。然后进行文件上传操作。

文件大小小于1k的操作:

if (request.isChunked()) { //说明还没有请求完成,继续

this.readingChunks = true;

LOGGER.info("文件分块操作....");

} else {

LOGGER.info("文件大小小于1KB,文件接收完成,直接进行相应的文件处理操作....");

//请求完成,则接收请求参数,进行初始化请求参数

RequestParamParser.parseParams(this.decoder, this.requestParams);

//根据请求参数进行相应的文件操作

LOGGER.info("文件处理开始....requestParams参数解析:{}",requestParams);

String result = DocServerHandlerFactory.process(this.requestParams);

LOGGER.info("文件处理结束....FileServerHandlerFactory处理结果:{}",result);

this.responseContent.append(result);

//给客户端响应信息

writeResponse(e.getChannel());

e.getFuture().addListener(ChannelFutureListener.CLOSE);

}

需要分块处理操作:

HttpChunk chunk = (HttpChunk) e.getMessage();

try {

//chunk.getContent().capacity();

LOGGER.info("文件分块操作....文件大小:{} bytes",chunk.getContent().capacity());

this.decoder.offer(chunk);

} catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {

e1.printStackTrace();

this.responseContent.append(e1.getMessage());

writeResponse(e.getChannel());

Channels.close(e.getChannel());

return;

}

if (chunk.isLast()) {

//文件末尾

this.readingChunks = false;

LOGGER.info("到达文件内容的末尾,进行相应的文件处理操作....start");

RequestParamParser.parseParams(this.decoder, this.requestParams);

LOGGER.info("文件处理开始....requestParams参数解析:{}",requestParams);

String result = DocServerHandlerFactory.process(this.requestParams);

LOGGER.info("文件处理结束....FileServerHandlerFactory处理结果:{}",result);

this.responseContent.append(result);

//给客户端响应信息

writeResponse(e.getChannel());

e.getFuture().addListener(ChannelFutureListener.CLOSE);

LOGGER.info("到达文件内容的末尾,进行相应的文件处理操作....end");

}

以上操作主要有两个注意点:

请求参数的解析工作(根据HttpDataType进行相应参数的赋值操作)

根据解析的参数进行相应的文件处理操作(根据文件操作类型,选择相应的处理句柄进行文件处理)

3. 客户端

3.1 功能简介

客户端组件主要提供对外访问服务端组件的接口,提供以下接口:文件上传,文件替换,文件删除,如果是图片的话,还可以生成缩略图等功能。代码结构如下:

1460000019853364?w=595&h=713

org.fortune.doc.client.DocClient类是对外提供接口的工具类,具有以下主要方法:

uploadFile 文件上传,对应文件处理句柄类为:org.fortune.doc.client.handler.UploadDocClientHandler

deleteFile 删除服务端文件,对应文件处理句柄类为:org.fortune.doc.client.handler.DeleteDocClientHandler

replaceFile 替换服务端文件,对应文件处理句柄类为:org.fortune.doc.client.handler.ReplaceDocClientHandler

createThumbPicture 生成缩略图,对应文件处理句柄类为:org.fortune.doc.client.handler.CreateThumbPictureClientHandler

3.2 实现步骤

实现步骤以上传文件为例,其他类似实现。直接上代码:

/**

* 文件上传

* @param file 需要上传的文件

* @param fileName 文件名称

* @param thumbMark 是否需要生成缩略图

* @return

* @author:landyChris

*/

public static String uploadFile(File file, String fileName,

boolean thumbMark) {

DocClientPipelineFactory clientPipelineFactory = new DocClientPipelineFactory();

//辅助类。用于帮助我们创建NETTY服务

ClientBootstrap bootstrap = createClientBootstrap(clientPipelineFactory);

String strThumbMark = Constants.THUMB_MARK_NO;

if (thumbMark) {

strThumbMark = Constants.THUMB_MARK_YES;

}

//具体处理上传文件逻辑

uploadFile(bootstrap, DocClientContainer.getInstance().getHost(),

DocClientContainer.getInstance().getPort(), file, fileName, strThumbMark,

DocClientContainer.getInstance().getUserName(),

DocClientContainer.getInstance().getPassword());

Result result = clientPipelineFactory.getResult();

if ((result != null) && (result.isSuccess())) {

return result.getFilePath();

}

return null;

}

具有三个参数,前面几行代码都是很一些netty的初始化工作,具体看一个私有方法uploadFile,如下代码所示:

private static void uploadFile(ClientBootstrap bootstrap, String host,

int port, File file, String fileName, String thumbMark,

String userName, String pwd) {

//1.构建uri对象

URI uri = getUri(host, port);

//2.连接netty服务端

ChannelFuture future = bootstrap.connect(new InetSocketAddress(host,

port));

//3.异步获取Channel对象

Channel channel = future.awaitUninterruptibly().getChannel();

if (!future.isSuccess()) {

future.getCause().printStackTrace();

bootstrap.releaseExternalResources();

return;

}

//4.初始化文件上传句柄对象

AbstractDocClientHandler handler = new UploadDocClientHandler(host, uri,

file, fileName, thumbMark, userName, pwd);

//5.获取Request对象

HttpRequest request = handler.getRequest();

//6.获取Http数据处理工厂

HttpDataFactory factory = getHttpDataFactory();

//7.进行数据的包装处理,主要是进行上传文件所需要的参数的设置,此时调用的句柄是具体的UploadFileClientHandler对象

HttpPostRequestEncoder bodyRequestEncoder = handler

.wrapRequestData(factory);

//8.把request写到管道中,传输给服务端

channel.write(request);

//9.做一些关闭资源的动作

if (bodyRequestEncoder.isChunked()) {

channel.write(bodyRequestEncoder).awaitUninterruptibly();

}

bodyRequestEncoder.cleanFiles();

channel.getCloseFuture().awaitUninterruptibly();

bootstrap.releaseExternalResources();

factory.cleanAllHttpDatas();

}

主要有以下实现步骤:

构建uri对象

连接netty服务端

异步获取Channel对象

初始化文件上传句柄对象

获取Request对象

获取Http数据处理工厂

进行数据的包装处理,主要是进行上传文件所需要的参数的设置,此时调用的句柄是具体的UploadFileClientHandler对象

把request写到管道中,传输给服务端

做一些关闭资源的动作

具体细节实现请参考github上的代码。如果各位读者喜欢的话,可以加个star哈。

4. 操作指引

该文件服务组件的使用需要分为两个部分,一个是服务端配置与启动,一个是客户端的配置与启动。

4.1 服务端配置与启动

4.1.1 配置

服务端的配置采用yml文件的配置,更加的简洁明了,主要的注意点是文件存放位置的配置,在开发过程中,可以有两种方式配置:

Idea自启动方式:如果采用此种方式则需要把rootPath配置到工程路径下(target目录),如下所示:

# 在idea中执行的话,需要配置target目录下的打包文件

rootPath: C:\03_code\idea_workspace\fortune-commons\commons-doc-server-netty\target\commons-doc-server-netty\ #上传文件的根目录,实际工作环境按照实际情况更改即可

打包后在tomcat独立启动方式

# 也可以单独把打包后的war包拷贝到tomcat webapp目录下直接运行也可以

rootPath: C:\05_webserver\apache-tomcat-8.5.42\webapps\doc-server #上传文件的根目录,实际工作环境按照实际情况更改即可

4.1.2 启动

本文采用的是idea自启动方式,则需要配置一下tomcat路径,以及引入相应的module即可,如下图所示:

1460000019853365?w=1614&h=1010

需要注意的是,在Deployment页签,需要配置该项目访问的Application Context,否则有可能启动后出现404的情况。如下图所示:

1460000019853366?w=1115&h=797

配置完成即可启动文件服务组件,如下图即为启动信息日志:

....

2019-07-20 23:48:56.174 [RMI TCP Connection(3)-127.0.0.1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'mvcViewResolver'

2019-07-20 23:48:56.182 [RMI TCP Connection(3)-127.0.0.1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'viewResolver'

2019-07-20 23:48:56.208 [RMI TCP Connection(3)-127.0.0.1] INFO org.fortune.commons.core.help.BeanInitializeCompletedListener - spring conf 容器初始化完毕..处理启动之后事件--start

2019-07-20 23:48:56.212 [RMI TCP Connection(3)-127.0.0.1] INFO org.fortune.doc.server.DocServerContainer - 加入账户:fortune

2019-07-20 23:48:56.212 [RMI TCP Connection(3)-127.0.0.1] INFO org.fortune.doc.server.DocServerContainer - 加入账户:fortune0

2019-07-20 23:48:56.213 [RMI TCP Connection(3)-127.0.0.1] INFO org.fortune.doc.server.DocServerContainer - 加入默认账户:Account{userName='default_account', password='lyx', rootPath='C:\05_webserver\apache-tomcat-8.5.42\bin\', level=1, thumbHeight=20, thumbWidth=20}

2019-07-20 23:48:56.296 [RMI TCP Connection(3)-127.0.0.1] INFO org.fortune.commons.core.help.BeanInitializeCompletedListener - spring conf 容器初始化完毕..处理启动之后事件--end

2019-07-20 23:48:56.302 [RMI TCP Connection(3)-127.0.0.1] DEBUG org.springframework.jndi.JndiTemplate - Looking up JNDI object with name [java:comp/env/spring.liveBeansView.mbeanDomain]

2019-07-20 23:48:56.303 [RMI TCP Connection(3)-127.0.0.1] DEBUG org.springframework.jndi.JndiLocatorDelegate - Converted JNDI name [java:comp/env/spring.liveBeansView.mbeanDomain] not found - trying original name [spring.liveBeansView.mbeanDomain]. javax.naming.NameNotFoundException: Name [spring.liveBeansView.mbeanDomain] is not bound in this Context. Unable to find [spring.liveBeansView.mbeanDomain].

2019-07-20 23:48:56.303 [RMI TCP Connection(3)-127.0.0.1] DEBUG org.springframework.jndi.JndiTemplate - Looking up JNDI object with name [spring.liveBeansView.mbeanDomain]

2019-07-20 23:48:56.304 [RMI TCP Connection(3)-127.0.0.1] DEBUG org.springframework.jndi.JndiPropertySource - JNDI lookup for name [spring.liveBeansView.mbeanDomain] threw NamingException with message: Name [spring.liveBeansView.mbeanDomain] is not bound in this Context. Unable to find [spring.liveBeansView.mbeanDomain].. Returning null.

2019-07-20 23:48:56.307 [RMI TCP Connection(3)-127.0.0.1] INFO org.springframework.web.context.ContextLoader - Root WebApplicationContext initialized in 2216 ms

2019-07-20 23:48:56.311 [RMI TCP Connection(3)-127.0.0.1] DEBUG org.springframework.web.filter.CharacterEncodingFilter - Filter 'characterEncodingFilter' configured for use

2019-07-20 23:48:56.320 [RMI TCP Connection(3)-127.0.0.1] INFO org.springframework.web.servlet.DispatcherServlet - Initializing Servlet 'doc-server'

....

然后就可以访问如下页面,显示如下:

1460000019853367?w=779&h=165

不过我们配置的netty端口是9999,我们试着访问一下,

1460000019853368?w=1480&h=963

此时我们就可以不依赖客户端,直接在网页端进行文件上传的测试操作了。输入账户,密码,选择相应的文件即可上传,上传成功的返回页面如下:

1460000019853369?w=1919&h=502

后台控制台打印出的日志信息如下:

2019-07-20 23:52:12.833 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....

2019-07-20 23:52:12.835 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:1024 bytes

2019-07-20 23:52:12.849 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:2048 bytes

2019-07-20 23:52:12.849 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:2048 bytes

2019-07-20 23:52:12.850 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:3072 bytes

2019-07-20 23:52:12.850 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:4096 bytes

2019-07-20 23:52:12.850 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:6144 bytes

2019-07-20 23:52:12.852 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:8192 bytes

2019-07-20 23:52:12.852 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:8192 bytes

2019-07-20 23:52:12.852 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:3072 bytes

2019-07-20 23:52:12.853 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:8192 bytes

2019-07-20 23:52:12.853 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:7168 bytes

2019-07-20 23:52:12.853 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:8192 bytes

2019-07-20 23:52:12.854 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:8192 bytes

2019-07-20 23:52:12.854 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:6144 bytes

2019-07-20 23:52:12.856 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:8157 bytes

2019-07-20 23:52:12.862 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件分块操作....文件大小:0 bytes

2019-07-20 23:52:12.862 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 到达文件内容的末尾,进行相应的文件处理操作....start

2019-07-20 23:52:12.865 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件处理开始....requestParams参数解析:

NETTY WEB Server

===================================

UserName=fortune

pwd=fortune

action=uploadFile

fileContentType=image/jpeg

fileSize=81 KB

getform=POST

Send=Send

2019-07-20 23:52:12.867 [New I/O worker #1] INFO org.fortune.doc.server.handler.factory.DocServerHandlerFactory - 进行文件上传操作....

2019-07-20 23:52:12.869 [New I/O worker #1] INFO org.fortune.doc.server.handler.UploadDocServerHandler - --srcFileName--psb.jpg

2019-07-20 23:52:12.871 [New I/O worker #1] INFO org.fortune.doc.server.handler.UploadDocServerHandler - 文件上传成功,保存路径为:fortune\l\190720235212_1027.jpg,真实路径为:C:\03_code\idea_workspace\fortune-commons\commons-doc-server-netty\target\commons-doc-server-netty\/fortune\l\190720235212_1027.jpg

2019-07-20 23:52:12.871 [New I/O worker #1] DEBUG org.fortune.doc.server.handler.UploadDocServerHandler - 生成缩略图

2019-07-20 23:52:12.872 [New I/O worker #1] INFO org.fortune.doc.server.handler.UploadDocServerHandler - 生成缩略图的名称为:190720235212_1027_thumb.jpg,路径为:C:\03_code\idea_workspace\fortune-commons\commons-doc-server-netty\target\commons-doc-server-netty\/fortune\l\190720235212_1027_thumb.jpg

2019-07-20 23:52:13.130 [New I/O worker #1] DEBUG org.fortune.doc.server.handler.factory.DocServerHandlerFactory - 执行结果:{"action":"uploadFile","code":1,"filePath":"fortune\\l\\190720235212_1027.jpg","msg":"文件上传成功","success":true}

2019-07-20 23:52:13.130 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 文件处理结束....FileServerHandlerFactory处理结果:{"action":"uploadFile","code":1,"filePath":"fortune\\l\\190720235212_1027.jpg","msg":"文件上传成功","success":true}

2019-07-20 23:52:13.133 [New I/O worker #1] INFO org.fortune.doc.server.support.DocServerHandler - 到达文件内容的末尾,进行相应的文件处理操作....end

再观察一下netty 代码中的target目录下就有上传的文件了,如下所示:

1460000019853370?w=624&h=249

我们可以通过如下地址进行访问,

http://localhost:8080/doc-server/fortune//l//190720235212_1027.jpg,关于如何得到图片地址,则在客户端工具类中有相应的方法获取。

4.2 客户端配置与启动

4.2.1 配置

客户端的配置比较简单,也是采用yml文件方式配置如下:

#上传成功后,在需要访问文件web工程中配置以下服务器地址,正确格式为:

# ${host}/${port}/${appName}/${path}

# appName为远程文件服务app名称,比如doc-server

# path为文件上传后服务端返回的文件相对路径

#http://localhost:8080/doc-server/fortune//p//190629082821_8300.jpg

upload:

server:

port: 9999 #需要配置的是远程文件服务器netty服务端口号

host: 127.0.0.1

access: #访问文件

port: 8080 #访问文件 web 服务端口号

domainName: doc-server #访问文件 web 服务应用名称

userName: fortune

password: fortune

需要注意的是,文件访问的端口号跟远程文件服务器netty对应的端口是不一样的,这点需要特别注意。在调用文件服务返回的路径的时候,需要用到服务端访问文件的地址,进而访问相应的文件内容。可通过方法 org.fortune.doc.client.DocClientContainer#getDocServerUrl得到相应的服务端地址,再拼接上返回的相对路径,即可得到文件的完整地址了。

4.2.2 启动/调用

客户端单元测试用例如下:

/**

* @author: landy

* @date: 2019/5/30 23:37

* @description:

*/

@RunWith(SpringJUnit4ClassRunner.class) //调用Spring单元测试类

@ContextConfiguration(classes = {

SettingsConfiguration.class, // common settings configuration

DocClientConfiguration.class,

ApplicationContextHelperConfiguration.class

}) //加载Spring配置文件

public class DocClientTest {

@Test

public void test() {

DocClient.uploadFile(new File("C:\\06_temp\\psb.jpg"), "psb.jpg",false);

}

}

同样的服务端也会显示出上述相似的日志信息,

2019-07-21 00:04:26.704 [New I/O worker #4] INFO org.fortune.doc.server.handler.UploadDocServerHandler - --srcFileName--psb.jpg

2019-07-21 00:04:26.705 [New I/O worker #4] INFO org.fortune.doc.server.handler.UploadDocServerHandler - 文件上传成功,保存路径为:fortune\w\190721000426_6348.jpg,真实路径为:C:\03_code\idea_workspace\fortune-commons\commons-doc-server-netty\target\commons-doc-server-netty\/fortune\w\190721000426_6348.jpg

2019-07-21 00:04:26.705 [New I/O worker #4] DEBUG org.fortune.doc.server.handler.factory.DocServerHandlerFactory - 执行结果:{"action":"uploadFile","code":1,"filePath":"fortune\\w\\190721000426_6348.jpg","msg":"文件上传成功","success":true}

2019-07-21 00:04:26.705 [New I/O worker #4] INFO org.fortune.doc.server.support.DocServerHandler - 文件处理结束....FileServerHandlerFactory处理结果:{"action":"uploadFile","code":1,"filePath":"fortune\\w\\190721000426_6348.jpg","msg":"文件上传成功","success":true}

2019-07-21 00:04:26.706 [New I/O worker #4] INFO org.fortune.doc.server.support.DocServerHandler - 到达文件内容的末尾,进行相应的文件处理操作....end

2019-07-21 00:05:50.539 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/doc-server/fortune//w//190721000426_6348.jpg", parameters={}

2019-07-21 00:05:50.540 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped to org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler@4fcd8ee1

2019-07-21 00:05:50.542 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK

观察服务端target目录下,又多了一个文件,显示如下,

1460000019853371?w=606&h=294

跟日志信息打印出来的路径是一致的,我们可以通过返回的地址信息进行访问文件,

1460000019853372?w=1317&h=967

5. 常见问题

5.1 Maven依赖问题

如果某些jar包无法下载的话,可以手动下载然后自己手动执行maven命令安装到本地仓库即可(Then, install it using the command)。

mvn install:install-file -DgroupId=com.fasterxml.jackson.core -DartifactId=jackson-core -Dversion=2.9.9.1 -Dpackaging=jar -Dfile=/path/to/file

或者直接利用远程仓库地址进行安装也可( Alternatively, if you host your own repository you can deploy the file there: ),

mvn deploy:deploy-file -DgroupId=com.fasterxml.jackson.core -DartifactId=jackson-core -Dversion=2.9.9.1 -Dpackaging=jar -Dfile=/path/to/file -Durl=[url] -DrepositoryId=[id]

5.2 Tomcat 版本问题

如果使用Tomcat7则会出现以下问题,经过对比发现,需要采用Tomcat8以上版本即可,JDK版本需要为1.8+。

七月 23, 2019 11:25:52 下午 org.apache.catalina.startup.ContextConfig processAnnotationsJar

严重: Unable to process Jar entry [module-info.class] from Jar [jar:file:/C:/03_code/idea_workspace/fortune-commons/commons-doc-server-netty/target/commons-doc-server-netty/WEB-INF/lib/asm-7.0.jar!/] for annotations

org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 19

at org.apache.tomcat.util.bcel.classfile.Constant.readConstant(Constant.java:133)

at org.apache.tomcat.util.bcel.classfile.ConstantPool.(ConstantPool.java:60)

at org.apache.tomcat.util.bcel.classfile.ClassParser.readConstantPool(ClassParser.java:209)

at org.apache.tomcat.util.bcel.classfile.ClassParser.parse(ClassParser.java:119)

at org.apache.catalina.startup.ContextConfig.processAnnotationsStream(ContextConfig.java:2104)

at org.apache.catalina.startup.ContextConfig.processAnnotationsJar(ContextConfig.java:1980)

at org.apache.catalina.startup.ContextConfig.processAnnotationsUrl(ContextConfig.java:1946)

at org.apache.catalina.startup.ContextConfig.processAnnotations(ContextConfig.java:1931)

at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1325)

at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:878)

at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:369)

at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)

at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)

at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5173)

at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)

at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)

at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)

at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)

at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1553)

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.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)

at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)

at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)

at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:622)

at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:569)

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.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)

at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)

at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)

at com.sun.jmx.remote.security.MBeanServerAccessController.invoke(MBeanServerAccessController.java:468)

at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468)

at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)

at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309)

at java.security.AccessController.doPrivileged(Native Method)

at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1408)

at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)

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 sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)

at sun.rmi.transport.Transport$1.run(Transport.java:200)

at sun.rmi.transport.Transport$1.run(Transport.java:197)

at java.security.AccessController.doPrivileged(Native Method)

at sun.rmi.transport.Transport.serviceCall(Transport.java:196)

at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)

at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)

at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)

at java.security.AccessController.doPrivileged(Native Method)

at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

at java.lang.Thread.run(Thread.java:748)

23:25:53,087 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]

23:25:53,088 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/394457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PHP 小数点保留两位【转】

最近在做统计这一块内容&#xff0c;接触关于数字的数据比较多&#xff0c; 用到了三个函数来是 数字保留小数后 N 位&#xff1b; 接下来简单的介绍一下三个函数&#xff1a; 1、number_format echo number_format("5000000")."<br>"; echo number_…

华为杯数学建模2020获奖名单_我校在2020年全国大学生数学建模竞赛中再获佳绩(内附获奖名单)...

# 近日&#xff0c;从全国大学生数学建模竞赛组委会获悉&#xff0c;我校在2020年全国大学生数学建模竞赛中获得5项国家二等奖。国家奖获奖数量在全国农林院校中并列排名第二。在黑龙江省高校中位居第三名。1你的喜悦&#xff0c;我们的欣慰# 2020年全国大学生数学建模竞赛于9月…

fn映射 mac 键盘_【新鲜评测】高颜值、低延迟、多模式跨平台办公神器-米物蓝牙键盘...

首先&#xff0c;要例行感谢糖纸众测&#xff0c;感谢麻麻酱给我这次评测机会。大家可以微信搜索【糖纸】小程序免费体验更多科技产品。小米旗下生态链公司米物最近出了一款蓝牙双模键盘&#xff0c;它作为一个85全键键盘&#xff0c;可以完成蓝牙和USB转换&#xff0c;以及PC和…

小程序 input 换行_小程序 input双向数据绑定

小程序 双向绑定数据&#xff08;单个&#xff09;<小程序 双向绑定数据&#xff08;多个&#xff09;<

Suricata的初始化脚本

见官网 https://suricata.readthedocs.io/en/latest/initscripts.html

jpa在自己创建表的是字段名不一致_用 数据透视表 完成 Excel多表合并

一般情况下&#xff0c;数据透视表只能汇总一个表格中的数据。即使使用多区域汇总&#xff0c;也只能对多表的单列内容进行数据汇总&#xff0c;而多列却无法实现。前段时间也推送过Power Query的方法&#xff0c;但它有版本限制。而今天宏兴会计培训小编推送的是一个通用的多表…

使用栈实现队列 Implement Queue using Stacks

为什么80%的码农都做不了架构师&#xff1f;>>> 问题&#xff1a; Implement the following operations of a queue using stacks. push(x) -- Push element x to the back of queue.pop() -- Removes the element from in front of queue.peek() -- Get the front…

550什么意思_研报翻译官第二期:带你了解什么是CPI

欢迎收看“第二期”研报翻译官&#xff0c;临近年末&#xff0c;各类金融研报接踵而至&#xff0c;我们也常会看到GDP、CPI、PPI这类字眼。过年回家跟亲戚朋友唠嗑的时候&#xff0c;如果不扯上几句CPI或PPI&#xff0c;都显自己得不够专业。听你们吹牛&#xff0c;我炒菜都有劲…

jieba库的使用

jieba库的使用: jieba库是一款优秀的 Python 第三方中文分词库&#xff0c;jieba 支持三种分词模式&#xff1a;精确模式、全模式和搜索引擎模式&#xff0c;下面是三种模式的特点。 精确模式&#xff1a;试图将语句最精确的切分&#xff0c;不存在冗余数据&#xff0c;适合做文…

mysql结果集相减_MySQL_(Java)使用JDBC向数据库发起查询请求

课程相关链接&#xff1a;JDBC编程和MySQL数据库课程源代码在文章末尾~Java Database Connectivity简单来说就是使用Java里面提供的一些类和方法&#xff0c;利用程序链接数据库&#xff0c;进行增删改查操作。这个过程就叫做JDBC编程接下来我们便分五步通过JDBC对MySQL中的数据…

在双系统(Windows与Ubuntu)下删除Ubuntu启动项

问题概述&#xff1a;因为在自己学习Linux的时候&#xff0c;按照网上的教程错误的删除了Ubuntu的一个内核驱动&#xff0c;导致Ubuntu不能启动。我想到的办法是重新安装系统&#xff0c;重装系统的第一步便是将Ubuntu从电脑中卸载。该笔记是有关如何删除Ubuntu启动项的。 使用…

神舟笔记本bios_海尔雷神(蓝天)神舟战神游戏本风扇狂转掉电大写灯狂闪维修实例...

昨天收到一台网友寄过来的海尔雷神游戏本。说到这个游戏本品牌&#xff0c;其实有几个品牌的笔记本&#xff0c;它们的主板和模具是一模一样的&#xff0c;也就是我们看到的品牌log不一样而已。比如神舟的战神 &#xff0c;机械师&#xff0c;机械革命&#xff0c;麦本本等等。…

“康园圈--互联网+校园平台“项目之成果展示及项目总结

一、总体效果&#xff08;ipad端截图&#xff09; 网站前台页面网站后台管理台页面二、前台访问链接&#xff08;用pc访问效果最佳&#xff09;&#xff1a;http://www.liangzhilin.cn:9100/kangyuanquan/ &#xff08;为保证数据安全&#xff0c;后台管理链接不对外公开&#…

java中二进制怎么说_面试:说说Java中的 volatile 关键词?

volatile 这个关键字可能很多朋友都听说过&#xff0c;或许也都用过。在 Java 5 之前&#xff0c;它是一个备受争议的关键字&#xff0c;因为在程序中使用它往往会导致出人意料的结果。在 Java 5之后&#xff0c;volatile 关键字才得以重获生机。volatile 关键字虽然从字面上理…

类的详解

面向对象是一种编程方式&#xff0c;此编程方式的实现是基于对类和对象的使用。类是一个模板&#xff0c;模板中包装了多个“函数”供使用&#xff08;可以讲多函数中公用的变量封装到对象中&#xff09;。对象&#xff0c;根据模板创建的实例&#xff08;即对象&#xff09;&a…

什么情况不能办理房产抵押贷款 房产抵押贷能贷多少?

所谓房产抵押贷款是指以自己或亲友的房产作为抵押物向贷款机构申请贷款&#xff0c;款项可用于企业经营、买房、买车、装修及其他用途的融资方式。但是有些情况是规定不能申请房产抵押贷款的&#xff0c;而且贷款的数额是有限的&#xff0c;不是想贷多少就多少。那么&#xff0…

2数据库表增加一个字段_14个实用的数据库设计技巧!

1. 原始单据与实体之间的关系可以是一对一、一对多、多对多的关系。在一般情况下&#xff0c;它们是一对一的关系&#xff1a;即一张原始单据对应且只对应一个实体。在特殊情况下&#xff0c;它们可能是一对多或多对一的关系&#xff0c;即一张原始单证对应多个实体&#xff0c…

错误: 找不到或无法加载主类 helloworld_全面剖析虚拟机类加载机制

1.引言java源文件经过编译后生成字节码class文件&#xff0c;需要经过虚拟机加载并转换成汇编指令才能执行&#xff0c;那么虚拟机是如何一步步加载这些class文件的对于java程序员是完全透明的&#xff0c;本文尝试全面分析jvm类加载机制。2.思考开始之前我们来简单思考一下&am…

200道物理学难题——038蚱蜢跃树

转载于:https://www.cnblogs.com/hanford/p/6168514.html

strcmp可以比较数组么_大家都用过百度云,但你面试过百度云么

作者&#xff1a;黄小斜百度研发面经百度智能云软件研发工程师百度智能云研发岗好像是做控制台方面的组一面&#xff1a;1自我介绍&#xff0c;项目2 static关键字有什么用&#xff0c;static修饰不同东西时有什么作用&#xff0c;内部类用static修饰和不用static修饰有何区别。…