【死磕springboot-第一篇】创建SpringApplication对象

本文详细剖析了SpringApplication的构造过程,从main方法开始,通过SpringApplication.run()逐步解析如何创建SpringApplication对象。在构造过程中,设置了资源加载器、主配置源、程序类型(NONE,SERVLET,REACTIVE)、初始化器和监听器。通过ClassUtils工具类判断程序类型,从spring.factories加载初始化器和监听器实例。整个过程涉及类加载、资源定位和工厂模式的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【死磕-第一篇】创建SpringApplication对象


导读

  • 每次每次!!!!,面试就看spring的源码,各种视频笔记到处看一点,没有系统的从头到尾学习
  • 这次!!,我一定要从main开始到结束,全部看完

1. 项目环境

版本

  • spring-boot 2.3.0.RELEASE

项目pom

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.0.RELEASE</version>
        </dependency>
  • 整个项目只引入了这一个依赖,从最常用的这个依赖来看springweb应用是如何启动的

项目代码

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}
  • 整个项目只有这样一个启动类,其余别的代码都没有,之后要是有测试的话,会加入一些代码来证明

2. 文章重点

  • 此篇文章主要讲述了main函数启动,调用 SpringApplication.run(MainApplication.class, args);
  • 这个函数中创建了一个SpringApplication对象,主要讲创建这个对象的构造函数干了什么

3. 源码解析(流程)

