JVM学习笔记9

bilibili-深入理解JVM 虚拟机 学习笔记

JVM学习笔记 1
JVM学习笔记 2
JVM学习笔记 3
JVM学习笔记 4
JVM学习笔记 5
JVM学习笔记 6
JVM学习笔记 7
JVM学习笔记 8

P27_线程上下文类加载器分析与实现(27)

当前类加载器

每个类都会使用自己的类加载器(加载当前类的类加载器)去加载自己所依赖的(且还未加载的)类。


线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。
类 java.lang.Thread 中的方法 getContextClassLoader() 和 setContextClassLoader(ClassLoader cl) 用来获取和设置线程的上下文类加载器。

如果没有通过 setContextClassLoader(ClassLoader cl) 方法进行设置的话,线程将继承其父线程的上下文类加载器。
Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。


父 ClassLoader 可以使用 线程上下文类加载器 加载的类(Thread.currentThread().getContextClassLoader()),这就改变了父加载器不能使用子加载器或没有父子关系的类加载器所加载的类的情况,即改变了双亲委托模型。

在这里插入图片描述


常见的SPI(Service Provider Interface):

  1. JDBC (Java Database Connectivity )

https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/

https://docs.oracle.com/javase/tutorial/jdbc/basics/index.html

  1. JCE (Java Cryptography Extension) s

Java加密扩展是Java平台的正式发布的标准扩展,是Java加密体系结构的一部分。JCE提供了用于加密,密钥生成和密钥协商以及消息认证码算法的框架和实现。JCE补充了Java平台,该平台已经包含消息摘要和数字签名的接口和实现。安装特定于所使用的Java平台版本,可下载Java 6,Java 7和Java 8。

https://www.oracle.com/java/technologies/javase-jce8-downloads.html

  1. JNDI (Java Naming and Directory Interface)

Java命名和目录接口,是Java的一个目录服务应用程序接口,它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。

https://docs.oracle.com/javase/jndi/tutorial/getStarted/overview/index.html

https://docs.oracle.com/javase/tutorial/jndi/overview/index.html

  1. JBI (Java Business Integration)

Java Business Integration 是在Java Community Process 下开发的规范,用于实现面向服务的体系结构的方法。JCP参考是用于JBI 1.0的JSR 208和用于JBI 2.0的JSR 312。提交者于2010年12月17日将JSR 312从JCP投票过程中删除,但未获得接受。

  1. JAXP (Java API for XML Processing)

JAXP 是Java XML程序设计的应用程序接口之一,它提供解析和验证XML文档的能力。JAXP是在Java社区进程下开发的,包括JSR 5 和 JSR 63 两个规范。

https://docs.oracle.com/javase/tutorial/jaxp/index.html

https://docs.oracle.com/javase/8/docs/technotes/guides/xml/jaxp/index.html

P28_线程上下文类加载器本质剖析与实做(28)

Tomcat Servlet ClassLoader 不是双亲委托模型

Spring WebAppClassLoader 学习点

在这里插入图片描述

P29_ServiceLoader在SPI中的重要作用分析(29)

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.48</version>
</dependency>
package new_package.jvm.p29;

import java.sql.*;
import java.util.Iterator;
import java.util.ServiceLoader;

public class ServiceLoaderTest {

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        ServiceLoader<Driver> serviceLoader = ServiceLoader.load(Driver.class);
        Iterator<Driver> iterator = serviceLoader.iterator();
        while (iterator.hasNext()) {
            Driver driver = iterator.next();
            System.out.println(driver.getClass());
            System.out.println(driver.getClass().getClassLoader());
            System.out.println("---");
        }

        System.out.println();
        System.out.println(Thread.currentThread().getContextClassLoader());
        System.out.println(ServiceLoader.class.getClassLoader());
    }
}

class com.mysql.jdbc.Driver
sun.misc.Launcher$AppClassLoader@18b4aac2
---
class com.mysql.fabric.jdbc.FabricMySQLDriver
sun.misc.Launcher$AppClassLoader@18b4aac2
---

sun.misc.Launcher$AppClassLoader@18b4aac2
null

java.util.ServiceLoader

A service provider is identified by placing a provider-configuration file in the resource directory META-INF/services. The file’s name is the fully-qualified binary name of the service’s type. The file contains a list of fully-qualified binary names of concrete provider classes, one per line. Space and tab characters surrounding each name, as well as blank lines, are ignored. The comment character is ‘#’ (’\u0023’, NUMBER SIGN); on each line all characters following the first comment character are ignored. The file must be encoded in UTF-8.
在这里插入图片描述

    private static final String PREFIX = "META-INF/services/";

    // Cached providers, in instantiation order
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

    public static <S> ServiceLoader<S> load(Class<S> service) {
        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 ServiceLoader(Class<S> svc, ClassLoader cl) {
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
        reload();
    }

    public void reload() {
        providers.clear();
        lookupIterator = new LazyIterator(service, loader);
    }

    // Private inner class implementing fully-lazy provider lookup
    //
    private class LazyIterator
        implements Iterator<S>
    {
    	// ...
    }
    private class LazyIterator
        implements Iterator<S>
    {

        Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
        Iterator<String> pending = null;
        String nextName = null;

        private LazyIterator(Class<S> service, ClassLoader loader) {
            this.service = service;
            this.loader = loader;
        }

        private boolean hasNextService() {
            if (nextName != null) {
                return true;
            }
            if (configs == null) {
                try {
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    fail(service, "Error locating configuration files", x);
                }
            }
            while ((pending == null) || !pending.hasNext()) {
                if (!configs.hasMoreElements()) {
                    return false;
                }
                pending = parse(service, configs.nextElement());
            }
            nextName = pending.next();
            return true;
        }

        private S nextService() {
            if (!hasNextService())
                throw new NoSuchElementException();
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
                fail(service,
                     "Provider " + cn + " not found");
            }
            if (!service.isAssignableFrom(c)) {
                fail(service,
                     "Provider " + cn  + " not a subtype");
            }
            try {
                S p = service.cast(c.newInstance());
                providers.put(cn, p);
                return p;
            } catch (Throwable x) {
                fail(service,
                     "Provider " + cn + " could not be instantiated",
                     x);
            }
            throw new Error();          // This cannot happen
        }

        public boolean hasNext() {
            if (acc == null) {
                return hasNextService();
            } else {
                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
                    public Boolean run() { return hasNextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

        public S next() {
            if (acc == null) {
                return nextService();
            } else {
                PrivilegedAction<S> action = new PrivilegedAction<S>() {
                    public S run() { return nextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }

    }

P30_线程上下文类加载器实战分析与难点剖析(30)

java.sql.DriverManager

    private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
        boolean result = false;
        if(driver != null) {
            Class<?> aClass = null;
            try {
                aClass =  Class.forName(driver.getClass().getName(), true, classLoader);
            } catch (Exception ex) {
                result = false;
            }
             // 防止命名空间不一致的问题
             result = ( aClass == driver.getClass() ) ? true : false;
        }

        return result;
    }

SPI 实现的 Java 类一般是由系统类加载器来加载的。引导类加载器是无法找到 SPI 的实现类的,因为它只加载 Java 的核心库。它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。也就是说,类加载器的代理模式无法解决这个问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值