一.好处
保证了Java程序的稳定运行,可以避免类的重复加载。保证了Java的核心API不被篡改。
二.源码
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 检查是否已经加载过
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
// 存在父加载器,交给父加载器加载
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// Bootstrap类加载器加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
// 父加载器无法加载,自己加载
if (c == null) {
c = findClass(name);
}
}
return c;
}
}
三.如何打破双亲委派机制
1.自定义类加载器,重写loadClass方法。
2.线程上下文类加载器。
public class Test {
public static void main(String[] args) throws SQLException {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select * from t1");
while(resultSet.next()) {
System.out.println(resultSet.getString("name"));
}
}
}
不用写Class.forName加载驱动类。
DriverManager.getConnection触发DriverManager的加载,类加载器是启动类加载器。
public class DriverManager {
static {
loadInitialDrivers();
}
private static void loadInitialDrivers() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
while(driversIterator.hasNext()) {
// 加载驱动类
driversIterator.next();
}
} catch(Throwable t) {
}
return null;
}
});
}
}
ServiceLoader.load
public static <S> ServiceLoader<S> load(Class<S> service) {
// AppClassLoader
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader)
{
return new ServiceLoader<>(service, loader);
}
加载驱动类
private S nextService() {
Class<?> c = null;
try {
// cn:com.mysql.cj.jdbc.Driver(META-INF/services/java.sql.Driver)
// loader:AppClassLoader
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
}
}
四.tomcat类加载器
Tomcat允许同时运行多个Web程序,每个Web程序依赖的类必须是相互隔离的,因为可能会依赖同一个第三方类库的不同版本。使用WebappClassLoader加载应用程序中的Class,只对当前webapp可见,对Tomcat和其他Web应用程序不可见。
Common类加载器,负责加载Tomcat和Web应用都复用的类。
Catalina类加载器,负责加载Tomcat专用的类,而这些被加载的类在Web应用中将不可见。
Shared类加载器,负责加载Tomcat下所有的Web应用程序都复用的类,而这些被加载的类在Tomcat中将不可见。
commonLoader,catalinaLoader,sharedLoader 现在是同一个对象(URLClassLoader)。