基于jetty 自制Java Web Server 容器
基于jetty 自制Java Web Server 容器
张宋付 发表于8年前
基于jetty 自制Java Web Server 容器
  • 发表于 8年前
  • 阅读 1601
  • 收藏 7
  • 点赞 0
  • 评论 3

【腾讯云】新注册用户域名抢购1元起>>>   

 

1.main class 如下;
public final class Bootstrap {
	//~ Static fields/initializers ============================================= 
	
	private static final String SHUTDOWN = "SHUTDOWN";
    private static final String RELOAD = "RELOAD";
	
	//~ Instance fields ========================================================

	private Logger logger;
	
	private Server server;
	
    /**
     * The port number on which we wait for shutdown commands.
     */
    private int port;

    /**
     * A random number generator that is only used if
     * the shutdown command string is longer than 1024 characters.
     */
    private Random random = null;
	
	//~ Constructors ===========================================================
	
	private Bootstrap() {
		
	}

	//~ Methods ================================================================
	
	private Logger getLogger() {
		if (logger == null) {
			logger = LoggerFactory.getLogger(getClass());
		}
		return logger;
	}
	
	public void init() {
		String painiuHome = System.getProperty("net365.home", System.getProperty("user.dir", "."));

		String configDir = System.getProperty("net365.config.dir");
		if (configDir == null) {
			configDir = painiuHome + File.separator + "etc" + File.separator;
		}
		if (!configDir.endsWith(File.separator)) {
			configDir += File.separator;
		}
		
		String configFile = configDir + "net365.properties";
		Map vars = new HashMap();
		vars.put("home", painiuHome);
		Configuration.initialize(configFile, vars);
		
		initLoggingSystem(configDir);
		
		port = Configuration.getInteger("server.shutdown.port", 8014);
	}
	
	private void initLoggingSystem(String configDir) {
		File loggingConfigFile = new File(configDir, "logging.properties");
		if (loggingConfigFile.exists()) {
			System.setProperty("java.util.logging.config.file", loggingConfigFile.getAbsolutePath());
		}
		File log4jConfigFile = new File(configDir, "log4j.properties");
		if (log4jConfigFile.exists()) {
			PropertyConfigurator.configure(log4jConfigFile.getAbsolutePath());
		}
	}
	
	public void startServer() throws Exception {
		getLogger().info("Bootstrap: Starting Server...");
		
		server = new Server();
		server.initialize();
		
		server.setGracefulShutdown(Configuration.getInteger("server.shutdown.timeout", 0));
		server.setStopAtShutdown(true);
		
		server.start();
	}
	
	public void stopServer() throws Exception {
		getLogger().info("Bootstrap: Stopping Server...");
		server.stop();
	}
	
	public static void main(String[] args) {
		Bootstrap bootstrap = new Bootstrap();
		
		try {
			bootstrap.init();
			
			String command = "start";
			if (args.length > 0) {
				command = args[args.length - 1];
			}

			if (command.equals("start")) {
				bootstrap.startServer();
				bootstrap.await();
				bootstrap.stopServer();
			} else if (command.equals("stop")) {
				bootstrap.stop();
			} else if (command.equals("restart")) {
				bootstrap.stop();
				// give me 2 seconds to shutdown the server
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {}
				bootstrap.startServer();
				bootstrap.await();
				bootstrap.stopServer();
			} else if (command.equals("reload")) {
				bootstrap.reload();
			}
			
			System.exit(0);
		} catch (Throwable t) {
			t.printStackTrace();
		}
	}
	
	public void stop() {
		sendCommand(SHUTDOWN);
	}

	public void reload() {
		sendCommand(RELOAD);
	}
	
	private void sendCommand(String command) {
		try {
            Socket socket = new Socket("127.0.0.1", port);
            OutputStream stream = socket.getOutputStream();
            for (int i = 0; i < command.length(); i++) {
                stream.write(command.charAt(i));
            }
            stream.flush();
            stream.close();
            socket.close();
        } catch (IOException e) {
            getLogger().error("IOException occurred: ", e);
        }
	}
	
