spring使用内置jetty创建提供http接口服务

1、添加pom文件依赖

<dependency>
	<groupId>org.eclipse.jetty</groupId>
	<artifactId>jetty-server</artifactId>
	<version>9.4.22.v20191022</version>
</dependency>
<dependency>
	<groupId>org.eclipse.jetty</groupId>
	<artifactId>jetty-deploy</artifactId>
	<version>9.4.22.v20191022</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-web</artifactId>
	<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>5.2.9.RELEASE</version>
</dependency>

2、编写代码

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;

/**
 * Spring root context keeper
 */
@Component
public class ApplicationContextKeeper implements ApplicationContextAware {

    private static WebApplicationContext webAppCtx;

    @Override
    public void setApplicationContext(ApplicationContext appCtx)
            throws BeansException {
        XmlWebApplicationContext xmlWebAppCtx = new XmlWebApplicationContext();
        xmlWebAppCtx.setParent(appCtx);
        xmlWebAppCtx.setConfigLocation("");
        xmlWebAppCtx.setClassLoader(appCtx.getClassLoader());
        xmlWebAppCtx.refresh();
        xmlWebAppCtx.registerShutdownHook();
        webAppCtx = xmlWebAppCtx;
    }

    public static WebApplicationContext getWebAppCtx() {
        return webAppCtx;
    }

}
import org.eclipse.jetty.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

/**
 * 服务生命周期辅助程序, 用于:
 * 1. 优雅关闭API服务, 加入JVM钩子, 保护数据.
 * 2. 可用于缓存持久化至数据库, 文件等操作
 */
public final class Bootstrap implements Lifecycle, InitializingBean, ApplicationListener<ContextRefreshedEvent> {
    private static final Logger LOG = LoggerFactory.getLogger(Bootstrap.class);

    private Server jettyServer;

    @Value("${rest.status}")
    private int status;

    @Value("${server.port}")
    private int port;

    /**
     * The set of registered LifecycleListeners for event notifications.
     */
    private LifecycleListener[] listeners = new LifecycleListener[0];

    private final Object listenersLock = new Object(); // Lock object for changes to listeners

    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        synchronized (listenersLock) {
            LifecycleListener[] results = new LifecycleListener[listeners.length + 1];
            System.arraycopy(listeners, 0, results, 0, listeners.length);
            results[listeners.length] = listener;
            listeners = results;
        }
    }

    @Override
    public void removeLifecycleListener(LifecycleListener listener) {
        synchronized (listenersLock) {
            int n = -1;
            for (int i = 0; i < listeners.length; i++) {
                if (listeners[i] == listener) {
                    n = i;
                    break;
                }
            }
            if (n < 0) {
                return;
            }
            LifecycleListener[] results = new LifecycleListener[listeners.length - 1];
            int j = 0;
            for (int i = 0; i < listeners.length; i++) {
                if (i != n) {
                    results[j++] = listeners[i];
                }
            }
            listeners = results;
        }
    }

    /**
     * @return true: no error, false: has error
     */
    private boolean doStop() {
        try {
            jettyServer.stop(); // 1. Gracefully shutdown

            // 2
            for (LifecycleListener listener : listeners) {
                listener.lifecycleEvent(new LifecycleEvent(this, Lifecycle.AFTER_STOP_EVENT));
            }
            return true;
        } catch (Exception e) {
            LOG.error("Shutdown jetty server error: ", e);
        }
        return false;
    }

    @Override
    public void afterPropertiesSet() {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            if (doStop()) {
                LOG.info("Shutdown completed");
            } else {
                LOG.warn("Shutdown completed with error, please check logs !!!");
            }
        }));
        LOG.info("Added JVM shutdown hook ...");
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getParent() == null) { // Notify when ROOT CONTEXT loaded
            try {
                /*
                 * Start Jetty container after all bean have been initialize.
                 *
                 * 1.In case of load big data from DB slowly but the WEB PORT
                 *   have been open, some request maybe send to here but
                 *   application can't process them.
                 *
                 * 2. Jetty will parse web.xml, DispatcherServlet need WebApplicationContext to make
                 *    handlerMapping (URL -> process bean), so if the Spring Container haven't load
                 *    controllers specified on "springmvc-context.xml" and Jetty parse web.xml,
                 *    springmvc maybe not found the beans, finally will throw 404 error to client.
                 */
                if (status == 1) {
                    jettyServer.start();
                    System.out.println("Start http server on port:" + port);
                }
            } catch (Exception e) {
                LOG.error("Start jetty server error: ", e);
                System.exit(1);
                throw new RuntimeException(e);
            }
        }
    }

    public void setJettyServer(Server jettyServer) {
        this.jettyServer = jettyServer;
    }

}
import org.springframework.web.servlet.DispatcherServlet;
public class CustomDispatcherServlet extends DispatcherServlet {

    private static final long serialVersionUID = 1L;

