在嵌入式Jetty中的相同端口上启动Web服务和休息

时间:2015-11-30 15:50:21

标签: java spring web-services rest jetty

我在同一个端口上运行了SOAP Web服务和我的REST api。这是使用Spring 4.1.2 / CXF 2.7.15 / Jetty 8.1.16。现在我将我的版本升级到Spring 4.2.3 / CXF 3.1.4 / Jetty 9.3.6。似乎我可以在同一端口上安装SOAP Web服务或REST,具体取决于在启动期间首先在代码中添加的内容。我怎样才能让他们在同一时间再次工作?

更新

正在运行的代码示例:

import org.apache.cxf.endpoint.ServerImpl;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.http_jetty.JettyHTTPDestination;
import org.apache.cxf.transport.http_jetty.JettyHTTPServerEngine;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import my.package.app.DefaultApp;
import my.package.misc.jmx.JMXAgent;
import my.package.misc.xmpp.XmppManager;
import my.package.rest.standalone.JacksonJsonProvider;
import my.package.util.PropertyUtil;
import my.package.webservice.user.UserWs;
import javax.servlet.DispatcherType;
import javax.xml.ws.Endpoint;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class StartApp extends DefaultApp {
    private static final Logger log = LoggerFactory.getLogger(StartApp.class);
    private static boolean started;
    // TODO: move this to SPRING
    protected static ExecutorService startupExecutor = Executors.newFixedThreadPool(10);

    // setting DNS caching to 1 hour
    static {
        java.security.Security.setProperty("networkaddress.cache.ttl", "3600");
    }

    private class ServiceStartTask implements Callable<Void> {
        private Endpoint endpoint;
        private String address;
        private int port;
        private String name;
        private Class implementor;
        private boolean startRest;
        private String packages;

        public ServiceStartTask(Endpoint endpoint, String address, int port, String name, Class implementor, boolean startRest, String packages) {
            this.endpoint = endpoint;
            this.address = address;
            this.port = port;
            this.name = name;
            this.implementor = implementor;
            this.startRest = startRest;
            this.packages = packages;
            log.debug("address = {} port = {} name = {} ", address, port, name);
        }

        @Override
        public Void call() {
            String baseUrl = "http://" + address + ":" + port + "/";
            String wsUrl = baseUrl + name;
            String restUrl = baseUrl + "rest";

            log.info("Export ws on: " + wsUrl);
            try {
                endpoint = Endpoint.create(DefaultApp.getBean(implementor));

                additionalJettySetup(endpoint, wsUrl, restUrl, implementor.getPackage().getName(), startRest, packages + ",my.package.rest.common");

            } catch (Exception e) {
                log.error("error publishing service " + wsUrl, e);
            }
            return null;
        }
    }

    private Endpoint endpointUser;

    public StartApp() {
    }

    public void start() {
        String[] s = {};
        start(s);
    }


    public void start(String[] args) {
        if (started) {
            return;
        }

        earlyInit();

        long startTime = System.currentTimeMillis();

        registerShutdownHook();

        init();

        if (PropertyUtil.getPropertyBoolean("jmx.enabled")) {
            startJMX();
        }

        String address;
        if (args.length == 0) {
            address = "localhost";
        } else {
            address = args[0];
        }

        publishWebServices(address);

        log.debug("starting rest services");
        // separate jetty instance for additional rest services
        int restPort = PropertyUtil.getPropertyInteger("rest.port");
        startRest(address, restPort, "my.package.rest.standalone");
        log.debug("rest services started");


        started = true;

        final long startupTime = System.currentTimeMillis() - startTime;
    }


    /**
     * Setup all Jetty properties that cannot be configured in spring xml.
     *
     * @param endpoint
     * @param restUrl
     * @param domain
     * @param startRest
     * @throws IOException
     */
    protected synchronized void additionalJettySetup(Endpoint endpoint, String wsUrl, String restUrl, String domain, boolean startRest, String packages) throws IOException {
        if (endpoint instanceof EndpointImpl) {
            // finding Jetty Server object
            EndpointImpl endpointJetty = (EndpointImpl) endpoint;
            // loging interceptors needs to be added before endpoint.getServer call
            addInterceptors(endpointJetty);

            ServerImpl server = endpointJetty.getServer(wsUrl);
            if (endpointJetty.getServerFactory().getDestinationFactory().getDestination(server.getEndpoint().getEndpointInfo()) instanceof JettyHTTPDestination) {
                JettyHTTPDestination d = (JettyHTTPDestination) endpointJetty.getServerFactory().getDestinationFactory().getDestination(server.getEndpoint().getEndpointInfo());
                JettyHTTPServerEngine engine = (JettyHTTPServerEngine) d.getEngine();
                if (startRest) {
                    log.info("Also starting REST service at {}", restUrl);
                    setRestConfig(engine, packages);
                }
                // publishing and starting the server
                endpoint.publish(wsUrl);
                // finally server is found
                Server jetty = engine.getServer();
                addJettyMBeans(domain, jetty);

            }
        }
    }

    private void addInterceptors(EndpointImpl endpointJetty) {
        //adding some endpoint interceptors
    }

    /**
     * Sets REST configuration for an existing server
     *
     * @param engine
     * @param packages
     */
    private void setRestConfig(final JettyHTTPServerEngine engine, final String packages) {

        List<Handler> handlers = engine.getHandlers();
        ServletContextHandler root = new ServletContextHandler(ServletContextHandler.SESSIONS);

        setRestServletAndApplicationContext(root, packages, "/rest/*");

        handlers.add(root);
    }

    /**
     * Adds to JMX Jetty object that will be monitored.
     */
    protected void addJettyMBeans(String domain, Server jetty) {
        log.debug("creating MBeanContainer");
        MBeanContainer mbContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
        mbContainer.setDomain(domain);
        jetty.getContainer().addEventListener(mbContainer);
        jetty.addBean(mbContainer);
        // Adding bean that we want to be exposed to JMX
        mbContainer.addBean(jetty.getConnectors()[0]);
        mbContainer.addBean(jetty);
        mbContainer.addBean(jetty.getThreadPool());
    }

    protected void startJMX() {
        try {
            JMXAgent.premain();
        } catch (Throwable e) {
            log.error("JMX agent startup error", e);
        }
    }

    private void startRest(final String address, final int restPort, final String packages) {
        startupExecutor.submit(new Runnable() {
            @Override
            public void run() {
                startRestfullServer(address, restPort, packages);
            }
        });
    }

    private void startRestfullServer(final String address, final int restPort, final String packages) {
        log.info("Starting REST service at port {}", restPort);
        Server server = new Server(restPort);
        try {
            ServletContextHandler root = new ServletContextHandler(ServletContextHandler.SESSIONS);
            setRestServletAndApplicationContext(root, packages + ",some.package", "/*");

            server.setHandler(root);
            server.setStopAtShutdown(true);
            server.setGracefulShutdown(1000);

            server.start();
            server.join();

        } catch (Exception e) {
            log.error("error", e);
            try {
                server.stop();
            } catch (Exception e1) {
                log.error("error", e);
            }
        }
    }

    private void setRestServletAndApplicationContext(ServletContextHandler root, String packages, String servletPath) {
        root.setContextPath("/");

        ResourceConfig resourceConfig = new ResourceConfig();
        resourceConfig.packages("org.codehaus.jackson.jaxrs;" + packages);

        // using our custom mapping provider
        resourceConfig.register(JacksonJsonProvider.class);
        // processing multipart
        resourceConfig.register(MultiPartFeature.class);

        resourceConfig.register(io.swagger.jaxrs.listing.ApiListingResource.class);
        resourceConfig.register(io.swagger.jaxrs.listing.SwaggerSerializers.class);

        ServletContainer ss = new ServletContainer(resourceConfig);

        ServletHolder servletHolder = new ServletHolder(ss);


        root.addServlet(servletHolder, servletPath);
        setUpSwagger();
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.copyConfigurationFrom(getContext().getBeanFactory());

        // CORS filter to allow swagger to be used from Swagger UI on another host
        root.addFilter(CrossOriginFilter.class, "/*", EnumSet.of(DispatcherType.INCLUDE, DispatcherType.REQUEST));

        /**
         * The trick is that Jersey expect WebApplication context and we need to mask our context as web context
         * so we create a WebApplicationContext and makes methods that Jersey uses to return from spring context.
         */
        final GenericWebApplicationContext webApplicationContext = new GenericWebApplicationContext(beanFactory) {
            @Override
            public String[] getBeanNamesForType(Class<?> type) {
                return getParent().getBeanNamesForType(type);
            }

            @Override
            public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
                return getParent().getBean(name, requiredType);
            }

            @Override
            public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
                return getParent().getBeansOfType(type);
            }
        };

        webApplicationContext.setServletContext(root.getServletContext());
        webApplicationContext.setParent(getContext());
        root.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, webApplicationContext);
        webApplicationContext.refresh();
    }

    private void setUpSwagger() {
        //settting up swagger
    }

    public void stop() {
        log.info("Stopping ALL WSs");

        getBean(XmppManager.class).send("Going off...!");

        if (endpointUser != null) {
            endpointUser.stop();
        }
    }

    private void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                log.info("Shutdown hook for StartApp executed");
                StartApp.this.stop();
            }
        });
    }

    private void publishWebServices(String address) {
        int portUser = PropertyUtil.getPropertyInteger("webservice.user.port");
        List<ServiceStartTask> services = new ArrayList<>();
        services.add(publish(endpointUser, address, portUser, "user", UserWs.class, true, "rest.endpoint.package"));
        for (ServiceStartTask task : services) {
            task.call();
        }
    }

    private <T> ServiceStartTask publish(Endpoint endpoint, String address, int port, String name, Class<T> implementor, boolean startRest, String packages) {
        return new ServiceStartTask(endpoint, address, port, name, implementor, startRest, packages);
    }

    public static void main(String[] args) {
        try {
            new StartApp().start(args);
        } catch (Exception e) {
            log.error("Error starting app!", e);
            System.exit(1);
        }
    }
}

在Spring中声明的Jetty引擎:

                                                             

<!-- Jetty parameters -->
<httpj:engine-factory bus="cxf">
    <!-- user -->
    <httpj:engine port="${webservice.user.port}">
        <httpj:threadingParameters minThreads="5"
                                   maxThreads="100"/>
        <httpj:connector>
            <beans:bean class="org.eclipse.jetty.server.nio.SelectChannelConnector">
                <beans:property name="port" value="${webservice.user.port}"/>
                <beans:property name="statsOn" value="false"/>
            </beans:bean>
        </httpj:connector>
        <httpj:handlers>
            <beans:bean class="org.eclipse.jetty.server.handler.DefaultHandler"/>
        </httpj:handlers>
        <httpj:sessionSupport>true</httpj:sessionSupport>
    </httpj:engine>
</httpj:engine-factory>

0 个答案:

没有答案