目前将工程代码打成jar包,又为了升级方便,自己的Jar包需要放到自定义目录,而非lib目录,所以需要系统启动时,先将自定义jar包加载好。
暂时使用的是写了一个自定义类继承了org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter类,在init方法中,将需要加载的外部类,实使用URLClassLoader加载进内存,具体如下:
CustomizeStrutsFilter.java
package cn.com.agama.efioc.boottrap;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import org.apache.log4j.Logger;
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter;
import cn.com.agama.efioc.core.StartBackgroudTask;
/**
* 自定义Filter,用于加载非lib目录下的jar包
* @author YangQi
* @since JDK1.4
* @version 2014-4-9
*/
public class CustomizeStrutsFilter extends StrutsPrepareAndExecuteFilter {
private static FindAllJars jarStore = null;
private final static boolean devMode = false ;
private URLClassLoader classLoader = null ;
private Logger logger = org.apache.log4j.Logger.getLogger(this.getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
if (!devMode) {
String dir = filterConfig.getInitParameter("efioc.pluginDir") ;
logger.debug("initparamter efioc.pluginDir-->"+dir);
String webDir = filterConfig.getServletContext().getRealPath(dir);
try {
loadJarsToApplication(webDir);
} catch (Exception e) {
e.printStackTrace();
}
}
super.init(filterConfig);
systemInit();
}
private void systemInit() {
logger.debug("Begin Start Efioc System!");
if (devMode) {
logger.debug("The System is Running in Development Mode!");
StartBackgroudTask backgroundTask = new StartBackgroudTask();
backgroundTask.startTask(null);
} else {
logger.debug("The System is Running in Release Mode!");
try {
Class<?> startupClass = classLoader
.loadClass("cn.com.agama.efioc.core.StartBackgroudTask");
Object startupInstance = startupClass.newInstance();
Class<?>[] classList = new Class<?>[1];
classList[0] = Object.class;
logger.debug("class-->"+startupClass);
java.lang.reflect.Method aMethod = startupClass.getMethod("startTask",classList);
Object[] objArray = new Object[1];
objArray[0] = classLoader;
aMethod.invoke(startupInstance, objArray);
} catch (Exception e) {
e.printStackTrace();
}
}
logger.debug("Start Efioc System Success!");
}
/**
* 加载jar到ClassLoader中。
* <p>主要是通过反射调用addURL方法,将外部jar包的URL传入到系统loader中加载<p>
* <p>Tomcat默认的是WebAppClassLoader
* @param webDir
* @throws Exception
*/
private void loadJarsToApplication(String webDir) throws Exception{
jarStore = new FindAllJars(webDir);
URL[] jarList = jarStore.getURLList();
logger.debug("Current Loader---->"+Thread.currentThread().getContextClassLoader());
classLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
Method add = URLClassLoader.class.getDeclaredMethod("addURL",new Class[] { URL.class });
add.setAccessible(true);
for(URL obj : jarList){
add.invoke(classLoader, new Object[]{obj} );
}
}
}
对应的web,xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 设置获取根目录的属性名 -->
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>efioc_root</param-value>
</context-param>
<!-- 加载struts2 -->
<filter>
<filter-name>efioc</filter-name>
<!--
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
-->
<filter-class>cn.com.agama.efioc.boottrap.CustomizeStrutsFilter</filter-class>
<init-param>
<param-name>config</param-name>
<param-value>struts-default.xml,
struts.xml</param-value>
</init-param>
<init-param>
<param-name>efioc.pluginDir</param-name>
<param-value>/</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>efioc</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
FindAllJars.jar类
package cn.com.agama.efioc.boottrap;
import java.io.File;
import java.io.FilenameFilter;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* 加载所需模块jar包
* @author YangQi
* @since JDK1.4
* @version 2014-4-4
*/
public class FindAllJars {
private List<String> searchPath = new ArrayList<String>();
private URL[] urlList = null;
private String currentDir = null;
public FindAllJars(String webPath){
this.currentDir = webPath ;
searchPath.add("plugin");
}
public URL[] getURLList() throws Exception {
searchJars();
return urlList ;
}
private void searchJars() throws Exception {
List<URL> jarList = new ArrayList<URL>();
for (int i = 0; i < searchPath.size(); i++) {
String path = (String) searchPath.get(i);
File aDir = new File(currentDir + "/" + path);
File[] files = searchDir(aDir);
if (null == files) {
continue;
}
for (int j = 0; j < files.length; j++) {
File aJar = files[j];
jarList.add(aJar.toURI().toURL());
}
}
urlList = new URL[jarList.size()];
for (int i = 0; i < jarList.size(); i++) {
urlList[i] = (URL) jarList.get(i);
}
}
private File[] searchDir(File input) throws Exception {
File[] files = input.listFiles(new MyFilenameFilter());
return files;
}
class MyFilenameFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
if (name.indexOf(".jar") > 0) {
return true;
} else {
return false;
}
}
}
}
MyEclipse工程目录结构为
这样做的好处是可以将所有代码包,打成jar包后,放于plugin目录,如果有代码调整需要升级,可以直接替换jar包后,重新load。