// 当前所在类:MainApplication.java (自己创建的)

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
    		// 调用SpringApplication 的静态 run方法
      	// 传入当前所在类,以及main方法中的args
        SpringApplication.run(MainApplication.class, args);
    }
}
  • 跳转到 run静态函数内部
	// 当前所在类:SpringApplication.java

	/**
	 * Static helper that can be used to run a {@link SpringApplication} from the
	 * specified source using default settings.
	 * 翻译:此静态方法可用于使用默认设置从指定源运行 SpringApplication
	 * @param primarySource the primary source to load
	 * 翻译:参数primarySource 主配置源
	 * @param args the application arguments (usually passed from a Java main method)
	 * 翻译:args 应用程序参数(通常从Java main方法中传递)
	 * @return the running {@link ApplicationContext}
	 * 翻译:返回运行中的 ApplicationContext
	 */
  public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class<?>[] { primarySource }, args);
  }
  • 跳转到run(new Class<?>[] { primarySource }, args) 内部
 	// 当前所在类:SpringApplication.java
	
	/**
	 * Static helper that can be used to run a {@link SpringApplication} from the
	 * specified sources using default settings and user supplied arguments.
	 * @param primarySources the primary sources to load
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return the running {@link ApplicationContext}
	 */
	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}
  • 此方法和上一个方法类似,这是这个方法可以传入多个primarySources
  • 跳转到new SpringApplication(primarySources) 内部(不是 run(args) 内部)
 	// 当前所在类:SpringApplication.java

	/**
	 * Create a new {@link SpringApplication} instance. The application context will load
	 * beans from the specified primary sources (see {@link SpringApplication class-level}
	 * documentation for details. The instance can be customized before calling
	 * {@link #run(String...)}.
	 * 
	 * 翻译:创建一个SpringApplication的实例,这个程序的context将会加载beans 从具体的主配置源
	 * 这个实例可以定制化在调用之前
	 * 
	 * @param primarySources the primary bean sources
	 * 
	 * 翻译:primarySources是 主要bean的来源
	 *
     * @see #run(Class, String[])
	 * @see #SpringApplication(ResourceLoader, Class...)
	 * @see #setSources(Set)
	 */
	public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}
  • 跳转到 this(null, primarySources); 的内部
  // 当前所在类:SpringApplication.java

	/**
	 * Create a new {@link SpringApplication} instance. The application context will load
	 * beans from the specified primary sources (see {@link SpringApplication class-level}
	 * documentation for details. The instance can be customized before calling
	 * {@link #run(String...)}.
     * 
     * 翻译:创建一个SpringApplication的实例,这个程序的context将会加载beans 从具体的主配置源
	 * 这个实例可以定制化在调用run(String...)之前
	 * 
	 * @param resourceLoader the resource loader to use
	 * 
	 * 翻译:resourceLoader 要使用的资源加载器
	 * 
	 * @param primarySources the primary bean sources
	 * 
	 * 翻译:primarySources 主配置源
	 * 
	 * @see #run(Class, String[])
	 * @see #setSources(Set)
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 设置资源加载器
		this.resourceLoader = resourceLoader;
    // 断言判断:primarySources不能为null
		Assert.notNull(primarySources, "PrimarySources must not be null");
    // 设置主配置源
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 设置此程序是什么类型的(NONE,SERVLET,REACTIVE)
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 设置初始化器
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 设置监听器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 设置主程序所在的class
		this.mainApplicationClass = deduceMainApplicationClass();
	}

4. 源码详细解析

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 设置资源加载器
		this.resourceLoader = resourceLoader;
    // 断言判断:primarySources不能为null
		Assert.notNull(primarySources, "PrimarySources must not be null");
    // 设置主配置源
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 4.1 设置此程序是什么类型的(NONE,SERVLET,REACTIVE)
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 4.2 设置初始化器
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 4.3 设置监听器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 4.4 设置主程序所在的class
		this.mainApplicationClass = deduceMainApplicationClass();
	}

4.1 设置程序的类型

    // 4.1 设置此程序是什么类型的(NONE,SERVLET,REACTIVE)
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
  • 跳转到deduceFromClasspath() 内部
  // WEBFLUX_INDICATOR_CLASS org.springframework.web.reactive.DispatcherHandler
  // WEBMVC_INDICATOR_CLASS org.springframework.web.servlet.DispatcherServlet
  // JERSEY_INDICATOR_CLASS org.glassfish.jersey.servlet.ServletContainer
  // SERVLET_INDICATOR_CLASSES 
	// 	javax.servlet.Servlet
	//  org.springframework.web.context.ConfigurableWebApplicationContext

	// deduceFromClasspath()
	// 翻译:从Classpath推断此程序是什么类型的
	static WebApplicationType deduceFromClasspath() {
    // 如果
    // 存在 DispatcherHandler
    // && 不存在 DispatcherServlet
    // && 不存在 ServletContainer
    // 则 程序是 REACTIVE 类型
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) 
        && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
    // 如果
    // 不存在 Servlet
    // || 不存在 ConfigurableWebApplicationContext
    // 则 程序是 NONE 类型
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
    // 以上都不成立 则 程序是 SERVLET 类型
		return WebApplicationType.SERVLET;
	}
  • 跳转到ClassUtils.isPresent内部
	// isPresent(String className, @Nullable ClassLoader classLoader)
	// 翻译:根据传入的类名,在传入的类加载器中查找是否存在此类
	public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
		try {
      // 根据类名在类加载器中查找
			forName(className, classLoader);
			return true;
		}
		catch (IllegalAccessError err) {
			throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
					className + "]: " + err.getMessage(), err);
		}
		catch (Throwable ex) {
			// Typically ClassNotFoundException or NoClassDefFoundError...
      /**
      * ClassNotFoundException 和 NoClassDefFoundError 的区别
      * 详细解释:https://www.huaweicloud.com/articles/11967786.html
      */
			return false;
		}
	}
  • 跳转到forName(className, classLoader) 内部
	/**
	 * Replacement for {@code Class.forName()} that also returns Class instances
	 * for primitives (e.g. "int") and array class names (e.g. "String[]").
	 * Furthermore, it is also capable of resolving inner class names in Java source
	 * style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State").
	 * 
	 * 翻译:此方法对标于Class.forName(),同样也返回class的实例
	 * 对于int,String[] 这种也可以返回
	 * 对于内部类 可以 用java.lang.Thread.State 来替换 java.lang.Thread$State用于查找
	 * 
	 * @param name the name of the Class
	 * @param classLoader the class loader to use
	 * (may be {@code null}, which indicates the default class loader)
	 * @return a class instance for the supplied name
	 * @throws ClassNotFoundException if the class was not found
	 * @throws LinkageError if the class file could not be loaded
	 * @see Class#forName(String, boolean, ClassLoader)
	 */
	public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
			throws ClassNotFoundException, LinkageError {
		// 断言: name不能为空
		Assert.notNull(name, "Name must not be null");

    // 解决基本类型的获取,例如int,float,double,以及int[],float[],等等
		Class<?> clazz = resolvePrimitiveClassName(name);
		if (clazz == null) {
      // 解决Integer,Double,以及异常,Byte, java.lang, Iterator等等常用的类型以及接口
			clazz = commonClassCache.get(name);
		}
		if (clazz != null) {
			return clazz;
		}

		// "java.lang.String[]" style arrays
		// 以[] 结尾的
		if (name.endsWith(ARRAY_SUFFIX)) {
      // 移除名字中的[], java.lang.String[] -》 java.lang.String
			String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
			// 获取 java.lang.String 在类加载器中,因为没有java.lang.String[]类型, 如果是[][]则会再次调用
      Class<?> elementClass = forName(elementClassName, classLoader);
      // 返回的名字竟然是调用Array的静态实例化方法然后获取这个实例的class获得,虽然传入的是0,但是也太奇怪了
			return Array.newInstance(elementClass, 0).getClass();
		}

		// "[Ljava.lang.String;" style arrays
		if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
			String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
			Class<?> elementClass = forName(elementName, classLoader);
			return Array.newInstance(elementClass, 0).getClass();
		}
        
		 // "[[I" or "[[Ljava.lang.String;" style arrays
          // [[L代表 String[][], Integer[][]
         // [[I代表 int[][]
         // [[F代表 float[][]
		if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
			String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
			Class<?> elementClass = forName(elementName, classLoader);
			return Array.newInstance(elementClass, 0).getClass();
		}

		ClassLoader clToUse = classLoader;
		if (clToUse == null) {
      // 获取默认的类加载器
			clToUse = getDefaultClassLoader();
		}
		try {
      // 根据名称从指定类加载器中获取
			return Class.forName(name, false, clToUse);
		}
		catch (ClassNotFoundException ex) {
      // 特别的去处理xxx.xxxx.xxxx 这种类,但实际在类加载器中存在的是 xxx.xxxx$xxxx 这种类形式的存在
      // 获取最后一个点的位置
			int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
			if (lastDotIndex != -1) {
        // 如果找的到的话,就将最后一个点换成$
				String innerClassName =
						name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
				try {
          // 重新获取
					return Class.forName(innerClassName, false, clToUse);
				}
				catch (ClassNotFoundException ex2) {
					// Swallow - let original exception get through
				}
			}
			throw ex;
		}
	}
  • 跳转到 getDefaultClassLoader
