从数据库读取JAR并加载到Classpath中
来源:互联网 发布:清除session php 编辑:程序博客网 时间:2024/06/05 18:30
在组件的开发过程中,我们可能会用到组件上传功能,这个时候就会将JAR等其它信息都存放到数据库,在应用初使化的时候,将组件的JAR从数据库中读出来,并一起加载到Classpath中。
我们可以分成几以下几布操作:
1、将JAR字节数据从数据库中读出来存到本地JAR文件;
1.1 将JAR字节数据从数据库读到内存中
/** * Load jar byte data from database into byte array. * * @param conn * @return * @throws SQLException */private static byte[] getJarBlobDataFromDatabase(Connection conn) throws SQLException {byte[] allBytesInBlob = null;PreparedStatement stmnt = conn.prepareStatement("select blobdata from table");// ExecuteResultSet rs = stmnt.executeQuery();if (rs.next()) {// Get as a BLOBBlob aBlob = rs.getBlob(1);allBytesInBlob = aBlob.getBytes(1, (int) aBlob.length());}// Close resourcesrs.close();stmnt.close();return allBytesInBlob;}
1.2 将读出来的字节数据,写为本地文件:
/** * Write the jar byte data into file * * @param strFilePath * @param bytes * @throws IOException */public static void writeFile(String strFilePath, byte[] bytes) throws IOException {FileOutputStream fos = new FileOutputStream(strFilePath);fos.write(bytes);fos.flush();fos.close();}
2、通过URLClassLoader将文件Jar加载到Classpath中。
URLClassLoader可以将本地JAR文件,网络上的JAR都可以加载到classpath中,实现代码如下:
/** * Add jar file into classpath. * * @param jarFile * @param addMainfestClasspath * tell the load if load the class-path in the mainfest file. * @throws IOException */public static void addJarFileToClasspath(File jarFile, boolean addMainfestClasspath) throws IOException {List<URL> urls = new ArrayList<URL>(5);urls.add(jarFile.toURI().toURL());if (addMainfestClasspath) {JarFile jf = new JarFile(jarFile);Manifest mf = jf.getManifest(); // if jar has a class-path in// manfist// add it's entries. That means we// should get it's dependency jar// before// add this jar to classpathif (mf != null) {String cp = mf.getMainAttributes().getValue("class-path");if (cp != null) {for (String cpe : cp.split("\\s+")) {File lib = new File(jarFile.getParentFile(), cpe);urls.add(lib.toURI().toURL());}}}jf.close();}URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();Class<? extends URLClassLoader> sysclass = URLClassLoader.class;try {Method method = sysclass.getDeclaredMethod("addURL", URL.class);method.setAccessible(true);for (URL url : urls) {method.invoke(sysloader, url);}} catch (Throwable t) {throw new IOException("Error, could not add URL to system classloader", t);}}
以上这一段代码,实现将jar文件加载到classpath,以及控制参数可以控制是否加载mainfest文件中class-path指定的jar。
这里需要注意一下的是我们是如何将jar加载到系统的classpath中,通过代码:
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
获取到系统的Classloader,然后通过反射将要加入到系统classpath的jar的URL加入到系统的Classloader的classpath中,之所以要通过反射才能够加进去,那是因为addURL这个方法是protected,不能允跨包调用:
Method method = sysclass.getDeclaredMethod("addURL", URL.class);method.setAccessible(true);for (URL url : urls) {method.invoke(sysloader, url);}
这样我们就实现了将自已的JAR加入到了系统的classpath(通常这里是AppClassLoader)中,我们在其它地方就可以通过Class.forName或classLoader.loadClass进行加载了。
3、测试
以下是这个测试是否成功将jar加到了我们的系统的classloader中:
/** * @param args * @throws SQLException */public static void main(String[] args) {//omit conn initConnection conn = null;try {byte[] bytes = getJarBlobDataFromDatabase(conn);String location = "d:/test.jar";writeFile(location, bytes);addJarFileToClasspath(new File(location), true);// Get a class from the jarClass clz = Thread.currentThread().getContextClassLoader().loadClass("com.test.TestClass");// If this can print and no exception. That means we load the jar successfully.System.out.println(clz);} catch (Exception e) {e.printStackTrace();} finally {if (conn != null) {try {conn.close();} catch (SQLException e) {}}}}
补充说明:
1、上面我们提到了通过反射将jar的URL加到系统的的URLClassLoader中,如果我们只是需要jar在当前生命周期之内有效,那我们可以不通过反射这种方式操作,我们可以新起一个classloader:
public static ClassLoader addJarFileToNewClasspath(File jarFile, boolean addMainfestClasspath) throws IOException {List<URL> urls = new ArrayList<URL>(5);urls.add(jarFile.toURI().toURL());if(addMainfestClasspath){JarFile jf = new JarFile(jarFile);Manifest mf = jf.getManifest(); if (mf != null) {String cp = mf.getMainAttributes().getValue("class-path");if (cp != null) {for (String cpe : cp.split("\\s+")) {File lib = new File(jarFile.getParentFile(), cpe);urls.add(lib.toURI().toURL());}}}jf.close();}// End forClassLoader cl = null;if (urls.size() > 0) {cl = new URLClassLoader(urls.toArray(new URL[urls.size()]),ClassLoader.getSystemClassLoader());}return cl;}
这里的实现差别就是new了一个classloader,虽然指定了其parent classloader,但是在使用的时候,必须使用当前new出来的class loader才可以找到类,因为新的jar中的class并没有被加到当前系统的classloader中,因而我们在使用的时候,就需要如下使用:
/** * @param args * @throws SQLException */public static void main(String[] args) {//Omit conn initConnection conn = null;try {byte[] bytes = getJarBlobDataFromDatabase(conn);String location = "d:/test.jar";writeFile(location, bytes);ClassLoader cl = addJarFileToNewClasspath(new File(location),true);// Get a class from the jarClass clz = cl.loadClass("com.ubs.sae.business.service.starrclient.Good");// If this can print and no exception. That means we load the jar into classpath successfully.System.out.println(clz);} catch (Exception e) {e.printStackTrace();} finally {if (conn != null) {try {conn.close();} catch (SQLException e) {}}}}并且我们不能够使用当前classloader的loadClass方法,不能够使用Class.forName方法,因为Class.forName是到当前的系统classloader去查找的,而上面通过反射将jar加到当前系统的classloader中,此时在不考虑类是否会被初使化的情况下,使用classloader的loadClass方法或者是Class.forName都可以找到我们需要的类。
2、说一下classloader的loadClass与Class.forName的区别吧,就是Class.forName会对类进行初使化,如执行类中的静态块,而classloader的loadClass方法不会,根据不同的使用场景进行选择了,如果类中没有需要初使化的静态块,那就是两个都可以随便选择了。
- 从数据库读取JAR并加载到Classpath中
- linux网络编程 从配置文件中读取配置并加载到变量中
- 将图片保存到数据库表中及从数据库表中读取图片并显示
- 使用Apache POI创建Excel,并从数据库中读取数据写入到Excel文件中
- c#从excel中读取数据并添加到数据库中
- 自定义类加载器-从.class和.jar中读取
- 从数据库中读取数据到Excel
- 从数据库中读取二进制文件,并将图片打印到页面上
- java代码实现利用 classloader 动态加载 jar包、文件夹到classpath中
- 从jar 包中读取文件,并且复制到jar包的目录中
- 从配置文件读取相应的信息加载到应用程序中
- 从文本文件中读取数据排序并输出到文本
- 从数据库中读取并生成图片的Servlet
- 从数据库中读取Blob对象图片并显示
- 从数据库中读取并生成图片的Servlet
- 从数据库中读取blob字段并生成图片文件
- C#从数据库中读取二进制数据,并显示图片
- 从数据库中读取二进制字符并转化为图片
- Error listenerStart 错误,Tomcat终极排错杀手
- Handler的基本使用(1)之更新progressBar
- 如何创建一个滑出式导航面板(2)
- android ndk 编译ffmpeg+x264
- AlertDialog显示错误 Unable to add window token null is not for an application
- 从数据库读取JAR并加载到Classpath中
- Android 异步下载图片并缓存到本地以节约网络流量
- 如果编程语言是女人
- asp.net使用Cookies实现购物车
- cxGrid中行property为image
- oracle 使用总结 导入 ,导出,创建用户,授权等
- DeepLearning(深度学习)原理与实现(五)
- [小代码]简化android Log,显示调用类和函数名
- minSdkVersion、targetSdkVersion、targetApiLevel的区别