	public void await() {
		// Set up a server socket to wait on
        ServerSocket serverSocket = null;
        try {
            serverSocket =
                new ServerSocket(port, 1,
                                 InetAddress.getByName("127.0.0.1"));
        } catch (IOException e) {
            getLogger().error("Bootstrap.await: create[" + port + "]: ", e);
            System.exit(1);
        }

        // Loop waiting for a connection and a valid command
        while (true) {

            // Wait for the next connection
            Socket socket = null;
            InputStream stream = null;
            try {
                socket = serverSocket.accept();
                socket.setSoTimeout(10 * 1000);  // Ten seconds
                stream = socket.getInputStream();
            } catch (AccessControlException ace) {
                getLogger().warn("StandardServer.accept security exception: " + ace.getMessage(), ace);
                continue;
            } catch (IOException e) {
                getLogger().error("StandardServer.await: accept: ", e);
                System.exit(1);
            }

            // Read a set of characters from the socket
            StringBuffer command = new StringBuffer();
            int expected = 1024; // Cut off to avoid DoS attack
            while (expected < SHUTDOWN.length()) {
                if (random == null)
                    random = new Random(System.currentTimeMillis());
                expected += (random.nextInt() % 1024);
            }
            while (expected > 0) {
                int ch = -1;
                try {
                    ch = stream.read();
                } catch (IOException e) {
                    getLogger().warn("Bootstrap.await: read: ", e);
                    ch = -1;
                }
                if (ch < 32)  // Control character or EOF terminates loop
                    break;
                command.append((char) ch);
                expected--;
            }

            // Close the socket now that we are done with it
            try {
                socket.close();
            } catch (IOException e) {
            }

            // Match against our command string
            if (command.toString().equals(SHUTDOWN)) {
                break;
            } else if (command.toString().equals(RELOAD)) {
            	try {
					server.reload();
				} catch (Exception e) {
					getLogger().error("Bootstrap.reloading failed", e);
				}
            } else {
                getLogger().warn("Bootstrap.await: Invalid command '" +
                                   command.toString() + "' received");
            }
        }

        // Close the server socket and return
        try {
            serverSocket.close();
        } catch (IOException e) {
        }

	}

}


2.server class 如下:

public class Server extends org.mortbay.jetty.Server {
	//~ Static fields/initializers =============================================

	private static final Logger logger = LoggerFactory.getLogger(Server.class);
	
	//~ Instance fields ========================================================
	
	private ClassPathXmlApplicationContext applicationContext;
	private Handler webapp;
	private RemotingServer remotingServer;
	
	
	//~ Constructors ===========================================================

	public Server() {
	}
	
	//~ Methods ================================================================
	
	private void initApplicationContext() {
		String configLocation = Configuration.get("spring.config.location", "applicationContext*.xml");
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
		context.setConfigLocation(context.CLASSPATH_ALL_URL_PREFIX + configLocation);
		context.refresh();
		applicationContext = context;
	}
	
	//private void initYPFS() {
	//	YPFS.initialize(null);
	//}
	
	private SecurityHandler createSecurityHandler() {
		return new SecurityHandler();
	}

	private SessionHandler createSessionHandler() {
		//SessionManager sessionManager = (SessionManager) applicationContext.getBean("jettySessionManager");
		//if (sessionManager == null) {
		//	logger.error("SessionManager not configured! use default: HashSessionManager");
		SessionManager sessionManager = new HashSessionManager();
		//}
		sessionManager.setSessionDomain("." + Configuration.get("webapp.domain"));
		return new SessionHandler(sessionManager);
	}
	
	private ErrorHandler createErrorHandler() {
		ErrorHandler handler = new ErrorHandler();
		handler.setShowStacks(Configuration.getBoolean("devmode", false));
		return handler;
	}
	
	public void reload() throws Exception {
		applicationContext.refresh();
		webapp.stop();
		webapp.start();
	}
	
	public void initialize() throws Exception {
		initApplicationContext();
		//initYPFS();
		
		Connector connector = new SelectChannelConnector();
		connector.setPort(Configuration.getInteger("server.port", 8080));
		setConnectors(new Connector[] { connector });
		
		webapp = initWebAppHandler();
		
		if (Configuration.getBoolean("devmode", false)) {
			// setup static context for development
			List handlers = new ArrayList(3);
			handlers.add(webapp);
			if (Configuration.get("server.media.vhosts") != null) {
				handlers.add(initStaticContext());
			}
			
			ContextHandlerCollection contexts = new ContextHandlerCollection();
			contexts.setHandlers(handlers.toArray(new Handler[handlers.size()]));
			setHandler(contexts);
		} else {
			setHandler(webapp);
		}
	}
	
	private Handler initStaticContext() {
		ResourceHandler staticHandler = new ResourceHandler();
		ContextHandler staticContext = new ContextHandler();
		staticContext.setContextPath("/");
		staticContext.setResourceBase(Configuration.get("server.media.war"));
		staticContext.setHandler(staticHandler);
		
		String vhosts = Configuration.get("server.media.vhosts", "");
		logger.info("Starting media server, vhosts: {}", vhosts);
		staticContext.setVirtualHosts(StringUtils.split(vhosts));

		return staticContext;
	}
	