/**
	 * Return the default ClassLoader to use: typically the thread context
	 * ClassLoader, if available; the ClassLoader that loaded the ClassUtils
	 * class will be used as fallback.
	 * 
	 * 翻译:返回一个默认的类加载器去使用:通常是此线程的类加载器,如果有的话;加载ClassUtils类的类加载器将会作为后备
	 * 
	 * <p>Call this method if you intend to use the thread context ClassLoader
	 * in a scenario where you clearly prefer a non-null ClassLoader reference:
	 * for example, for class path resource loading (but not necessarily for
	 * {@code Class.forName}, which accepts a {@code null} ClassLoader
	 * reference as well).
	 * 
	 * 翻译:如果你打算在一个场景中使用线程上下文的ClassLoader,你显然更喜欢一个非空的ClassLoader引用,请调用此方法
	 * :例如,对于类的路径资源加载,(但不一定用于 Class.forName, 这也接受一个null的ClassLoader)
	 * 
	 * @return the default ClassLoader (only {@code null} if even the system
	 * ClassLoader isn't accessible)
	 * @see Thread#getContextClassLoader()
	 * @see ClassLoader#getSystemClassLoader()
	 */
	@Nullable
	public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
      // 返回此线程的类加载器
			cl = Thread.currentThread().getContextClassLoader();
		}
		catch (Throwable ex) {
			// Cannot access thread context ClassLoader - falling back...
		}
    // 如果是null
		if (cl == null) {
			// No thread context class loader -> use class loader of this class.
			// 获取 ClassUtils类 加载的类加载器
      cl = ClassUtils.class.getClassLoader();
			if (cl == null) {
				// getClassLoader() returning null indicates the bootstrap ClassLoader
				try {
          // 获取系统的类加载器
					cl = ClassLoader.getSystemClassLoader();
				}
				catch (Throwable ex) {
					// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
				}
			}
		}
		return cl;
	}
  • 跳转返回 deduceFromClasspath() 内部
deduceFromClasspath()
  可以理解为就是从各种类加载中获取指定的类,如果有或者没有此类来判断是什么类型的应用

4.2 设置初始化器

    // 4.2 设置初始化器
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  • 跳转到getSpringFactoriesInstances(ApplicationContextInitializer.class) 内部
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
         // 可以根据类型以及参数类型来获取指定的类实例
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}
  • 跳转到getSpringFactoriesInstances(type, new Class<?>[] {});内部

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		// 获取加载器,底层逻辑是先获取resourceLoader的类加载器,没有的话然后用ClassUtils.getDefaultClassLoader();获取默认的类加载器
         ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
         // 根据类型获取spring.factories中符合的类名
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		// 根据以上获取的类名创建类的实例
         List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		// 将实例进行排序
         AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
  • 跳转到SpringFactoriesLoader.loadFactoryNames(type, classLoader)内部
	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		// 获取传入的class的name
         String factoryTypeName = factoryType.getName();
         // 从spring.factories中获取指定的类型,如果没有的话,返回一个空List
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}
  • 跳转到 loadSpringFactories(classLoader)内部
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    	// 从缓存中获取类加载器
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
             // 缓存中没有类加载器的话
             // FACTORIES_RESOURCE_LOCATION META-INF/spring.factories
			// 使用指定类加载器获取所有包中的META-INF/spring.factories
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
                  // 从指定位置加载 Properties
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                  // 遍历 Properties 中的键值对
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
              // 将spring.factories中的键值对结果以类加载器为key存入缓存中,以便下次调用直接从缓存中读取
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

  • 返回 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  • 跳转到 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);内部
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
                  // 从类加载器中获取指定的类
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				// instanceClass 是不是 type的子类
                 Assert.isAssignable(type, instanceClass);
                  // 根据参数获取此类的构造器
				Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                  // 根据传入的构造器对象以及构造器所需的参数创建一个实例
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				// 将创建好的实例添加到集合中
                  instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}
  • 最后将返回结果给 setListeners()

  • 跳转到 setInitializers内部

/**
* Sets the {@link ApplicationContextInitializer} that will be applied to the Spring
* {@link ApplicationContext}.
*
* 翻译:设置多个ApplicationContextInitializer,这会施加到spring ApplicationContext 中
* 
* @param initializers the initializers to set
*/
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
	this.initializers = new ArrayList<>(initializers);
}
  • 接着就setListeners
  • 其流程和setInitializers类似,不同的地方在于,他们从spring.factories中获取的key不同,setListerners获取的是
  • ApplicationListener
  • 最后也将获取到的类实例化,然后设置到springApplication中
/**
* Sets the {@link ApplicationListener}s that will be applied to the SpringApplication
* and registered with the {@link ApplicationContext}.
* 
* 翻译: 设置 多个ApplicationListener, 这将会施加到SpringApplication 和 注册到ApplicationContext中
* 
* @param listeners the listeners to set
*/
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
    this.listeners = new ArrayList<>(listeners);
}
  • 最后来到了构造器的最后一步
// 设置主程序类
this.mainApplicationClass = deduceMainApplicationClass();
  • 跳转到 deduceMainApplicationClass内部

private Class<?> deduceMainApplicationClass() {
    try {
        // 创建一个运行异常获取他的方法调用栈的信息
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        // 循环遍历栈,判断哪个栈的方法名是main,返回此方法的class
        for (StackTraceElement stackTraceElement : stackTrace) {
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}

5. 总结

重点介绍了哪些方法

  • SpringApplication(ResourceLoader resourceLoader, Class<?>… primarySources)
    • springApplication构造器
  • ClassUtils.isPresent
    • ClassUtils工具类方法,isPresent 用于判断是否存在此类
  • SpringFactoriesLoader.loadFactoryNames
    • 用于获取spring.factories中的值
  • ClassUtils.getDefaultClassLoader
    • 用于加载默认的ClassLoader

6.补充

ClassLoader.getSystemClassLoader() 是怎么运行的

/**
     * Returns the system class loader for delegation.  This is the default
     * delegation parent for new <tt>ClassLoader</tt> instances, and is
     * typically the class loader used to start the application.
     *
     * 翻译:  此方法返回系统类加载器,这个加载器是使用 ClassLoader 创建的加载器的默认父加载器,它通常被用来启动应用程序。
     * 简单的说就是继承ClassLoader的加载器,默认的构造器函数(没有传入父加载器)是调用此函数作为父加载器的
     * 
     * <p> This method is first invoked early in the runtime's startup
     * sequence, at which point it creates the system class loader and sets it
     * as the context class loader of the invoking <tt>Thread</tt>.
     *
     * 翻译:在程序早期运行的时候,此方法将会被第一次执行。当此方法被执行的时候,程序会创建系统类加载器并将其设置其调用该方法
     * 父类加载器
     * <p> The default system class loader is an implementation-dependent
     * instance of this class.
     * 翻译:这个系统类加载器是依赖于实现的一个类的实例,(即AppClassloader是抽象类ClassLoader类的一个实现,系统类加载器是这个
     * 实现类的一个实例)。
     *
     * <p> If the system property "<tt>java.system.class.loader</tt>" is defined
     * when this method is first invoked then the value of that property is
     * taken to be the name of a class that will be returned as the system
     * class loader.  The class is loaded using the default system class loader
     * and must define a public constructor that takes a single parameter of
     * type <tt>ClassLoader</tt> which is used as the delegation parent.  An
     * instance is then created using this constructor with the default system
     * class loader as the parameter.  The resulting class loader is defined
     * to be the system class loader.
     * 翻译:如果系统的环境变量 java.system.class.loader 在此方法第一次执行之前被设置的话,这个属性的值代表的ClassLoader将会
     * 被作为指定的系统类加载器,这个被指定的系统类加载器要求提供一个公有的接收一个ClassLoader参数的构造方法,这个CLassLoader会
     * 被作为此类的父类加载器。这个类的加载器实例会被默认的系统类加载器创建,返回的系统类加载器就是系统类加载。
     *
     * <p> If a security manager is present, and the invoker's class loader is
     * not <tt>null</tt> and the invoker's class loader is not the same as or
     * an ancestor of the system class loader, then this method invokes the
     * security manager's {@link
     * SecurityManager#checkPermission(java.security.Permission)
     * <tt>checkPermission</tt>} method with a {@link
     * RuntimePermission#RuntimePermission(String)
     * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify
     * access to the system class loader.  If not, a
     * <tt>SecurityException</tt> will be thrown.  </p>
     *
     * @return  The system <tt>ClassLoader</tt> for delegation, or
     *          <tt>null</tt> if none
     *
     * @throws  SecurityException
     *          If a security manager exists and its <tt>checkPermission</tt>
     *          method doesn't allow access to the system class loader.
     *
     * @throws  IllegalStateException
     *          If invoked recursively during the construction of the class
     *          loader specified by the "<tt>java.system.class.loader</tt>"
     *          property.
     *
     * @throws  Error
     *          If the system property "<tt>java.system.class.loader</tt>"
     *          is defined but the named class could not be loaded, the
     *          provider class does not define the required constructor, or an
     *          exception is thrown by that constructor when it is invoked. The
     *          underlying cause of the error can be retrieved via the
     *          {@link Throwable#getCause()} method.
     *
     * @revised  1.4
     */

    @CallerSensitive
    public static ClassLoader getSystemClassLoader() {
        // 初始化系统类加载器
        initSystemClassLoader();
        if (scl == null) {
            return null;
        }
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkClassLoaderPermission(scl, Reflection.getCallerClass());
        }
        return scl;
    }
  • 进入initSystemClassLoader()内部

private static synchronized void initSystemClassLoader() {
    	// sclSet:标识系统类加载器是否被加载
        if (!sclSet) {
            if (scl != null)
                throw new IllegalStateException("recursive invocation");
            // 获取launcher的实例
            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
            if (l != null) {
                Throwable oops = null;
                // 获取launcher的实例中 类加载器
                scl = l.getClassLoader();
                try {
                    scl = AccessController.doPrivileged(
                        new SystemClassLoaderAction(scl));
                } catch (PrivilegedActionException pae) {
                    oops = pae.getCause();
                    if (oops instanceof InvocationTargetException) {
                        oops = oops.getCause();
                    }
                }
                if (oops != null) {
                    if (oops instanceof Error) {
                        throw (Error) oops;
                    } else {
                        // wrap the exception
                        throw new Error(oops);
                    }
                }
            }
            sclSet = true;
        }
    }
  • 进入Launcher.java内部
public class Launcher {
    
    private static Launcher launcher = new Launcher();
	
    ...

    public Launcher() {
        Launcher.ExtClassLoader var1;
        try {
            // 创建一个 ExtClassLoader
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }

        try {
            // 创建一个 AppClassLoader类加载器 将 ExtClassLoader作为它的parent
            // 并且将this.loader 的值赋为 AppClassLoader,这个也就是initSystemClassLoader 获得的值
            this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
        } catch (IOException var9) {
            throw new InternalError("Could not create application class loader", var9);
        }
	    // 设置当前线程的类加载器为AppClassLoader
        Thread.currentThread().setContextClassLoader(this.loader);
        String var2 = System.getProperty("java.security.manager");
        if (var2 != null) {
            SecurityManager var3 = null;
            if (!"".equals(var2) && !"default".equals(var2)) {
                try {
                    var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
                } catch (IllegalAccessException var5) {
                } catch (InstantiationException var6) {
                } catch (ClassNotFoundException var7) {
                } catch (ClassCastException var8) {
                }
            } else {
                var3 = new SecurityManager();
            }

            if (var3 == null) {
                throw new InternalError("Could not create SecurityManager: " + var2);
            }

            System.setSecurityManager(var3);
        }

    }
}

我们尝试给initSystemClassLoader函数打断点,发现它一直是有值的用于进不去,什么使用初始化过了呢?

  • 下载openjdk的源码,发现一个叫SystemDictionary.cpp的文件有一个这样的方法,此方法会在Threads::create_vm中调用
void SystemDictionary::compute_java_system_loader(TRAPS) {
  KlassHandle system_klass(THREAD, WK_KLASS(ClassLoader_klass));
  JavaValue result(T_OBJECT);
  // 调用java的getSystemClassLoader()函数
  JavaCalls::call_static(&result,
                         KlassHandle(THREAD, WK_KLASS(ClassLoader_klass)),
                         vmSymbols::getSystemClassLoader_name(),
                         vmSymbols::void_classloader_signature(),
                         CHECK);

  _java_system_loader = (oop)result.get_jobject();

  CDS_ONLY(SystemDictionaryShared::initialize(CHECK);)
}
  • 还有就是为什么第一次的断点进不去,那是因为第一次调用属于还没到java层面,debug包都没加载,怎么打断点
  • 此部分自己也不是很熟悉,所以没有写很多
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值