springBoot1.5.9.RELEASE启动源码分析之SpringApplication#prepareContext

 1.大致预览一下这个方法,方法的入参

context 为AnnotationConfigEmbeddedWebApplicationContext

environment 为 StandardServletEnvironment

listeners 为SpringApplicationRunListeners  

applicationArguments 为  DefaultApplicationArguments

printedBanner 为SpringApplicationBannerPrinter$PrintedBanner

 

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}

		// Add boot specific singleton beans
		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

		// Load the sources
		Set<Object> sources = getSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[sources.size()]));
		listeners.contextLoaded(context);
	}

2.context.setEnvironment(environment); 这个很简单

3.postProcessApplicationContext(context); 进入这个方法,

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
		if (this.beanNameGenerator != null) {
			context.getBeanFactory().registerSingleton(
					AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
					this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			if (context instanceof GenericApplicationContext) {
				((GenericApplicationContext) context)
						.setResourceLoader(this.resourceLoader);
			}
			if (context instanceof DefaultResourceLoader) {
				((DefaultResourceLoader) context)
						.setClassLoader(this.resourceLoader.getClassLoader());
			}
		}
	}

可以resourceLoader 和 beanNameGenerator都为null,此方法相当于什么都没做

4.applyInitializers(context)方法  

@SuppressWarnings({ "rawtypes", "unchecked" })
	protected void applyInitializers(ConfigurableApplicationContext context) {
		for (ApplicationContextInitializer initializer : getInitializers()) {
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
					initializer.getClass(), ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
			initializer.initialize(context);
		}
	}

这里就是将之前springApplication对象中initializers进行遍历,执行initializer.initialize(context);方法

其中 initializers以SharedMetadataReaderFactoryContextInitializer为例

@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		applicationContext.addBeanFactoryPostProcessor(
				new CachingMetadataReaderFactoryPostProcessor());
	}

这里是执行applicationContext.addBeanFactoryPostProcessor,也就是添加BeanFactoryPostProcessor

5.listeners.contextPrepared(context);这个方法会进入EventPublishingRunListener的contextPrepared,而这个方法特么是个空方法体,又什么也没干

@Override
	public void contextPrepared(ConfigurableApplicationContext context) {

	}

6.if (this.logStartupInfo) { logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}进入这个方法

context.getParent()为null,他没有父上下文,进入到logStartupInfo(true)

public void logStarting(Log log) {
		Assert.notNull(log, "Log must not be null");
		if (log.isInfoEnabled()) {
			log.info(getStartupMessage());
		}
		if (log.isDebugEnabled()) {
			log.debug(getRunningMessage());
		}
	}

 会打印日志

2019-08-12 11:15:14.835  INFO 24024 --- [           main] com.songhq.ZongHeApplication             : Starting ZongHeApplication on SC-201812171309 with PID 24024 (D:\songhaiqiang\code\workspace\my\zonghe\target\classes started by Administrator in D:\songhaiqiang\code\workspace\my\zonghe) 和

2019-08-12 11:17:04.169 DEBUG 24024 --- [           main] com.songhq.ZongHeApplication             : Running with Spring Boot v1.5.9.RELEASE, Spring v4.3.13.RELEASE

protected void logStartupProfileInfo(ConfigurableApplicationContext context) {
		Log log = getApplicationLog();
		if (log.isInfoEnabled()) {
			String[] activeProfiles = context.getEnvironment().getActiveProfiles();
			if (ObjectUtils.isEmpty(activeProfiles)) {
				String[] defaultProfiles = context.getEnvironment().getDefaultProfiles();
				log.info("No active profile set, falling back to default profiles: "
						+ StringUtils.arrayToCommaDelimitedString(defaultProfiles));
			}
			else {
				log.info("The following profiles are active: "
						+ StringUtils.arrayToCommaDelimitedString(activeProfiles));
			}
		}
	}

这个方法会打印

2019-08-12 11:18:44.820  INFO 24024 --- [           main] com.songhq.ZongHeApplication             : The following profiles are active: dev

7.进入context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);这个方法,

这个方法很明显,是在beanfactory手动注入一个springApplicationArguments的单例对象,我们这里看看registerSingleton这个方法,看看具体是如何注入的

@Override
	public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
		super.registerSingleton(beanName, singletonObject);

		if (hasBeanCreationStarted()) {
			// Cannot modify startup-time collection elements anymore (for stable iteration)
			synchronized (this.beanDefinitionMap) {
				if (!this.beanDefinitionMap.containsKey(beanName)) {
					Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames.size() + 1);
					updatedSingletons.addAll(this.manualSingletonNames);
					updatedSingletons.add(beanName);
					this.manualSingletonNames = updatedSingletons;
				}
			}
		}
		else {
			// Still in startup registration phase
			if (!this.beanDefinitionMap.containsKey(beanName)) {
				this.manualSingletonNames.add(beanName);
			}
		}

		clearByTypeCache();
	}