	/* (non-Javadoc)
	 * @see org.mortbay.jetty.Server#doStop()
	 */
	@Override
	protected void doStop() throws Exception {
		logger.info("Shutting down...");
		super.doStop();
		
		if (remotingServer != null) {
			logger.info("Stopping remoting server...");
			remotingServer.stop();
		}
		
		applicationContext.destroy();
	}

	
	private Handler initWebAppHandler() throws IOException {
		WebAppContext context = new WebAppContext(createSecurityHandler(), createSessionHandler(), null, createErrorHandler());
		context.setDefaultsDescriptor("com/net365/server/jetty/webdefault.xml");
		context.setContextPath(Configuration.get("webapp.contextPath", "/"));
		context.setWar(Configuration.get("server.war"));
		context.setExtractWAR(false);
		context.setParentLoaderPriority(true);
		context.setTempDirectory(new File(Configuration.get("server.tmpDir")));
		context.setAttribute(B2CEshop.APPLICATION_CONTEXT_KEY, applicationContext);

		if (Configuration.getBoolean("devmode", false)) {
			String vhosts = Configuration.get("server.vhosts", "");
			logger.info("Starting server in DevMode, vhosts: {}", vhosts);
			context.setVirtualHosts(StringUtils.split(vhosts));
		}
		
		InputStream in = null;
		
		try {
			Resource resource = context.getWebInf().addPath("urlrewrite.xml");
			if (resource == null || !resource.exists()) {
				logger.error("Url rewrite rules not found, url rewrite will not be supported");
				return context;
			}
			in = resource.getInputStream();
			
			RewriteHandler handler = new RewriteHandler();
			handler.setHandler(context);
			handler.setRules(loadRewriteRules(in));
			handler.setActionExtension(Configuration.get("webapp.action.extension"));
			
			return handler;
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					logger.error("Error closing urlrewrite configuration file", e);
				}
			}
		}
	}
	
	private static Rule[] loadRewriteRules(InputStream in) {		
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setValidating(true);
        factory.setNamespaceAware(true);
        factory.setIgnoringComments(true);
        factory.setIgnoringElementContentWhitespace(true);
        
        DocumentBuilder parser;
        try {
            parser = factory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            logger.error("Unable to setup XML parser for reading conf", e);
            return null;
        }
        
        DefaultHandler handler = new DefaultHandler();
        parser.setErrorHandler(handler);
        parser.setEntityResolver(handler);

        List rules = new ArrayList();
        
        try {
            Document doc = parser.parse(in);
            
            Element rootElement = doc.getDocumentElement();
            NodeList categoryList = rootElement.getChildNodes();
            for (int i = 0; i < categoryList.getLength(); i++) {
                Node node = categoryList.item(i);

                if (node.getNodeType() == Node.ELEMENT_NODE &&
                        ((Element) node).getTagName().equals("category")) {
                	String categoryName = getAttrValue(node, "name");
                	
                	NodeList ruleList = node.getChildNodes();
                	
                	for (int j = 0; j < ruleList.getLength(); j++) {
                		Node subNode = ruleList.item(j);
                		
                		if (subNode.getNodeType() == Node.ELEMENT_NODE &&
                				((Element) subNode).getTagName().equals("rule")) {
                			Element ruleElement = (Element) subNode;
                			
                			RewriteRegexRule rule = new RewriteRegexRule();
                			rule.setCategory(categoryName);
                			rule.setRegex(getNodeValue(ruleElement.getElementsByTagName("from").item(0)));
                			rule.setReplacement(getNodeValue(ruleElement.getElementsByTagName("to").item(0)));

                			rules.add(rule);
                		}
                	}
                }
            }
        } catch (SAXParseException e) {
            logger.error("Parse error on line " + e.getLineNumber() + " " + e.getMessage(), e);
        } catch (Exception e) {
            logger.error("Exception loading conf " + e.getMessage(), e);
        }
        
        return rules.toArray(new Rule[rules.size()]);
	}
	
	private static String getNodeValue(Node node) {
        if (node == null) return null;
        NodeList nodeList = node.getChildNodes();
        if (nodeList == null) return null;
        Node child = nodeList.item(0);
        if (child == null) return null;
        if ((child.getNodeType() == Node.TEXT_NODE)) {
            String value = ((Text) child).getData();
            return value.trim();
        }
        return null;
    }
	
    private static String getAttrValue(Node n, String attrName) {
        if (n == null) return null;
        NamedNodeMap attrs = n.getAttributes();
        if (attrs == null) return null;
        Node attr = attrs.getNamedItem(attrName);
        if (attr == null) return null;
        String val = attr.getNodeValue();
        if (val == null) return null;
        return val.trim();
    }
}

这个其中一个小段,还有一些我的应用中加入的。哈哈。。

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 28
博文 15
码字总数 11591
评论 (3)
张宋付
选用jetty原因就是想让在分布式中能有更快成本更低JAVA WEB服务器。哈哈。
红薯
俺多年以前的作品: http://www.ibm.com/developerworks/cn/java/l-hsqldb/index.html
张宋付
呵呵。hsqldb是一个小型DB系统。对于内嵌也是相当不错的。
×
张宋付
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: