springboot 启动过程五

用于源码分析的代码:Github
接着上一篇继续debug,这次看run方法里的源码,每次看的源码不贪多,慢慢嚼。上一篇已经将源码3.0的逻辑分析完了,这一篇就源码4.0处继续:

public ConfigurableApplicationContext run(String... args) {
    //StopWatch就是一个监控程序启动时间的类,start方法表示开始计时,stop方法表示计时结束
    //用于日志输出启动时间
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		// 设置一个环境变量,该环节变量标识当前程序是在没有显示器、鼠标等显示设备上运行的
		// 目的是为了能直接访问支持在无显示设备下的图形和文字处理对象的API,比如AWT的绘图API
		configureHeadlessProperty();
		// 1.0
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// 2.0
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 3.0
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			// 4.0
			configureIgnoreBeanInfo(environment);
			// 4.1
			Banner printedBanner = printBanner(environment);
			// 4.2
			context = createApplicationContext();
			// 4.3
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}  

还是首先列出自己的问题,带着问题看源码

待解答的问题

  • 这段源码做了什么?
  • 为什么这么做?
  • 学到了哪些东西?

项目启动命令

使用远程debug的方式来启动,先将项目使用mvn package 命令打成jar包,然后cd到jar包所在目录,使用命令方式启动项目,我这里启动命令是:java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005 -Dlogging.level.root=info -jar spring-boot-learn-1.0-SNAPSHOT.jar --spring.profiles.active=profile --spring.main.lazy-initialization=false ,5005就是远程debug时的端口,然后通过idea来做远程debug,在启动过程一中有讲到远程debug的配置。

源码分析

4.0

此处是检查启动参数里的 spring.beaninfo.ignore是否有配置,如果没有配置,则设置为默认的true,没有深究这一步的具体含义,大概意思是在通知spring容器在调用Introspector#getBeanInfo(Class, int)方法时,以一个比较轻量的模式来调用,而getBeanInfo本身是个非常重的操作,有兴趣的可以去研究下getBeanInfo方法的源码,在实际应用中没有遇到这个配置,所以此处跳过

configureIgnoreBeanInfo(environment);

private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
		if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
			Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
			System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
		}
	}

4.1

	Banner printedBanner = printBanner(environment);

这个作用就是配置Springboot启动时的那个banner图,比如默认是:

![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rJrJYgC0-1604976239232)(quiver-image-url/B1040FB7D5CCA17F4C4856505EF14CAF.jpg =1042x170)]

banner生成器:https://www.bootschool.net/ascii
只需要将生成的内容放到classpath下的banner.txt里就行了,并且还支持gif、jpg、png格式的图片,banner的相关配置信息如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dBflEHGi-1604976239239)(quiver-image-url/F1C538858ACC4950AF11DB70CC1C8D87.jpg =1071x618)]]

4.2

这里就是怎么生成ConfigurableApplicationContext,这个类是大名鼎鼎BeanFactory的子类,但是这个类是Spring启动过程中的最顶层的上下文对象,这个对象里不仅存储了BeanFactory,还存储了Evironment、主配置、各种后置处理器、监听器等等,可以看下类图:
在这里插入图片描述

逻辑就是根据webApplicationType的类型来决定生成哪种context,而webApplicationType的赋值是在启动过程二里有讲解,先看源代码:

context = createApplicationContext();

	protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

由于webApplicationType是SERVLET,所以这里就加载org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext类,并通过BeanUtils.instantiateClass就是获取这个类的构造器,然后通过反射调用构造器生成实例。
这里重点看下这个类的构造器,构造器里会初始化几个非常重要的后置处理器:

/**
	 * Create a new {@link AnnotationConfigServletWebServerApplicationContext} that needs
	 * to be populated through {@link #register} calls and then manually
	 * {@linkplain #refresh refreshed}.
	 */
	public AnnotationConfigServletWebServerApplicationContext() {
	//
		this.reader = new AnnotatedBeanDefinitionReader(this);
		//负责扫描指定的包路径下需要有Spring容器管理的bean
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

这里先看AnnotatedBeanDefinitionReader类的构造器

/**
	 * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
	 * using the given {@link Environment}.
	 * @param registry the {@code BeanFactory} to load bean definitions into,
	 * in the form of a {@code BeanDefinitionRegistry}
	 * @param environment the {@code Environment} to use when evaluating bean definition
	 * profiles.
	 * @since 3.1
	 */
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		// 这个类是用来解析@Conditional注解的,用来判断该注解里的条件是否成立
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		// 这个会注释几个很重要的后置处理器
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

来查看后置处理器的注册逻辑:

/**
	 * Register all relevant annotation post processors in the given registry.
	 * @param registry the registry to operate on
	 * @param source the configuration source element (already extracted)
	 * that this registration was triggered from. May be {@code null}.
	 * @return a Set of BeanDefinitionHolders, containing all bean definitions
	 * that have actually been registered by this call
	 */
	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) {
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			// 添加用于排序的比较器,比如在执行beanFactory的后置处理器时,按照什么顺序执行?这里就会用这个来做排序
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			// 4.2.1源码
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
     // 4.2.2源码
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
    // 4.2.3源码
		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
   // 4.2.4源码
		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
    // 4.2.5源码
		// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition();
			try {
				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
						AnnotationConfigUtils.class.getClassLoader()));
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
			}
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
    // 4.2.6源码
		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}
    // 4.2.7源码
		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

		return beanDefs;
	}
4.2.1源码

这段代码是设置一个支持检查@Lazy、@Aotowire、@Qualifier、@Value这几个注解的类,这个类提供的功能包括检查是否存在这些注解及与这些注解相关的功能,其中有一个知识点需要了解下,就是spring怎么做到懒加载的,即:@Lazy注解是怎么做到懒加载的?下面研究下ContextAnnotationAutowireCandidateResolver类的getLazyResolutionProxyIfNecessary方法:

@Override
	@Nullable
	public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
		return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
	}

protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
		Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory,
				"BeanFactory needs to be a DefaultListableBeanFactory");
				// 第一步:获取beanFactory
		final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();
		// 第二步:生成一个包含了beanfactory的TargetSource对象,该对象的getTarget方法会通过beanFactory实例化这个对象,也就是在真正使用到这个对象时,才会调用这个getTarget方法来实例化
		TargetSource ts = new TargetSource() {
			@Override
			public Class<?> getTargetClass() {
				return descriptor.getDependencyType();
			}
			@Override
			public boolean isStatic() {
				return false;
			}
			@Override
			public Object getTarget() {
				Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);
				if (target == null) {
					Class<?> type = getTargetClass();
					if (Map.class == type) {
						return Collections.emptyMap();
					}
					else if (List.class == type) {
						return Collections.emptyList();
					}
					else if (Set.class == type || Collection.class == type) {
						return Collections.emptySet();
					}
					throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
							"Optional dependency not present for lazy injection point");
				}
				return target;
			}
			@Override
			public void releaseTarget(Object target) {
			}
		};
		// 第三步:将这个targetSource传给代理工厂,生成代理类
		ProxyFactory pf = new ProxyFactory();
		pf.setTargetSource(ts);
		Class<?> dependencyType = descriptor.getDependencyType();
		if (dependencyType.isInterface()) {
			pf.addInterface(dependencyType);
		}
		return pf.getProxy(beanFactory.getBeanClassLoader());
	}

spring是通过生成代理类来实现懒加载,具体就是生成一个TargetSource 在该对象的getTargert()方法里做实例化的事情,而在真正使用的时候才会去调用getTarget()方法,由于Spring的AOP有两种实现方式,一种是基于接口的JDK自带的实现方式,一种是基于继承的cglib的实现方式,所以这里找到具体调用getTarget()方法的代码:
一、先看基于接口的JdkDynamicAopProxy实现,基于接口的实现实际上是通过一个InvocationHandler的实例来调用真正的对象的,而JdkDynamicAopProxy类是继承自InvocationHandler,所以这里看下JdkDynamicAopProxy的invoke方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SNOPBcmC-1604976239243)(quiver-image-url/173C70D64CA4D6DE4C1AEBAA3DE48EE1.jpg =517x167)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5q71lGzr-1604976239244)(quiver-image-url/C84FA1672EB6AFAA61AEC950BB7F5711.jpg =1076x980)]

二、看基于继承的CglibAopProxy类,具体生成代理的代码在getProxy方法里,我这里就直接贴出生成的代理类的反编译代码看下,我这里定义了一个自己的类GenericTypeAutoWire,然后看下这个类被代理后的反编译文件:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kKnnPQK9-1604976239245)(quiver-image-url/0AC59E8EFAB71AA742972A8A9E7C67CA.jpg =669x442)]

下面是GenericTypeAutoWire的代理类被反编译后的代码,通过类的继承关系可以看出是基于继承来实现的:

public class GenericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d
extends GenericTypeAutoWire
implements SpringProxy,
Advised,
Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private MethodInterceptor CGLIB$CALLBACK_1;
    private NoOp CGLIB$CALLBACK_2;
    private NoOp CGLIB$CALLBACK_3;
    private Dispatcher CGLIB$CALLBACK_4;
    private MethodInterceptor CGLIB$CALLBACK_5;
    private MethodInterceptor CGLIB$CALLBACK_6;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$print$0$Method;
    private static final MethodProxy CGLIB$print$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;

    static void CGLIB$STATICHOOK5() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class<?> class_ = Class.forName("com.hj.learn.autowire.GenericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d");
        Class<?> class_2 = Class.forName("java.lang.Object");
        Method[] arrmethod = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, class_2.getDeclaredMethods());
        CGLIB$equals$1$Method = arrmethod[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(class_2, class_, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = arrmethod[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(class_2, class_, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = arrmethod[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(class_2, class_, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = arrmethod[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(class_2, class_, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        class_2 = Class.forName("com.hj.learn.autowire.GenericTypeAutoWire");
        CGLIB$print$0$Method = ReflectUtils.findMethods(new String[]{"print", "()V"}, class_2.getDeclaredMethods())[0];
        CGLIB$print$0$Proxy = MethodProxy.create(class_2, class_, "()V", "print", "CGLIB$print$0");
    }

    final void CGLIB$print$0() {
        super.print();
    }

    @Override
    public final void print() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            GenericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d.CGLIB$BIND_CALLBACKS(this);
            // 将CGLIB$CALLBACK_0赋值给methodInterceptor,而这个this.CGLIB$CALLBACK_0在源码2处赋值
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
        // 源码1
            Object object = methodInterceptor.intercept(this, CGLIB$print$0$Method, CGLIB$emptyArgs, CGLIB$print$0$Proxy);
            return;
        }
        super.print();
    }
    
      private static final void CGLIB$BIND_CALLBACKS(Object object) {
        block2: {
            Object object2;
            GenericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d;
            block3: {
                genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d = (GenericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d)object;
                if (genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d.CGLIB$BOUND) break block2;
                genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d.CGLIB$BOUND = true;
                object2 = CGLIB$THREAD_CALLBACKS.get();
                if (object2 != null) break block3;
                object2 = CGLIB$STATIC_CALLBACKS;
                if (CGLIB$STATIC_CALLBACKS == null) break block2;
            }
            Callback[] arrcallback = (Callback[])object2;
            GenericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d2 = genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d;
            genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d2.CGLIB$CALLBACK_6 = (MethodInterceptor)arrcallback[6];
            genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d2.CGLIB$CALLBACK_5 = (MethodInterceptor)arrcallback[5];
            genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d2.CGLIB$CALLBACK_4 = (Dispatcher)arrcallback[4];
            genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d2.CGLIB$CALLBACK_3 = (NoOp)arrcallback[3];
            genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d2.CGLIB$CALLBACK_2 = (NoOp)arrcallback[2];
            genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d2.CGLIB$CALLBACK_1 = (MethodInterceptor)arrcallback[1];
            // 源码2
            genericTypeAutoWire$$EnhancerBySpringCGLIB$$7645618d2.CGLIB$CALLBACK_0 = (MethodInterceptor)arrcallback[0];
        }
    }

在这段代码的【源码1】可以看出print方法被代理后会先调用Object object = methodInterceptor.intercept(this, CGLIB$print 0 0 0Method, CGLIB e m p t y A r g s , C G L I B emptyArgs, CGLIB emptyArgs,CGLIBprint 0 0 0Proxy);方法,这个方法在【源码2】位置处被赋值,可以看出是arrcallback数组的0号位置,那这个数组就在CglibAopProxy类的getProxy方法里:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IAHQznJp-1604976239246)(quiver-image-url/06B4FFFCD65A24B395B37F115AF0324F.jpg =932x778)]

接着看getCallbacks方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6YSfVtO6-1604976239247)(quiver-image-url/3C4C16445B4DFEE66981CA9196FCC235.jpg =920x831)]

这里可以看出这个0号下标的拦截器是个DynamicAdvisedInterceptor类,那么就看这个类的intercept方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yMP5Bdkm-1604976239247)(quiver-image-url/48F91D26CBF123B8D075D8EA8248DF64.jpg =997x880)]

可以看出这个拦截器的拦截方法里最终也是调用了TargetSource的getTarget方法。
到这就能看到@Lazy注解是怎么实现懒加载的,在注入的时候用@Lazy标注的话,Spring容器会生成这个类的代理类,所以在没有调用这个代理类的方法前,被注入的是这个proxy,而代理类在每个方法被真正调用前会调用这个了TargetSource的getTarget方法来实现真正的实例化,以此来实现在真正使用的时候再做懒加载。

4.2.2源码
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

这部分主要是注册ConfigurationClassPostProcessor这个后置处理器,之所以能在被@Configuration标注的类里用@Bean来生成bean,就是这个类在起作用,先看下类图,可以看到这个类实现了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor接口,这两个接口定义了BeanDefinition被加载到Spring容器后的回调方法 以及 在BeanFactory实例化的后置回调方法 ,至于让@Bean起作用的原理,感兴趣的同学可以看下这个类的postProcessBeanDefinitionRegistry方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pFlYI0fE-1604976239248)(quiver-image-url/2749C3F0DAFA6B12B823F77947D210E6.jpg =1186x320)]

4.2.3源码
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

这部分是注册AutowiredAnnotationBeanPostProcessor后置处理器,该处理器主要负责解析@Autowired @Value注解的注入逻辑,我们常用@Value来注入配置文件里配置的内容

4.2.4源码
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

这部分是注册CommonAnnotationBeanPostProcessor后置处理器,该处理器主要负责@PostConstruct、@PreDestroy、 @Resource、@WebServiceRef注解的逻辑,@PostConstruct标注在方法上,用来告诉容器在当前这个对象的构造方法被调用后执行这个方法、@PreDestroy标注在方法上,用来告诉容器在bean销毁前需要执行这个方法(比如线程池的shutdown、资源的释放等)、 @Resource告知容器需要注入这个属性、@WebServiceRef是告知容器注入一个webservice远程调用的代理对象(现在很少用,可以忽略)

4.2.5源码
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition();
			try {
				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
						AnnotationConfigUtils.class.getClassLoader()));
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
			}
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

这部分是新增PersistenceAnnotationBeanPostProcessor后置处理器,解析@PersistenceUnit、@PersistenceContext注解的逻辑

4.2.6源码
// 4.2.6源码
		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}

注册EventListenerMethodProcessor后置处理器,这个是解析@EventListener注解的逻辑,我们经常会用到事件的发布和订阅逻辑,这个注解就是用来注册事件监听者的