    public CustomDispatcherServlet() {
        super(ApplicationContextKeeper.getWebAppCtx());
    }

}
public interface Lifecycle {

    String BEFORE_START_EVENT = "before_start";
    String AFTER_START_EVENT = "after_start";

    String BEFORE_STOP_EVENT = "before_stop"; // Before jetty gracefully shutdown
    String AFTER_STOP_EVENT = "after_stop"; // After jetty gracefully shutdown

    void addLifecycleListener(LifecycleListener listener);

    void removeLifecycleListener(LifecycleListener listener);

}

import java.util.EventObject;

public class LifecycleEvent extends EventObject {
    private static final long serialVersionUID = 1L;

    /**
     * The event type this instance represents.
     */
    private final String type;

    public LifecycleEvent(Object source, String type) {
        super(source);
        this.type = type;
    }

    public String getType() {
        return type;
    }

}

/**
 * Interface defining a listener for significant events (including "server
 * start" and "server stop")
 */
public interface LifecycleListener {

    /**
     * Acknowledge the occurrence of the specified event.
     *
     * @param event LifecycleEvent that has occurred
     */
    void lifecycleEvent(LifecycleEvent event);

}

3、配置bean

<bean id="bootstrap" class="com.xuanwu.msggate.mto.mos.server.Bootstrap">
	<property name="jettyServer" ref="jettyServer" />
</bean>

4、配置mvc注解驱动

<mvc:annotation-driven />

通过mvc:annotation-driven/配置,Spring MVC会启用对注解的支持,使得可以在控制器类和方法上使用注解来定义请求映射、参数绑定等操作。

具体来说,mvc:annotation-driven/会启用以下功能:
支持@Controller注解,用于标识控制器类
支持@RequestMapping注解,用于定义请求映射
支持@RequestParam注解,用于绑定请求参数
支持@ResponseBody注解,用于将方法返回值直接作为HTTP响应体返回
支持@PathVariable注解,用于绑定URI模板变量

注意: 如果没有mvc注解支持。则会出现No mapping for POST

5、添加jetty配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
           http://www.springframework.org/schema/context 
           http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<bean id="contextHandlerCollection" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"></bean>
	
	<bean id="jettyServer" class="org.eclipse.jetty.server.Server" destroy-method="stop">
		<constructor-arg name="pool">
			<bean class="org.eclipse.jetty.util.thread.QueuedThreadPool">
				<constructor-arg name="minThreads" value="${rest.api.jetty.poolSize.minThreads}" />
				<constructor-arg name="maxThreads" value="${rest.api.jetty.poolSize.maxThreads}" />
			</bean>
		</constructor-arg>
		<property name="stopAtShutdown" value="true" />
		<property name="stopTimeout" value="3000" />
		<property name="connectors">
			<array>
				<bean class="org.eclipse.jetty.server.ServerConnector">
					<constructor-arg name="server" ref="jettyServer" />
					<property name="port" value="${server.port}" />
					<property name="acceptQueueSize" value="1024" />
				</bean>
			</array>
		</property>
		<property name="handler">
			<bean class="org.eclipse.jetty.server.handler.HandlerCollection">
				<property name="handlers">
					<list>
						<ref bean="contextHandlerCollection" />
					</list>
				</property>
			</bean>
		</property>
		<property name="beans">
			<list>
				<ref bean="deploymentManager" />
			</list>
		</property>
	</bean>
	
	<bean id="deploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
		<property name="contexts" ref="contextHandlerCollection" />
		<property name="appProviders">
			<list>
				<ref bean="webAppProvider" />
			</list>
		</property>
	</bean>
	
	<bean id="webAppProvider" class="org.eclipse.jetty.deploy.providers.WebAppProvider">
		<property name="monitoredDirName" value="${webapps.dir}webapps" />
		<property name="scanInterval" value="5" />
		<property name="extractWars" value="true" />
		<property name="configurationManager">
			<bean class="org.eclipse.jetty.deploy.PropertiesConfigurationManager" />
		</property>
	</bean>
	
</beans>

6、在spring中导入

<import resource="classpath:/com/xuanwu/msggate/mto/mos/jetty-context.xml"/>

7、创建webapps目录并创建web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
	<display-name>rest api</display-name>
	
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>com.xuanwu.msggate.rest2mtreceiver.server.CustomDispatcherServlet</servlet-class>
		<init-param>
			<param-name>detectAllHandlerAdapters</param-name>
			<param-value>true</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>

	<!-- Spring字符集过滤器      建议放前面 不然拦截可能有问题-->
	<filter>
		<filter-name>SpringEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>SpringEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<filter>
		<filter-name>HttpRequestFilter</filter-name>
		<filter-class>com.xuanwu.msggate.rest2mtreceiver.rest.filter.HttpRequestFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>HttpRequestFilter</filter-name>
		<url-pattern>/api/authorization/*</url-pattern>
	</filter-mapping>

</web-app>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值