Tomcat源码解析之Web请求与处理

前言

Tomcat最全UML类图

Tomcat请求处理过程:

Connector对象创建的时候,会创建Http11NioProtocol的ProtocolHandler,在Connector的startInteral方法中,会启动AbstractProtocol,AbstractProtocol启动NioEndPoint进行监听客户端的请求,EndPoint接受到客户端的请求之后,会交给Container去处理请求。请求从Engine开始经过的所有容器都含有责任链模式,每经过一个容器都会调用该容器的责任链对请求进行处理。

一、EndPoint

默认的EndPoint实现是NioEndPoint,NioEndPoint有四个内部类,分别是Poller、Acceptor、PollerEvent、SocketProcessor、NioSocketWrapper。

(1)Acceptor负责监听用户的请求,监听到用户请求之后,调用getPoller0().register(channel);先将当前请求封装成PollerEvent,new PollerEvent(socket, ka, OP_REGISTER); 将当前请求,封装成注册事件,并添加到PollerEvent队列中,然后将PollerEvent注册到Poller的Selector对象上面。

(2)Poller线程会一直遍历可以处理的事件(netty的selestor),当找到需要处理的事件之后,调用processKey(sk, socketWrapper);对,执行要处理的PollerEvent的run方法,对请求进行处理。

(3)PollerEvent继承自Runnable接口,在其run方法里面,如果是PollerEvent的事件是注册OP_REGISTER,那么就将当前的socket注册到Poller的selector上。

 public void run() {
            if (interestOps == OP_REGISTER) {
                try {
                	// 核心代码,终于找到了!!!!!
                    // 当事件是注册的时候,将当前的NioSocketChannel注册到Poller的Selector上。
                    socket.getIOChannel().register(
                            socket.getPoller().getSelector(), SelectionKey.OP_READ, socketWrapper);
                } catch (Exception x) {
                    log.error(sm.getString("endpoint.nio.registerFail"), x);
                }
            } else {
                final SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
                try {
                    if (key == null) {

                        // The key was cancelled (e.g. due to socket closure)
                        // and removed from the selector while it was being
                        // processed. Count down the connections at this point
                        // since it won't have been counted down when the socket
                        // closed.
                        // SelectionKey被取消的时候需要将SelectionKey对应的EndPoint的Connection计数器,减一
                        socket.socketWrapper.getEndpoint().countDownConnection();
                        ((NioSocketWrapper) socket.socketWrapper).closed = true;
                    } else {
                        final NioSocketWrapper socketWrapper = (NioSocketWrapper) key.attachment();
                        if (socketWrapper != null) {
                            //we are registering the key to start with, reset the fairness counter.
                            int ops = key.interestOps() | interestOps;
                            socketWrapper.interestOps(ops);
                            key.interestOps(ops);
                        } else {
                            socket.getPoller().cancelledKey(key);
                        }
                    }
                } catch (CancelledKeyException ckx) {
                    try {
                        socket.getPoller().cancelledKey(key);
                    } catch (Exception ignore) {
                    }
                }
            }
        }

(4)Poller线程内会执行keyCount = selector.select(selectorTimeout);获取当前需要处理的SelectionKey的数量,然后当keyCount大于0时,会获取selector的迭代器,遍历所有需要的selectionkey,并对其进行处理。在这里将socket的事件封装成NioSocketWrapper。

// 得到selectedKeys的迭代器
Iterator<SelectionKey> iterator =
         keyCount > 0 ? selector.selectedKeys().iterator() : null;

 // 遍历所有的SelectionKey,并对其进行处理
 while (iterator != null && iterator.hasNext()) {
     SelectionKey sk = iterator.next();
     iterator.remove();
     NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
     // Attachment may be null if another thread has called
     // cancelledKey()
     // 如果有attachment,就处理
     if (socketWrapper != null) {
         // 处理事件
         processKey(sk, socketWrapper);
     }
 }

processKey在处理SelectionKey,如果当前Poller已经关闭,就取消key。SelectionKey对应的Channel如果发生读事件,就调用AbatractEndPoint.processSocket执行读操作processSocket(attachment, SocketEvent.OPEN_READ, true),如果SelectionKey对应的Channel发生写事件,就执行processSocket(attachment, SocketEvent.OPEN_WRITE, true);读大于写。socket的事件处理调用的是AbatractEndPoint的processSocket方法。

protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
	     try {
	         if (close) {
	             // 如果Poller已经关闭了,就取消key
	             cancelledKey(sk);
	         } else if (sk.isValid() && attachment != null) {
	             if (sk.isReadable() || sk.isWritable()) {
	                 if (attachment.getSendfileData() != null) {
	                     processSendfile(sk, attachment, false);
	                 } else {
	                     unreg(sk, attachment, sk.readyOps());
	                     boolean closeSocket = false;
	                     // Read goes before write
	                     // 读优于写
	                     // 如果SelectionKey对应的Channel已经准备好了读
	                     // 就对NioSocketWrapper进行读操作
	                     if (sk.isReadable()) {
	                         if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
	                             closeSocket = true;
	                         }
	                     }
	                     // 如果SelectionKey对应的Channel已经准备好了写
	                     // 就对NioSocketWrapper进行写操作
	                     if (!closeSocket && sk.isWritable()) {
	                         if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
	                             closeSocket = true;
	                         }
	                     }
	                     if (closeSocket) {
	                         // 如果已经关闭了,就取消key
	                         cancelledKey(sk);
	                     }
	                 }
	             }

}

AbatractEndPoint.processSocket方法首先从缓存中获取SocketProcessor类,如果缓存中没有就创建一个,SocketProcessorBase接口对应的就是NioEndPoint.SocketProcessor,也就是Worker。将对应的SocketProcessor类放入到线程池中执行。

 public boolean processSocket(SocketWrapperBase<S> socketWrapper,
                                 SocketEvent event, boolean dispatch) {

	// 得到socket的处理器
	// Connector在构造函数里面已经指定了协议:org.apache.coyote.http11.Http11NioProtocol。
	SocketProcessorBase<S> sc = processorCache.pop();
	if (sc == null) {
	// 如果没有,就创建一个Socket的处理器。创建的时候指定socketWrapper以及socket的事件。
	    sc = createSocketProcessor(socketWrapper, event);
	} else {
	    sc.reset(socketWrapper, event);
	}
	//socket的处理交给了线程池去处理。
	Executor executor = getExecutor();
	if (dispatch && executor != null) {
	    executor.execute(sc);
	} else {
	    sc.run();
	}

(5)NioEndPoint.NioSocketWrapper,是Socket的封装类,增强类,将Socket与其他对象建立关联。

 public static class NioSocketWrapper extends SocketWrapperBase<NioChannel> {
 		private final NioSelectorPool pool;

        private Poller poller = null; // 轮询的Poller
        private int interestOps = 0;
        private CountDownLatch readLatch = null;
        private CountDownLatch writeLatch = null;
        private volatile SendfileData sendfileData = null;
        private volatile long lastRead = System.currentTimeMillis();
        private volatile long lastWrite = lastRead;
        private volatile boolean closed = false;

(6)NioEndPoint.SocketProcessor(Worker)继承了Runnable接口,负责对socket的g各种事件进行处理。读事件、写事件、停止时间、超时事件、断连事件、错误时间、连接失败事件。

SocketProcessor的doRun方法,会根据SocketState进行处理,SocketState 为STOP、DISCONNECT或者ERROR的时候就进行关闭,SocketWrapperBase对应的selector事件,得到指定的Handler处理器进行处理。

@Override
 protected void doRun() {
     NioChannel socket = socketWrapper.getSocket();
     SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());

     try {
         int handshake = -1;

         try {
             if (key != null) {
                 if (socket.isHandshakeComplete()) {
                     // 是否已经握手成功,不需要TLS(加密)握手,就让处理器对socket和event的组合进行处理。
                     handshake = 0;
                 } else if (event == SocketEvent.STOP || event == SocketEvent.DISCONNECT ||
                         event == SocketEvent.ERROR) {
                     // 不能够完成TLS握手,就把他认为是TLS握手失败。
                     handshake = -1;
                 } else {
                     handshake = socket.handshake(key.isReadable(), key.isWritable());
                     // The handshake process reads/writes from/to the
                     // socket. status may therefore be OPEN_WRITE once
                     // the handshake completes. However, the handshake
                     // happens when the socket is opened so the status
                     // must always be OPEN_READ after it completes. It
                     // is OK to always set this as it is only used if
                     // the handshake completes.
                     // 握手从/向socket读/写时,握手一旦完成状态应该为OPEN_WRITE,
                     // 握手是在套接字打开时发生的,因此在完成后状态必须始终为OPEN_READ
                     // 始终设置此选项是可以的,因为它仅在握手完成时使用。
                     event = SocketEvent.OPEN_READ;
                 }
             }
         } catch (IOException x) {
             handshake = -1;
             if (log.isDebugEnabled()) log.debug("Error during SSL handshake", x);
         } catch (CancelledKeyException ckx) {
             handshake = -1;
         }
         if (handshake == 0) {
             SocketState state = SocketState.OPEN;
             // Process the request from this socket
             if (event == null) {
                 // 调用处理器进行处理。
                 // NioEndPoint的默认Handler是Http11的
                 // 这里的Handler是AbstractProtocol.ConnectionHandler
                 // 这个Handler的设置方法是:
                 // 首先在Connector类的构造函数中,将默认的ProtocolHandler设置为org.apache.coyote.http11.Http11NioProtocol
                 // AbstractHttp11Protocol的构造函数里面创建了Handler类ConnectionHandler
                 state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
             } else {
                 state = getHandler().process(socketWrapper, event);
             }
             // 如果返回的状态是SocketState,那么就关掉连接
             if (state == SocketState.CLOSED) {
                 close(socket, key);
             }
         } else if (handshake == -1) {
             getHandler().process(socketWrapper, SocketEvent.CONNECT_FAIL);
             close(socket, key);
         } else if (handshake == SelectionKey.OP_READ) {
             // 如果是SelectionKey.OP_READ,也就是读事件的话,就将OP_READ时间设置到socketWrapper
             socketWrapper.registerReadInterest();
         } else if (handshake == SelectionKey.OP_WRITE) {
             // 如果是SelectionKey.OP_WRITE,也就是读事件的话,就将OP_WRITE事件设置到socketWrapper
             socketWrapper.registerWriteInterest();
         }

二、ConnectionHandler

(1)ConnectionHandler用于根据Socket连接找到相应的Engine处理器。

上面是SocketProcessor的doRun方法,执行了getHandler().process(socketWrapper, SocketEvent.OPEN_READ);;process方法是首先在Map缓存中查找当前socket是否存在对应的processor,如果不存在,再去可循环的处理器栈中查找是否存在,如果不存在就创建相应的Processor,然后将新创建的Processor与Socket建立映射,存在connection的Map中。在任何一个阶段得到Processor对象之后,会执行processor的process方法state = processor.process(wrapper, status);

protected static class ConnectionHandler<S> implements AbstractEndpoint.Handler<S> {

        private final AbstractProtocol<S> proto;
        private final RequestGroupInfo global = new RequestGroupInfo();
        private final AtomicLong registerCount = new AtomicLong(0);
        // 终于找到了这个集合,给Socket和处理器建立连接
        // 对每个有效链接都会缓存进这里,用于连接选择一个合适的Processor实现以进行请求处理。
        private final Map<S, Processor> connections = new ConcurrentHashMap<>();
        // 可循环的处理器栈
        private final RecycledProcessors recycledProcessors = new RecycledProcessors(this);

  		@Override
        public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
            if (getLog().isDebugEnabled()) {
                getLog().debug(sm.getString("abstractConnectionHandler.process",
                        wrapper.getSocket(), status));
            }
            if (wrapper == null) {
                // wrapper == null 表示Socket已经被关闭了,所以不需要做任何操作。
                return SocketState.CLOSED;
            }
            // 得到wrapper内的Socket对象
            S socket = wrapper.getSocket();
            // 从Map缓冲区中得到socket对应的处理器。
            Processor processor = connections.get(socket);
            if (getLog().isDebugEnabled()) {
                getLog().debug(sm.getString("abstractConnectionHandler.connectionsGet",
                        processor, socket));
            }

            // Timeouts are calculated on a dedicated thread and then
            // dispatched. Because of delays in the dispatch process, the
            // timeout may no longer be required. Check here and avoid
            // unnecessary processing.

            // 超时是在专用线程上计算的,然后被调度。
            // 因为调度过程中的延迟,可能不再需要超时。检查这里,避免不必要的处理。
            if (SocketEvent.TIMEOUT == status &&
                    (processor == null ||
                            !processor.isAsync() && !processor.isUpgrade() ||
                            processor.isAsync() && !processor.checkAsyncTimeoutGeneration())) {
                // This is effectively a NO-OP
                return SocketState.OPEN;
            }
            // 如果Map缓存存在该socket相关的处理器
            if (processor != null) {
                // Make sure an async timeout doesn't fire
                // 确保没有触发异步超时
                getProtocol().removeWaitingProcessor(processor);
            } else if (status == SocketEvent.DISCONNECT || status == SocketEvent.ERROR) {
                // Nothing to do. Endpoint requested a close and there is no
                // longer a processor associated with this socket.
                // SocketEvent事件是关闭,或者SocketEvent时间出错,此时不需要做任何操作。
                // Endpoint需要一个CLOSED的信号,并且这里不再有与这个socket有关联了
                return SocketState.CLOSED;
            }

            ContainerThreadMarker.set();

            try {
                // Map缓存不存在该socket相关的处理器
                if (processor == null) {
                    String negotiatedProtocol = wrapper.getNegotiatedProtocol();
                    // OpenSSL typically returns null whereas JSSE typically
                    // returns "" when no protocol is negotiated
                    // OpenSSL通常返回null,而JSSE通常在没有协议协商时返回""
                    if (negotiatedProtocol != null && negotiatedProtocol.length() > 0) {
                        // 获取协商协议
                        UpgradeProtocol upgradeProtocol = getProtocol().getNegotiatedProtocol(negotiatedProtocol);
                        if (upgradeProtocol != null) {
                            // 升级协议为空
                            processor = upgradeProtocol.getProcessor(wrapper, getProtocol().getAdapter());
                            if (getLog().isDebugEnabled()) {
                                getLog().debug(sm.getString("abstractConnectionHandler.processorCreate", processor));
                            }
                        } else if (negotiatedProtocol.equals("http/1.1")) {
                            // Explicitly negotiated the default protocol.
                            // Obtain a processor below.
                        } else {
                            // TODO:
                            // OpenSSL 1.0.2's ALPN callback doesn't support
                            // failing the handshake with an error if no
                            // protocol can be negotiated. Therefore, we need to
                            // fail the connection here. Once this is fixed,
                            // replace the code below with the commented out
                            // block.
                            if (getLog().isDebugEnabled()) {
                                getLog().debug(sm.getString("abstractConnectionHandler.negotiatedProcessor.fail",
                                        negotiatedProtocol));
                            }
                            return SocketState.CLOSED;
                            /*
                             * To replace the code above once OpenSSL 1.1.0 is
                             * used.
                            // Failed to create processor. This is a bug.
                            throw new IllegalStateException(sm.getString(
                                    "abstractConnectionHandler.negotiatedProcessor.fail",
                                    negotiatedProtocol));
                            */
                        }
                    }
                }
                // 经过上面的操作,processor还是null的话。
                if (processor == null) {
                    // 从recycledProcessors可循环processors中获取processor
                    processor = recycledProcessors.pop();
                    if (getLog().isDebugEnabled()) {
                        getLog().debug(sm.getString("abstractConnectionHandler.processorPop", processor));
                    }
                }
                if (processor == null) {
                    // 创建处理器
                    processor = getProtocol().createProcessor();
                    register(processor);
                    if (getLog().isDebugEnabled()) {
                        getLog().debug(sm.getString("abstractConnectionHandler.processorCreate", processor));
                    }
                }
                processor.setSslSupport(
                        wrapper.getSslSupport(getProtocol().getClientCertProvider()));

                // 将socket和processor建立关联。
                connections.put(socket, processor);

                SocketState state = SocketState.CLOSED;
                do {
                    // 调用processor的process方法。
                    state = processor.process(wrapper, status);

                    // processor的process方法返回升级状态
                    if (state == SocketState.UPGRADING) {
                        // Get the HTTP upgrade handler
                        // 得到HTTP的升级句柄
                        UpgradeToken upgradeToken = processor.getUpgradeToken();
                        // Retrieve leftover input
                        // 检索剩余输入
                        ByteBuffer leftOverInput = processor.getLeftoverInput();
                        if (upgradeToken == null) {
                            // Assume direct HTTP/2 connection
                            UpgradeProtocol upgradeProtocol = getProtocol().getUpgradeProtocol("h2c");
                            if (upgradeProtocol != null) {
                                // Release the Http11 processor to be re-used
                                release(processor);
                                // Create the upgrade processor
                                processor = upgradeProtocol.getProcessor(wrapper, getProtocol().getAdapter());
                                wrapper.unRead(leftOverInput);
                                // Associate with the processor with the connection
                                connections.put(socket, processor);
                            } else {
                                if (getLog().isDebugEnabled()) {
                                    getLog().debug(sm.getString(
                                            "abstractConnectionHandler.negotiatedProcessor.fail",
                                            "h2c"));
                                }
                                // Exit loop and trigger appropriate clean-up
                                state = SocketState.CLOSED;
                            }
                        } else {
                            HttpUpgradeHandler httpUpgradeHandler = upgradeToken.getHttpUpgradeHandler();
                            // Release the Http11 processor to be re-used
                            release(processor);
                            // Create the upgrade processor
                            processor = getProtocol().createUpgradeProcessor(wrapper, upgradeToken);
                            if (getLog().isDebugEnabled()) {
                                getLog().debug(sm.getString("abstractConnectionHandler.upgradeCreate",
                                        processor, wrapper));
                            }
                            wrapper.unRead(leftOverInput);
                            // Associate with the processor with the connection
                            connections.put(socket, processor);
                            // Initialise the upgrade handler (which may trigger
                            // some IO using the new protocol which is why the lines
                            // above are necessary)
                            // This cast should be safe. If it fails the error
                            // handling for the surrounding try/catch will deal with
                            // it.
                            if (upgradeToken.getInstanceManager() == null) {
                                httpUpgradeHandler.init((WebConnection) processor);
                            } else {
                                ClassLoader oldCL = upgradeToken.getContextBind().bind(false, null);
                                try {
                                    httpUpgradeHandler.init((WebConnection) processor);
                                } finally {
                                    upgradeToken.getContextBind().unbind(false, oldCL);
                                }
                            }
                        }
                    }
                } while (state == SocketState.UPGRADING);

(2)以Http11协议为例,执行的是Http11Processor,Http11Processor的祖父类AbstractProcessorLight实现了process方法,process调用了service模板方法,service模板方法是由Http11Processor进行实现的。service方法最重要的操作是执行getAdapter().service(request, response);

@Override
    public SocketState service(SocketWrapperBase<?> socketWrapper)
            throws IOException {
		// 上面省略n行
		// 调用Coyote的service方法
		 getAdapter().service(request, response);
		 // 下面省略n行

三、Coyote

回顾一下CoyoteAdapter的创建是在Connector的initInternal方法。

@Override
    public SocketState service(SocketWrapperBase<?> socketWrapper)
            throws IOException {
		// 上面省略n行
		// 调用Coyote的service方法
		 getAdapter().service(request, response);
		 // 下面省略n行

Coyote的作用就是coyote.Request和coyote.Rsponse转成HttpServletRequest和HttpServletRsponse。然后,因为Connector在init的时候,将自己注入到了CoyoteAdapter中,所以,直接通过connector.getService()方法就可以拿到Service,然后从Service开始调用责任链模式,进行处理。

@Override
    public SocketState service(SocketWrapperBase<?> socketWrapper)
            throws IOException {
		// 上面省略n行
		// 调用Coyote的service方法
		 getAdapter().service(request, response);
		 // 下面省略n行

四、容器责任链模式

接下来就是从StandradEngine开始的责任链模式。首先执行StandradEngine的责任链模式,找到合适的Engine,合适的Engine在通过责任链模式找到合适的Context,直到找到StandardWrapperValve。最后执行到StandardWrapperValve的invoke方法。首先查看Context和Wrapper是不是不可用了,如果可用,并且Servelt还没有被初始化,就执行初始化操作。如果是单线程模式就直接返回之前创建好的Servelt,如果是多线程模式,就先创建一个Servelt对象进行返回。

@Override
    public final void invoke(Request request, Response response)
            throws IOException, ServletException {
        // 初始化我们需要的本地变量
        boolean unavailable = false;
        Throwable throwable = null;
        // This should be a Request attribute...
        long t1 = System.currentTimeMillis();
        // 原子类AtomicInteger,CAS操作,表示请求的数量。
        requestCount.incrementAndGet();
        StandardWrapper wrapper = (StandardWrapper) getContainer();
        Servlet servlet = null;
        Context context = (Context) wrapper.getParent();

        // 检查当前的Context应用是否已经被标注为不可以使用
        if (!context.getState().isAvailable()) {
            // 如果当前应用不可以使用的话,就报503错误。
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                    sm.getString("standardContext.isUnavailable"));
            unavailable = true;
        }

        // 检查Servelt是否被标记为不可使用
        if (!unavailable && wrapper.isUnavailable()) {
            container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
                    wrapper.getName()));
            long available = wrapper.getAvailable();
            if ((available > 0L) && (available < Long.MAX_VALUE)) {
                response.setDateHeader("Retry-After", available);
                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                        sm.getString("standardWrapper.isUnavailable",
                                wrapper.getName()));
            } else if (available == Long.MAX_VALUE) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND,
                        sm.getString("standardWrapper.notFound",
                                wrapper.getName()));
            }
            unavailable = true;
        }
        // Servelt是第一次调用的时候初始化
        try {
            if (!unavailable) {
                // 如果此时Servelt还没有被初始化,就分配一个Servelt实例来处理request请求。
                servlet = wrapper.allocate();
            }
        /// 省略代码..........................................
        // // 给该request创建Filter过滤链。Filter过滤链执行完之后,会执行Servelt
        ApplicationFilterChain filterChain =
                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

        // Call the filter chain for this request
        // NOTE: This also calls the servlet's service() method
        try {
            if ((servlet != null) && (filterChain != null)) {
                // Swallow output if needed
                if (context.getSwallowOutput()) {
                    try {
                        SystemLogHandler.startCapture();
                        if (request.isAsyncDispatching()) {
                            request.getAsyncContextInternal().doInternalDispatch();
                        } else {
                            // 调用过滤链
                            filterChain.doFilter(request.getRequest(),
                                    response.getResponse());
                        }
        /// 省略代码..........................................

到此这篇关于Tomcat源码解析之Web请求与处理的文章就介绍到这了,更多相关Tomcat的Web请求与处理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • IDEA 配置Tomcat服务器和发布web项目的图文教程

    1.创建好web项目之后,现在需要配置服务器,以Tomcat为例 2.选择Run-Edit Configurations 3.点击右上角 + 号,选择2处展开剩下选项 4.找到Tomcat Server,然后选择Local Server 5.设置Tomcat服务器显示名,选择Configure 6.选择Tomcat在磁盘中的安装位置 7.确认之后会自动识别出Tomcat服务器 8.确定之后会自动识别出访问路径和端口 9.选择部署选项,然后点击右边的 + ,弹出的项目中选择Artfact 10.在

  • 解决SpringBoot webSocket 资源无法加载、tomcat启动报错的问题

    问题描述: 1. 项目集成WebSocket,且打包发布tomcat时出现websocket is already in CLOSING or CLOSE state这样的问题,建议参考"解决方法二",但是"解决方法一"请要了解查看 ,因为解决方法二是在一的基础上进行更正 2. 如果出现javax.websocket.server.ServerContainer not available这样的错误,请参考"解决方法一"中步骤3 解决方法一:(常

  • IDEA2020.1.2创建web项目配置Tomcat的详细教程

    本文章是一篇IDEA创建web项目配置Tomcat的整合文章,并非原创,原文链接 https://blog.csdn.net/qq_45738810/article/details/107842532 https://www.cnblogs.com/shindo/p/7272646.html 作为初学者,先看了第一个链接里大佬的文章又看其他的文章表示很懵,为了避免各位和我一样,所以在此整合一下,希望能帮到各位! 第一步,先创建一个普通的Java项目 第二步,创建web项目.右键项目名–>Add

  • idea配置tomcat启动web项目的图文教程

    配置tomcat 1.点击run configuration 2.选择tomcat local 3.配置tomcat 4.部署web项目 部署有2种方式 war包:打成war置于服务器运行,这种方式我们比较常见. war exploded:将web工程以当前文件夹的位置关系上传到服务器.就是直接把文件夹.jsp页面 .classes等移到Tomcat 部署文件夹里面,进行加载部署.因此这种方式支持热部署,一般在开发的时候也是用这种方式. 中方式获取上下文绝对路径不一样: String conte

  • 简述Docker安装Tomcat镜像并部署web项目

    一.安装Tomcat 1.查找Docker Hub上的tomcat镜像 docker search tomcat 2.拉取官方的镜像 docker pull tomcat 等待下载完毕,需要一些时间. 3.查看docker所有的镜像 docker images 4.启动tomcat镜像 注:前者是外围访问端口:后者是容器内部端口 docker run -d -p 8080:8080 tomcat 注:前者是外围访问端口:后者是容器内部端口 如下命令可后台启动tomcat -d: 后台运行容器,并

  • 使用IDEA创建Web项目并发布到tomcat的操作方法

    Web开发 1.web开发概述 •学习web开发,需要先安装一台web服务器,将开发好的web项目部署在web服务器中供外界访问. WEB服务器有很多,流行的WEB服务器有Tomcat. WebSphere .WebLogic.Jboss等. 在小型的应用系统或者有特殊需要的系统中,可以使用一个免费的Web服务器: Apache 的Tomcat,该服务器支持全部JSP以及Servlet规范. Tomcat安装配置 Tomcat官方站点:http://tomcat.apache.org 获取Tom

  • Tomcat首次部署web项目流程图解

    将自己的web项目放进tomcat目录下的webapps目录下 根据里面ROOT的web.xml文件 里面的头文件,删除html语句后 新建自己的项目 html文件是用的随便找了个菜鸟教程的html语句 利用http://localhost:8080/mystudy/ 打开文件(有可能显示404 我是等了一会 自己就好了 如果还不行 重启tomcat试试) 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们.

  • 如何在IntelliJ IDEA 2018上配置Tomcat并运行第一个JavaWeb项目

    1 下载和启动Tomcat 进入官网 http://tomcat.apache.org/ ,下载最新版本的Tomcat 9 根据自己的电脑版本下载,我这里是windows 64位 下载完之后解压即可. 找到自己解压目录,打开文件夹下面的/bin目录,其中startup.bat是启动tomcat,shutdown.bat 是关闭tomcat 双击startup.bat启动tomcat后,打开 http://localhost:8080 ,若进入下面的界面则表示启动成功了. 2 在win10中为To

  • Tomcat和Weblogic部署纯html文件过程解析

    1.首先纯html文件,得有一个入口 index.html 2.Tomcat是不需要指定web.xml的,因为即使你的文件里没有web.xml,也会读取conf 目录下的web.xml,在这个文件里边指定了index.html的入口 Tomcat的话只要将原文件部署到 webapps\ 目录下,或者在\conf\Catalina\localhost 目录下新建xml文件,指向html页面 <?xml version='1.0' encoding='utf-8'?> <Context do

  • Spring Boot如何移除内嵌Tomcat,使用非web方式启动

    前言:当我们使用Spring Boot编写了一个批处理应用程序,该程序只是用于后台跑批数据,此时不需要内嵌的tomcat,简化启动方式使用非web方式启动项目,步骤如下: 1.修改pom.xml文件 在pom.xml文件中去除内嵌tomcat,添加servlet依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</

  • Java web项目启动Tomcat报错解决方案

    点击运行项目时显示 A Java Exception has occurred. 'Starting Tomcat v9.0 Server at localhost' has oncountered a problem. Server Tomcat v9.0 Server at localhost failed tostart. 并显示以下两个弹框 同时控制台报错org.apache.catalina.startup.Bootstraporg.apache.catalina.startup.Bo

  • 阿里云服务器linux系统搭建Tomcat部署Web项目

    整个过程我给它分成四个步骤: 下载并安装jdk 下载并安装Tomcat 配置阿里云服务器信息 部署web项目 使用的工具:Xshell.WinSCP. 没有安装jdk的小伙伴点击上方超链接跳转到安装jdk博客 下载并安装Tomcat 到这个网页下查看最新的镜像:https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat 使用工具Xshell操作Linux系统 移动到home目录下载tomcat 下载 wget https://mirrors.tuna.t

  • 在IDEA 2020.3.1中部署Tomcat并且创建第一个web项目的过程详解

    Tomcat介绍 Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache.Sun 和其他一些公司及个人共同开发而成.由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范.因为Tomcat 技术先进.性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前

  • 解决tomcat发布工程后,WEB-INF/classes下文件不编译的问题

    今天部署项目到tomcat,发布完后,启动tomcat,报class not found: 临时找了个解决方案,由于项目是copy过来的,于是就将原来项目的classes下面编译好的class文件也一并拷过来了:但是治标不治本: 后来在我修改代码的时候,重新发布到tomcat,发现新写的代码还是没有自动编译:classes下面还是没有class文件: 于是找解决方法:我是按照下面操作成功的: 1)在java build path下面删除原来的jre,重新导入jre: 2)删掉所有引用的jar包,

随机推荐