日期:2014-05-16  浏览次数:20514 次

自定义的类装载器-从DB装载class(附上对类装载器的分析)
代码才是最实在的,先从代码开始,然后再一步一步分析:
第一步:写个类用来装载
public class MyClassLoaderTest implements MyClassLoaderTestInterface {

    public MyClassLoaderTest() {
        System.out.println("MyClassLoaderTest构造函数被调用了...");
    }
    
    public void sayHello(String name) {
        System.out.println("Hello " + name + " 我是sayHello函数,我被调用了...");
    }
    
    public class InnerClassTest {
        public InnerClassTest() {}
        public void print() {
            System.out.println("内部类");
        }
    }
}

package com.jvm.one.loadclassfromdb;

public interface MyClassLoaderTestInterface {
    void sayHello(String name);
}


第二步:把编译后的class文件插入DB(MySql)
1.单独写个连接DB的类
package com.jvm.one.loadclassfromdb;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConnectDB {
    
    /**
     * 驱动程序名
     */
    private static final String driver = "com.mysql.jdbc.Driver";
    
    /**
     * URL指向要访问的数据库名
     */
    private static final String url = "jdbc:mysql://localhost:3306/classloader_test?useUnicode=true&characterEncoding=UTF-8";
    
    /**
     * 用户名
     */
    private static final String user = "root";
    
    /**
     * 密码
     */
    private static final String password = "141421";

    public static Connection getConnnection() {
        
        Connection conn = null;
        try {
            Class.forName(driver);
            //连接数据库
            conn = DriverManager.getConnection(url, user, password);
            if (!conn.isClosed())
                System.out.println("数据库连接成功...");
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            try {
                if (null != conn) conn.close();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }
        return conn;
    }
    
    public static void closeConnection(Connection conn) {
        try {
            if (null != conn) {
                conn.close();
                System.out.println("数据库连接关闭...");
            } else {
                System.out.println("数据库连接不存在...");
            }
        } catch (SQLException e1) {
            e1.printStackTrace();
        }
    }
}

这里插一句,由于Class.forName函数也跟ClassLoader有关,这里有点问题也解释下
平常我们都习惯使用Class.forName(driver)这种方式装载JDBC驱动,但是Class.forName只是返回Class对象,并没有返回driver的实例,也就是说driver并没有被实例化,为什么不需要实例化呢,很多人有这样的困惑,所以他们这么写代码:
Class.forName(driver).newInstance()

其实这样写是没有必要的,代码是最真实的,我们看看MySql的jdbc驱动源码片段:
代码来自com.mysql.jdbc.Driver
	static {
		try {
			java.sql.DriverManager.registerDriver(new Driver());
		} catch (SQLException E) {
			throw new RuntimeException("Can't register driver!");
		}
	}

下面代码来自java.lang.Class
public static Class<?> forName(String className) 
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }

    private static native Class forName0(String name, boolean initialize,
					    ClassLoader loader)
	throws ClassNotFoundException;

boolean initialize参数为true的时候,在装载类的同时会初始化(注意不是调用构造函数),类被初始化时类中的静态语句块会被执行,所以Class.forName(driver);执行的时候已经有一个驱动的实例被注册到DriverManager中了,好了,这个问题告一段落,接着贴代码

2.建表
CREATE TABLE `classfile` (
  `classname` varchar(200) NOT NULL,
  `classcode` blob NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=gbk;

3.将class文件的内容插入DB
package com.jvm.one.loadclassfromdb;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import j