4.2.7源码
    // 4.2.7源码
		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

注册DefaultEventListenerFactory,这个类负责将4.2.6源码里的EventListenerMethodProcessor后置处理器解析出来被@EventListener标注的方法生成真正的Listener的

4.3

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] {ConfigurableApplicationContext.class }, context);  

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}  

作用就是检查spring.factories配置文件(详细逻辑见启动过程二)里查找配置的SpringBootExceptionReporter类,这个类的作用就是在启动过程中出现异常后,会调用该类的reportException方法,比如springboot默认的是org.springframework.boot.diagnostics.FailureAnalyzers类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ab4GcWJV-1604976239249)(quiver-image-url/27D1AE512ADB77F733ADDF68C6ACF94D.jpg =1895x639)]

看下这个类的reportException方法:

public boolean reportException(Throwable failure) {
		FailureAnalysis analysis = analyze(failure, this.analyzers);
		return report(analysis, this.classLoader);
	}
	
	
	private FailureAnalysis analyze(Throwable failure, List<FailureAnalyzer> analyzers) {
		for (FailureAnalyzer analyzer : analyzers) {
			try {
				FailureAnalysis analysis = analyzer.analyze(failure);
				if (analysis != null) {
					return analysis;
				}
			}
			catch (Throwable ex) {
				logger.debug("FailureAnalyzer " + analyzer + " failed", ex);
			}
		}
		return null;
	}

	private boolean report(FailureAnalysis analysis, ClassLoader classLoader) {
		List<FailureAnalysisReporter> reporters = SpringFactoriesLoader.loadFactories(FailureAnalysisReporter.class,
				classLoader);
		if (analysis == null || reporters.isEmpty()) {
			return false;
		}
		for (FailureAnalysisReporter reporter : reporters) {
			reporter.report(analysis);
		}
		return true;
	}

这里可以看到在发生异常时候,spring容器会先遍历项目里配置的FailureAnalyzer分析异常,并将FailureAnalyzer返回的结果通过FailureAnalysisReporter来执行具体的report逻辑,而FailureAnalyzer和FailureAnalysisReporte也是通过遍历spring.factories配置文件来配置的,比如springboot默认的如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9y5xKlah-1604976239249)(quiver-image-url/257756FC14E695BD38E7EBE6DE3275DE.jpg =1823x687)]

可以看到 springboot默认配置了一个org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter来讲异常输出到日志里,大家应该很眼熟:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0b6928Xi-1604976239250)(quiver-image-url/07F225B966FE724D629E241489572A1A.jpg =1086x596)]

总结及思考

这段源码做了什么?

分析了4.0到4.3的源码,可以看出这部分还是在做一些准备工作:

  1. 加载banner配置,打印banner信息
  2. 创建ApplicationContext对象,这个是最核心和最顶层的对象,将贯穿整个启动过程,而这个对象的构造器里会创建两个重要对象:
  • AnnotatedBeanDefinitionReader对象,在这个类的构造器里会加载各种初始的后置处理器、监听器,用来支持Spring的原始注解,包括@Conditional、@Lazy、@Aotowire、@Qualifier、@Value、@PostConstruct、@PreDestroy、 @Resource、@WebServiceRef、@EventListener注解,这里基本包含了我们常用的注解,这些后置处理器里就包括最重要的后置处理器ConfigurationClassPostProcessor.class(负责扫描包路径,并将需要管理的bean封装成beanDefinition注册到容器内)
  • ClassPathBeanDefinitionScanner对象,这个对象就是负责扫描指定的包路径下的所有类,将需要被容器管理的类包装成BeanDefinition注册到BeanFactory里,核心代码就在scan方法里
    3、加载配置的SpringBootExceptionReporter

学到了哪些东西?

了解了ApplicationContext对象的创建过程中创建的两个非常重要的对象,一个负责扫描类,一个负责解析注解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值