ClassLoader JAVA learning

ClassLoader JAVA learning

Foreword

Was recently touched by a word - to plant a tree is the best time ten years ago, followed by now. So we decided to start recording his own way of learning.

What is the class loader?

We all know that each .java files can be compiled into .class through javac command file, which contains the machine instructions java virtual machine. When we need to use a java class, the virtual load its .class file, creates a corresponding java object. .Class transferred to the virtual machine process, called load.

loading: loading. Find .class bytecode files by fully qualified name of the class, while creating an object.

verification: verification. Ensure that the class bytecode files meet the requirements of the current virtual machine.

preparation: Preparation. This time will be modified static memory allocation of variables, and set the initial value.

resolution: resolution. The virtual machine will become symbolic constant pool references direct reference.

  • Symbolic references: After the completion of the compilation, and not a constant memory allocation, it can only reference symbol.
  • Direct Quote: the preparation phase will be constant constant memory allocation, so they can establish a direct link virtual machine memory, you can directly reference.

initialization: Initialization. Classloading final stage. If the class has a superclass, super class initialization, class static block of code, while imparting to the static class variable initial value. In front of the preparation phase is to allocate memory, just the default value, it has not been given the initial value.

There are two ways to load class in java

  • Display loaded. . GetClassLoader.loadClass (classname) by loading class.fornNme (classname) or this.getClass (). That is to finish loading the class by calling the class loader classLoader
  • Implicit loading. Class to be used when needed, it does not call ClassLoader, but the virtual machine automatically call ClassLoader loaded into memory.

What is the ClassLoader?

Class loader has the task class binary stream of bytes read into the JVM, then becomes the object class can identify a JVM, while instantiated. So we can break down ClassLoader task.

  1. Found binary byte stream class and loads come
  2. Rules into JVM class objects can be identified

We view the source code, find the corresponding solutions:

In the ClassLoader, we define two interfaces:

  1. findClass(String name).
  2. defineClass(byte[] b , int off , int len)

findClass used to find and read a binary file, call defineClass flow into JVM class object can be identified by the byte, while examples of class objects.

Let's look at an example:

protected Class<?> findClass(String name) throws ClassNotFoundException {
	  // 获取类的字节数组,通过name找到类,如果你对字节码加密,需要自己解密出来
      byte[] classData = getClassData(name);  
      if (classData == null) {
          throw new ClassNotFoundException();
      } else {
	      //使用defineClass生成class对象
          return defineClass(name, classData, 0, classData.length);
      }
  }

Proxy mode