7.1super.registerSingleton(beanName, singletonObject); 进入DefaultSingletonBeanRegistry类中

@Override
	public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
		Assert.notNull(beanName, "'beanName' must not be null");
		synchronized (this.singletonObjects) {
			Object oldObject = this.singletonObjects.get(beanName);
			if (oldObject != null) {
				throw new IllegalStateException("Could not register object [" + singletonObject +
						"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
			}
			addSingleton(beanName, singletonObject);
		}
	}

看这个/** Cache of singleton objects: bean name --> bean instance */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);当前只有

{autoConfigurationReport=org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport@37fb0bed}这一个单例对象,所以会走addSingleton这个方法

protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

然后一步步返回

8. 走到  if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        },代码很简单,向context注入 一个单例的springBootBanner

9.走到  Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");  获取springApplication中的sources

10.进入 load(context, sources.toArray(new Object[sources.size()]));方法

protected void load(ApplicationContext context, Object[] sources) {
		if (logger.isDebugEnabled()) {
			logger.debug(
					"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
		}
		BeanDefinitionLoader loader = createBeanDefinitionLoader(
				getBeanDefinitionRegistry(context), sources);
		if (this.beanNameGenerator != null) {
			loader.setBeanNameGenerator(this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			loader.setResourceLoader(this.resourceLoader);
		}
		if (this.environment != null) {
			loader.setEnvironment(this.environment);
		}
		loader.load();
	}

10.1 if (logger.isDebugEnabled()) {
            logger.debug(
                    "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }

打印出日志2019-08-12 19:19:09.017 DEBUG 4068 --- [           main] o.s.boot.SpringApplication               : Loading source class com.songhq.ZongHeApplication

10.2 getBeanDefinitionRegistry(context)

private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
		if (context instanceof BeanDefinitionRegistry) {
			return (BeanDefinitionRegistry) context;
		}
		if (context instanceof AbstractApplicationContext) {
			return (BeanDefinitionRegistry) ((AbstractApplicationContext) context)
					.getBeanFactory();
		}
		throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
	}

这个方法时获取BeanDefinitionRegistry

继续进入createBeanDefinitionLoader方法

protected BeanDefinitionLoader createBeanDefinitionLoader(
			BeanDefinitionRegistry registry, Object[] sources) {
		return new BeanDefinitionLoader(registry, sources);
	}

再进入构造方法,BeanDefinitionLoader这个类是加载beanDefinition的,也是对AnnotatedBeanDefinitionReader,

ClassPathBeanDefinitionScanner,XmlBeanDefinitionReader 等类的包装

BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
		Assert.notNull(registry, "Registry must not be null");
		Assert.notEmpty(sources, "Sources must not be empty");
		this.sources = sources;
		this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
		this.xmlReader = new XmlBeanDefinitionReader(registry);
		if (isGroovyPresent()) {
			this.groovyReader = new GroovyBeanDefinitionReader(registry);
		}
		this.scanner = new ClassPathBeanDefinitionScanner(registry);
		this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
	}

10.3 进入 load.load(),根据sources的不同类型加载不同的load方法,这里用到了方法的重载

这里的sources 是ZhongHeApplication的clazz,走到了 load(Class<?> source)方法,最后走到this.annotatedReader.register(source);方法,进而走registerBean;如下

@SuppressWarnings("unchecked")
	public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

以这个对象AnnotatedGenericBeanDefinition封装我们的clazz,接着是解析此BeanDefinition的ScopeMetadata ,而一个ScopeMetadata对象里面有有两个默认的属性值,一个作用域的范围,一个是该范围的代理模式

作用域默认为singleton ,ScopedProxyMode默认为ScopedProxyMode.NO,即不创建代理

 private String scopeName = BeanDefinition.SCOPE_SINGLETON;

 private ScopedProxyMode scopedProxyMode = ScopedProxyMode.NO;

然后将ScopeMetadata对象的scoscoreName赋值给AnnotatedGenericBeanDefinition中的scope属性,此处就是singleton,

接下来进入this.beanNameGenerator.generateBeanName(abd, this.registry)方法,该方法在AnnotationBeanNameGenerator类中

@Override
	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		if (definition instanceof AnnotatedBeanDefinition) {
			String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
			if (StringUtils.hasText(beanName)) {
				// Explicit bean name found.
				return beanName;
			}
		}
		// Fallback: generate a unique default bean name.
		return buildDefaultBeanName(definition, registry);
	}

从这个方法的名称上看,就是根据BeanDefinition和BeanDefinitionRegistry 来生成这个bean的名称,

前面已经分析过,BeanDefinition是spring对原始bean的clazz封装和管理,注意还没生成对象,BeanDefinitionRegistry 又是个什么东西,这里具体看看,这里的BeanDefinitionRegistry当然是个接口

这个接口中关于接口的注释大致为:

于保存bean Definition例如rootbeanDefinition和childbeanDefinition的注册表的接口,通常由内部使用AbstractBeanDefinition层次结构的BeanFactory实现,可见他和重要,被BeanFactory实现

从名字上看他就是注册BeanDefinition的作用,这里的实现类是AnnotationConfigEmbeddedWebApplicationContext,正是前面的context ,该上下文也实现了BeanDefinitionRegistry接口

接下来看看 AnnotationBeanNameGenerator这个类,该类在类上的注释的大致意思是

该类是为了@Component注解实现的,也支持@ManagedBean 等注解

接下来要看 determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);方法

protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
		AnnotationMetadata amd = annotatedDef.getMetadata();
		Set<String> types = amd.getAnnotationTypes();
		String beanName = null;
		for (String type : types) {
			AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
			if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
				Object value = attributes.get("value");
				if (value instanceof String) {
					String strVal = (String) value;
					if (StringUtils.hasLength(strVal)) {
						if (beanName != null && !strVal.equals(beanName)) {
							throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
									"component names: '" + beanName + "' versus '" + strVal + "'");
						}
						beanName = strVal;
					}
				}
			}
		}
		return beanName;
	}

这里先是拿到了该clazz上的所有注解,这里ZongHeApplication.class,上的注解有@SpringBootApplication和
@EnableAspectJAutoProxy(proxyTargetClass = true)两个注解

至于怎么拿到的,最原始的方法为在java.lang.Class类中,而ZongHeApplication.class即是Class的一个实例

 public Annotation[] getAnnotations() {
        return AnnotationParser.toArray(annotationData().annotations);
    }

至于继续是怎么走的。这里我们不再深究,继续往下走,第一次遍历的是注解org.springframework.boot.autoconfigure.SpringBootApplication

进入isStereotypeWithNameValue方法,该方法就是判断你是否是Stereotype并且注解里面有value属性,也就是说你是否制定生成对象的对象名,很明显没有

第二次是这个注解org.springframework.context.annotation.EnableAspectJAutoProxy,很明显也没有

protected boolean isStereotypeWithNameValue(String annotationType,
			Set<String> metaAnnotationTypes, Map<String, Object> attributes) {

		boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
				(metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
				annotationType.equals("javax.annotation.ManagedBean") ||
				annotationType.equals("javax.inject.Named");

		return (isStereotype && attributes != null && attributes.containsKey("value"));
	}

没有制定生成对象的名字,就会走return buildDefaultBeanName(definition, registry);方法最后会进入这个方法

protected String buildDefaultBeanName(BeanDefinition definition) {
		String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
		return Introspector.decapitalize(shortClassName);
	}

他的shortClassName为ZongHeApplication,然后将的首字母小写,最后得到zongHeApplication

得到名称,和将所对应的beanDefinition处理好了,就轮到register取注册该bean了,该处的register为AnnotationConfigEmbeddedWebApplicationContext也是GenericApplicationContext的子类

在GenericApplicationContext中有如下方法

//---------------------------------------------------------------------
	// Implementation of BeanDefinitionRegistry
	//---------------------------------------------------------------------

	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
	}

这里嫁接到了this.beanFactory.registerBeanDefinition(beanName, beanDefinition);这里的beanFactory是DefaultListableBeanFactory

//---------------------------------------------------------------------
	// Implementation of BeanDefinitionRegistry interface
	//---------------------------------------------------------------------

	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition oldBeanDefinition;

		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(oldBeanDefinition)) {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

可以看出这里还是把它放在一map中去了,而且并没有实例化出来,至此第10步分析完毕

11.进入 listeners.contextLoaded(context);

再进入

public void contextLoaded(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextLoaded(context);
		}
	}

再进入,下面的方法先将listener处理一下,如果是ApplicationContextAware就把context赋值给他,然后广播事件ApplicationPreparedEvent

@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		for (ApplicationListener<?> listener : this.application.getListeners()) {
			if (listener instanceof ApplicationContextAware) {
				((ApplicationContextAware) listener).setApplicationContext(context);
			}
			context.addApplicationListener(listener);
		}
		this.initialMulticaster.multicastEvent(
				new ApplicationPreparedEvent(this.application, this.args, context));
	}

最终又走到listener.onApplicationEvent(event);方法上,与之前类似

自此prepareContext方法分析完毕

总结一下,大致对Context进行配置,然后注入一些bean,还有就是广播了一个ApplicationPreparedEvent事件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值