- 浏览: 514529 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (563)
- 工作经验 (12)
- 数据库 (13)
- Servlet (10)
- Struts2 (1)
- Spring (25)
- Eclipse (5)
- Hibernate (5)
- Eclips (8)
- HTTP (7)
- J2EE (21)
- EHcache (1)
- HTML (11)
- 工具插件使用 (20)
- JPA (2)
- 杂谈 (17)
- 数据结构与算法 (3)
- Cloud Foundry (1)
- 安全 (10)
- J2SE (57)
- SQL (9)
- DB2 (6)
- 操作系统 (2)
- 设计模式 (1)
- 版本代码管理工具 (13)
- 面试 (10)
- 代码规范 (3)
- Tomcat (12)
- Ajax (5)
- 异常总结 (11)
- REST (2)
- 云 (2)
- RMI (3)
- SOA (1)
- Oracle (12)
- Javascript (20)
- jquery (7)
- JSP自定义标签 (2)
- 电脑知识 (5)
- 浏览器 (3)
- 正则表达式 (3)
- 建站解决问题 (38)
- 数据库设计 (3)
- git (16)
- log4j (1)
- 每天100行代码 (1)
- socket (0)
- java设计模式 耿祥义著 (0)
- Maven (14)
- ibatis (7)
- bug整理 (2)
- 邮件服务器 (8)
- Linux (32)
- TCP/IP协议 (5)
- java多线程并发 (7)
- IO (1)
- 网页小工具 (2)
- Flash (2)
- 爬虫 (1)
- CSS (6)
- JSON (1)
- 触发器 (1)
- java并发 (12)
- ajaxfileupload (1)
- js验证 (1)
- discuz (2)
- Mysql (14)
- jvm (2)
- MyBatis (10)
- POI (1)
- 金融 (1)
- VMWare (0)
- Redis (4)
- 性能测试 (2)
- PostgreSQL (1)
- 分布式 (2)
- Easy UI (1)
- C (1)
- 加密 (6)
- Node.js (1)
- 事务 (2)
- zookeeper (3)
- Spring MVC (2)
- 动态代理 (3)
- 日志 (2)
- 微信公众号 (2)
- IDEA (1)
- 保存他人遇到的问题 (1)
- webservice (11)
- memcached (3)
- nginx (6)
- 抓包 (1)
- java规范 (1)
- dubbo (3)
- xwiki (1)
- quartz (2)
- 数字证书 (1)
- spi (1)
- 学习编程 (6)
- dom4j (1)
- 计算机系统知识 (2)
- JAVA系统知识 (1)
- rpcf (1)
- 单元测试 (2)
- php (1)
- 内存泄漏cpu100%outofmemery (5)
- zero_copy (2)
- mac (3)
- hive (3)
- 分享资料整理 (0)
- 计算机网络 (1)
- 编写操作系统 (1)
- springboot (1)
最新评论
-
masuweng:
亦论一次OutOfMemoryError的定位与解错 -
变脸小伙:
引用[color=red][/color]百度推广中运用的技术 ...
Spring 3 mvc中返回pdf,json,xml等不同的view -
Vanillva:
不同之处是什么??
Mybatis中的like查询 -
thrillerzw:
转了。做个有理想的程序员
有理想的程序员必须知道的15件事 -
liujunhui1988:
觉得很有概括力
15 个必须知道的 Java 面试问题(2年工作经验)
源: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.
评:
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.
发表评论
-
NullPointerException丢失异常堆栈信息
2017-09-25 11:23 1016源:http://blog.csdn.net/taotao4/ ... -
JAVA实现SFTP实例
2016-04-20 19:10 487源:http://www.cnblogs.com/chen19 ... -
Axis1.x WebService开发指南—目录索引
2015-11-30 15:54 641源:http://www.cnblogs.com/hoojo/ ... -
CXF WebService整合Spring
2015-11-30 15:50 503源:http://www.cnblogs.com/hoojo/ ... -
几种常用的webservice客户端和spring集成的方法
2015-11-30 15:47 562源:http://my.oschina.net/zimingf ... -
serialVersionUID的作用
2015-11-08 15:27 580源:http://www.cnblogs.com/gu ... -
(未解决问题)Tomcat undeploy does not remove web application artifacts
2015-09-18 11:26 554源:http://stackoverflow.com/ques ... -
使用 VisualVM 进行性能分析及调优
2015-08-25 21:26 494源:http://www.ibm.com/develo ... -
使用Java VisualVM监控远程JVM
2015-08-25 21:25 744源:http://blog.163.com/liuyb_942 ... -
获取spring的ApplicationContext几种方式
2015-06-24 15:35 699源:http://blog.sina.com.cn/s/blo ... -
转:Java 理论与实践: 用 JMX 检测应用程序
2015-06-17 21:26 419源:http://www.ibm.com/developerw ... -
Developing a Service Provider using Java API(Service Provider Interface)
2015-04-15 15:52 632源:http://blog.csdn.net/fenglibi ... -
如何使用webservice
2015-04-09 15:47 5271:到http://cxf.apache.org/downlo ... -
spring获取webapplicationcontext,applicationcontext几种方法详解
2015-04-02 16:38 467源:http://www.blogjava.net/Todd/ ... -
【java规范】Java spi机制浅谈
2015-01-27 10:52 453源:http://singleant.iteye.com/bl ... -
REGISTRY KEY 'SOFTWARE\JAVASOFT\JAVA RUNTIME ENVIRONMENT\CURRENTVERSION'错误
2015-01-21 20:17 590源:http://www.blogjava.net/tomor ... -
Spring线程池开发实战
2014-12-12 10:44 499源:http://blog.csdn.net/chszs/ar ... -
在web.xml下配置error-page
2014-07-18 16:13 429源:http://ysj5125094.iteye.com/b ... -
什么是流
2013-04-05 17:41 959源:http://www.iteye.com/topic/3 ... -
什么是J2EE,包括哪些规范!
2013-01-17 14:17 820源:http://blog.163.com/xiaopeng ...
相关推荐
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....
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 ...
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 ...
<rich:panelBarItem label="Write your own custom rich components with built-in AJAX support"> Component Development Kit (CDK) is a design-time extension for Ajax4jsf. The CDK includes... ...
<rich:panelBarItem label="Write your own custom rich components with built-in AJAX support"> Component Development Kit (CDK) is a design-time extension for Ajax4jsf. The CDK includes... ...
Create your own POP3 client to retrieve e-mails from mail server. Source code + tutorial.<END><br>26 , chat.zip This code shows you how to creat a local network chat room so that you and your ...
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 ...
The Server must run on a Domain Controller.<END><br>39 , Reboot.zip This conveniently placed program allows you to restart your computer more easily, from your system tray. <END><br>40 , ...
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 ...
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...