Mentioned class loader, must involve the delegation model. In JAVA, ClassLoader exist at several categories, their relationship is as follows:

  • Bootstrap ClassLoader: bootstrap class loader. In native c ++ realize, a java class loading of the core ( %JAVA_HOME%/libthe core class libraries, or in the path -Xbootclasspathspecified in the jar package) into memory. No parent .

  • Extension ClassLoader: extension class loader. java implementation, loading /lib/extthe directory or path bit is designated by the library system variable -Djava.ext.dir. Parent class loader to null.

  • System ClassLoader: it will be based on the classpath java application (CLASSPATH) to load categories, namely java -classpath, or -D java.class.pathspecify the library path under, that is, we often use the classpath. In general, the class java application is done by it. It can be obtained from ClassLoader.getSystemLoader () method. The parent class loader is the Extension ClassLoader.

  • Customize ClassLoader: custom loader. For the completion of the user's own unique needs. Parent class loader for the System ClassLoader.

    1. Loads CLASSPATH is not in the path of the class file
    2. class encrypted files require the user to customize the ClassLoader to be decrypted in order to identify the JVM.
    3. Hot deployment, with a different class class object file generated by different class loaders. Two classes are identical, if not the same class file, you also need the same class loader, with a JVM.

    The agency model , like the above picture is shown above, when you want to load a class loader will seek help its parent, so the parent class attempts to load the class. Only when the parent fails, it will load by themselves. The reflected ClassLoader loadClass () method.

    Sample code:

    protected Class<?> loadClass(String name, boolean resolve)
          throws ClassNotFoundException
      {
          synchronized (getClassLoadingLock(name)) {
              Class<?> c = findLoadedClass(name);
              if (c == null) {
                  long t0 = System.nanoTime();
                  try {
                      if (parent != null) {
                          //如果找不到,则委托给父类加载器去加载
                          c = parent.loadClass(name, false);
                      } else {
                      //如果没有父类,则委托给启动加载器去加载
                          c = findBootstrapClassOrNull(name);
                      }
                  } catch (ClassNotFoundException e) {
                      // ClassNotFoundException thrown if class not found
                      // from the non-null parent class loader
                  }
    
                  if (c == null) {
                      // If still not found, then invoke findClass in order
                      // 如果都没有找到,则通过自定义实现的findClass去查找并加载
                      c = findClass(name);
    
                  }
              }
              if (resolve) {//是否需要在加载时进行解析
                  resolveClass(c);
              }
              return c;
          }
      }
    
    

    findClass (String name) is implemented with a similar example, resolveClass above () is the completion of parsing function.

    URLClassLoader

    URLClassLoader is a common ClassLoader class that implements findclass () interface, so if inherited URLClassLoader custom can not rewrite findclass (). Extension ClassLoader ExtClassLoader belongs in the proxy mode, and AppClassLoader belongs System ClassLoader.

    Thread context loader

    As mentioned earlier BootStrap ClassLoader loaded is the core library files under% JAVA_HOME% / lib, but libraries in the CLASSPATH path is loaded by the System ClassLoader. But in java language, the existence of this phenomenon, Java provides many service provider interface (Service Provider Interface, SPI), allow third parties to provide implementations for these interfaces, such as JDBC, JCE, JNDI and so on. The SPI is the Java core libraries, loaded by BootStrap ClassLoader, third-party implementations is on the CLASSPATH path, loaded by the System ClassLoader. When BootStrap ClassLoader enabled, its implementation needs to be loaded, but they could not find, and because the agency model exists, can not be entrusted System ClassLoader to load, it can not be achieved.

    Contex ClassLoader (thread context loader) just to solve this problem.

    Contex ClassLoader (thread context loader) are introduced from the beginning JDK 1.2. Class java.lang.Threadmethod getContextClassLoader()and setContextClassLoader(ClassLoader cl)is used to get and set thread's context class loader. If no By setContextClassLoader(ClassLoader cl)setting method, then the thread will inherit the parent thread context class loader's. The initial thread running Java application context class loader is the system class loader. Code running in the thread can load classes and resources through this class loader.

    Examples of JDBC:

    public class DriverManager {
    	//省略......
        static {
            loadInitialDrivers();
            println("JDBC DriverManager initialized");
        }
    
     private static void loadInitialDrivers() {
         sun.misc.Providers()
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                  //省略不必要的代码......
                }
            });
        }
    public class Driver extends com.mysql.cj.jdbc.Driver {
        public Driver() throws SQLException {
            super();
        }
    
        static {
          //省略
        }
    }
    public static <S> ServiceLoader<S> load(Class<S> service) {
    	 //通过线程上下文类加载器加载
          ClassLoader cl = Thread.currentThread().getContextClassLoader();
          return ServiceLoader.load(service, cl);
      }
    //调用
    String url = "jdbc:mysql://localhost:3342/cm-storylocker?characterEncoding=UTF-8";
    // 通过java库获取数据库连接
    Connection conn = java.sql.DriverManager.getConnection(url, "root", "password");
    
    
    

    We can see that when we use JDBC, it will have to use the DriverManager class, ServiceLoader class of its static code area will be finished loading JDBC reference implementation class.

    How to design your own ClassLoader

    Examples are given, rewrites the file system loader

    public class FileSystemClassLoader extends ClassLoader { 
     
       private String rootDir; 
     
       public FileSystemClassLoader(String rootDir) { 
           this.rootDir = rootDir; 
       } 
     
       protected Class<?> findClass(String name) throws ClassNotFoundException { 
           //根据规则获取字节流数组
           byte[] classData = getClassData(name); 
           if (classData == null) { 
               throw new ClassNotFoundException(); 
           } 
           else { 
               return defineClass(name, classData, 0, classData.length); 
           } 
       } 
     //设定自己的读取规则
       private byte[] getClassData(String className) { 
           String path = classNameToPath(className); 
           try { 
               InputStream ins = new FileInputStream(path); 
               ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
               int bufferSize = 4096; 
               byte[] buffer = new byte[bufferSize]; 
               int bytesNumRead = 0; 
               while ((bytesNumRead = ins.read(buffer)) != -1) { 
                   baos.write(buffer, 0, bytesNumRead); 
               } 
               return baos.toByteArray(); 
           } catch (IOException e) { 
               e.printStackTrace(); 
           } 
           return null; 
       } 
     
       private String classNameToPath(String className) { 
           return rootDir + File.separatorChar 
                   + className.replace('.', File.separatorChar) + ".class"; 
       } 
    }
    

    Reference herein to learn from

    [1] https://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html#minor1.1

    [2] https://blog.csdn.net/javazejian/article/details/73413292

    [3] https://juejin.im/post/5e1aaf626fb9a0301d11ac8e#heading-8

Guess you like

Origin www.cnblogs.com/waaaafool/p/12578914.html