`
MauerSu
  • 浏览: 513470 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Write your own Java server

    博客分类:
  • J2EE
 
阅读更多
源:http://srcode.org/2014/05/11/write-your-own-java-server/
评:


Classloaders are on the dark side of Java. If you want to implement your own Java server to manage the lifecycle of your services and modules, you probably have to deal with these monsters. Normally you start up a Java program like this: $ java -classpath my_lib.jar MyMainClass, where MyMainClass contains the main function. The program will have access to the my_lib.jar defined by -classpath or -cp. However, the reality is you have tons of jars to load, and more jars are added as you programs grows. Now you might start to think about writing a script to maintain the list of jars. If you have only a couple of jars, say, less than 10, this probably is not a problem, while if you have 50 or more jars to load, you quickly blow your script up. So we needs a smarter way to manage our jars. Think about when you deploy a web application with Tomcat, Tomcat automatically recognizes the jars and classes you dropped in the WEB-INF/lib and WEB-INF/classes folder. So what’s the magic? Before running into code, let’s take a look at how Java’s classloaders work together to load all these jars and classes.

Java classloadersJava classloaders

From top to bottom, the bootstrap classloader is managed by the JDK or JRE, which loads all the core java classes shipped with the JRE, like the java.io and javax.swing. Extension classloader loads up the classes you put in the ext folder in your JRE. If your program needs to access the serial ports, sometimes you put those com port access api libraries there. The system classloader loads classes from your classpath where you defined in the java startup script. So the real magic is here in the blue boxes. We can futher make our own classloader to load jars and classes wherever we want.

First, let’s create a folder called our_app as the root of our Java server application. Inside the root folder, we have a lib folder to hold all the jars and a classes folder to hold all the calsses. This is going to be the standard layout of our app. Then we create the Bootstrap class to load the jars and classes in the lib and classes folder, respectively.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72



package boot;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

public class Bootstrap {

private static final String CP_CLASSES = "classes";
private static final String CP_LIB = "lib";

public static void main(String[] args) throws Exception {
List<File> jarList = new ArrayList<File>();
getClassPath(jarList, new File(getServerHome(), CP_LIB));
URL[] urlList = toURL(jarList);
URLClassLoader loader = new URLClassLoader(urlList);
Class c = loader.loadClass(args[0]);
Method m = c.getMethod("main", new Class[] { args.getClass() });
String[] appArgs = new String[args.length - 1];
System.arraycopy(args, 1, appArgs, 0, args.length - 1);
m.invoke(null, new Object[] { appArgs });
}

private static URL[] toURL(List<File> list) throws IOException {
List<URL> urlList = new ArrayList<URL>();
urlList.add(new URL("file:///" + getServerHome() + "/" + CP_CLASSES + "/"));
for (int i = 0; i < list.size(); ++i) {
urlList.add(new URL("file:///" + ((File) list.get(i)).getCanonicalPath()));
}
return (URL[]) urlList.toArray(new URL[0]);
}

private static Filter filter = new Filter();

private static void getClassPath(List<File> list, File f) {
if (f.exists() && f.isDirectory()) {
File[] ss = f.listFiles(filter);
for (int i = 0; i < ss.length; ++i) {
if (ss[i].isFile()) {
list.add(ss[i]);
} else if (ss[i].isDirectory()) {
getClassPath(list, ss[i]);
}
}
}
}

private static class Filter implements FilenameFilter {
public boolean accept(File dir, String name) {
File f = new File(dir, name);
boolean isDir = f.isDirectory();
boolean isFile = f.isFile();
boolean isJar = name.toLowerCase().endsWith(".jar");
boolean isZip = name.toLowerCase().endsWith(".zip");
return (isFile && (isJar || isZip)) || isDir;
}
}

private static String getServerHome() {
String serverHome = System.getProperty("server.home");
if (serverHome == null) {
serverHome = new File(System.getProperty("user.dir")).getParent();
System.setProperty("server.home", serverHome);
}
return serverHome;
}
}

The Bootstrap class uses a URLClassLoader classloader to search for all jars and classes from the lib and classes folders. When the search is done, it’s ready to invoke the real application’s main method using this instance of the URLClassLoader.

Then let’s compile and package the Bootstrap class to loader.jar. The loader.jar is a tiny utility jar that we use to further load and manage our real java application.

1
2
3
4
5
6
7
8
9



$ javac boot/Bootstrap.java
Note: boot/Bootstrap.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$
$ jar cvf loader.jar boot/*.class
added manifest
adding: boot/Bootstrap$1.class(in = 188) (out= 151)(deflated 19%)
adding: boot/Bootstrap$Filter.class(in = 883) (out= 535)(deflated 39%)
adding: boot/Bootstrap.class(in = 3046) (out= 1565)(deflated 48%)

Now let’s create a bin folder under the application root, and move the newly created loader.jar to the bin folder. Next create a script called startup.sh and place it in bin. The startup.sh will try its best to detect where your java is. Once java executable is found, it will launch the loader we just created, and invoke our real application.
startup.sh

1
2
3
4
5
6
7
8
9
10
11
12



#!/bin/bash

if [[ $(which ${JAVA_HOME}/bin/java) ]]; then
    exe="${JAVA_HOME}/bin/java"
elif [[ $(which java) ]]; then
    exe="java"
else
    echo "Java environment is not detected."
    exit 1
fi

${exe} -cp loader.jar boot.Bootstrap com.my.Main "Hello world"

Finally, let’s create our real, and really simple demo application, and package it into com.my.Main class. The source code is really simple as below. It prints the first parameter passed in if there is, otherwise, it prints “Hello.”.

1
2
3
4
5
6
7
8
9
10
11



package com.my;

public class Main {
public static void main(String[] args) {
if (args.length > 0) {
System.out.println(args[0]);
} else {
System.out.println("Hello.");
}
}
}

Compile it, package it into our_app.jar, drop it into the lib folder, and we are ready to go.

1
2
3
4
5
6
7
8
9
10



$ javac com/my/Main.java
$
$ java com/my/Main "Hello world"
Hello world
$ java com/my/Main
Hello.
$
$ jar cvf our_app.jar com/**/*.class
added manifest
adding: com/my/Main.class(in = 466) (out= 324)(deflated 30%)

Now the layout of our_app should look something like this:

1
2
3
4
5
6



|____bin
| |____loader.jar
| |____startup.sh
|____classes
|____lib
| |____our_app.jar

Go into the bin folder, and run ./start.sh. Boom, it says Hello world as expected.

1
2
3



$ cd bin
$ ./startup.sh
Hello world

Here is the link to download the sample code and script.
分享到:
评论

相关推荐

    Learning.Node.js.for..NET.Developers.epub

    Build an interactive web application with MongoDB and Redis and create your own JavaScript modules that work both on the client side and server side Familiarize yourself with the new features of Node....

    spring-boot-reference.pdf

    46. Creating Your Own Auto-configuration 46.1. Understanding Auto-configured Beans 46.2. Locating Auto-configuration Candidates 46.3. Condition Annotations 46.3.1. Class Conditions 46.3.2. Bean ...

    外文翻译 stus MVC

    This article introduces Struts, a Model-View-Controller implementation that uses servlets and JavaServer Pages (JSP) technology. Struts can help you control change in your Web project and promote ...

    richface标签.doc

    &lt;rich:panelBarItem label="Write your own custom rich components with built-in AJAX support"&gt; Component Development Kit (CDK) is a design-time extension for Ajax4jsf. The CDK includes... ...

    Richfaces标签

    &lt;rich:panelBarItem label="Write your own custom rich components with built-in AJAX support"&gt; Component Development Kit (CDK) is a design-time extension for Ajax4jsf. The CDK includes... ...

    VB编程资源大全(英文源码 网络)

    Create your own POP3 client to retrieve e-mails from mail server. Source code + tutorial.&lt;END&gt;&lt;br&gt;26 , chat.zip This code shows you how to creat a local network chat room so that you and your ...

    AkkaScala.pdf

    It leverages the actor model of computation, enabling developers to write scalable and resilient applications that can handle massive amounts of traffic and data. The core of Akka lies in its ...

    VB编程资源大全(英文源码 控制)

    The Server must run on a Domain Controller.&lt;END&gt;&lt;br&gt;39 , Reboot.zip This conveniently placed program allows you to restart your computer more easily, from your system tray. &lt;END&gt;&lt;br&gt;40 , ...

    python3.6.5参考手册 chm

    PEP 3333: Python Web Server Gateway Interface v1.0.1 Other Language Changes New, Improved, and Deprecated Modules email elementtree functools itertools collections threading datetime and time ...

    ZendFramework中文文档

    Cascading Write Operations 10.8.6.1. Notes Regarding Cascading Operations 11. Zend_Debug 11.1. 输出变量的值 (Dumping Variables) 12. Zend_Exception 12.1. 使用“异常” 13. Zend_Feed 13.1. 介绍 ...

    操作系统(内存管理)

    /* We own it */ memory_location = current_location; /* Leave the loop */ break; } } /* If we made it here, it's because the Current memory * block not suitable; move...

Global site tag (gtag.js) - Google Analytics