您的位置:首页 > 移动开发

spring boot实战(第九篇)Application创建源码分析

2017-11-28 09:17 876 查看


前言

通过前面的文章了解到在spring boot的启动时,利用的是编写的Application类,使用了注解@SpringBootApplication,本篇将阐述该Bean的加载过程。

[html] view
plain copy

@SpringBootApplication

public class Application {

public static void main(String[] args) {

SpringApplication app = new SpringApplication(Application.class);

app.addListeners(new MyApplicationStartedEventListener());

app.run(args);

}

}


Application

上篇中讲述了上下文的创建,在run方法中接下来会执行

[html] view
plain copy

load(context, sources.toArray(new Object[sources.size()]));

这个的sources表示的为Application类,在创建SpringApplication时手动传递

[html] view
plain copy

SpringApplication app = new SpringApplication(Application.class);

load方法如下:

[html] view
plain copy

protected void load(ApplicationContext context, Object[] sources) {

if (this.log.isDebugEnabled()) {

this.log.debug("Loading source "

+ StringUtils.arrayToCommaDelimitedString(sources));

}

BeanDefinitionLoader loader = createBeanDefinitionLoader(

getBeanDefinitionRegistry(context), sources);

if (this.beanNameGenerator != null) {

loader.setBeanNameGenerator(this.beanNameGenerato
1939f
r);

}

if (this.resourceLoader != null) {

loader.setResourceLoader(this.resourceLoader);

}

if (this.environment != null) {

loader.setEnvironment(this.environment);

}

loader.load();

}

调用loader.load();

[html] view
plain copy

private int load(Object source) {

Assert.notNull(source, "Source must not be null");

if (source instanceof Class<?>) {

return load((Class<?>) source);

}

if (source instanceof Resource) {

return load((Resource) source);

}

if (source instanceof Package) {

return load((Package) source);

}

if (source instanceof CharSequence) {

return load((CharSequence) source);

}

throw new IllegalArgumentException("Invalid source type " + source.getClass());

}

执行load((Class<?>) source)

[html] view
plain copy

private int load(Class<?> source) {

if (isGroovyPresent()) {

// Any GroovyLoaders added in beans{} DSL can contribute beans here

if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {

GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,

GroovyBeanDefinitionSource.class);

load(loader);

}

}

if (isComponent(source)) {

this.annotatedReader.register(source);

return 1;

}

return 0;

}

isComponent判断Application是否存在注解Compent

[html] view
plain copy

private boolean isComponent(Class<?> type) {

// This has to be a bit of a guess. The only way to be sure that this type is

// eligible is to make a bean definition out of it and try to instantiate it.

if (AnnotationUtils.findAnnotation(type, Component.class) != null) {

return true;

}

// Nested anonymous classes are not eligible for registration, nor are groovy

// closures

if (type.getName().matches(".*\\$_.*closure.*") || type.isAnonymousClass()

|| type.getConstructors() == null || type.getConstructors().length == 0) {

return false;

}

return true;

}

AnnotationUtils.findAnnotation(type, Component.class)
工具类获取执行类对应的注解信息,该工具类在自己编码代码时可用得到

由于Application使用注解@SpringBootApplication,其定义如下

[html] view
plain copy

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@Configuration

@EnableAutoConfiguration

@ComponentScan

public @interface SpringBootApplication {

/**

* Exclude specific auto-configuration classes such that they will never be applied.

* @return the classes to exclude

*/

Class<?>[] exclude() default {};

}

发现不存在Compoment注解,是不是表明Application不是一个Component呢?其实不然,来看下@Configuration注解

[html] view
plain copy

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Component

public @interface Configuration {

/**

* Explicitly specify the name of the Spring bean definition associated

* with this Configuration class. If left unspecified (the common case),

* a bean name will be automatically generated.

* <p>The custom name applies only if the Configuration class is picked up via

* component scanning or supplied directly to a {@link AnnotationConfigApplicationContext}.

* If the Configuration class is registered as a traditional XML bean definition,

* the name/id of the bean element will take precedence.

* @return the specified bean name, if any

* @see org.springframework.beans.factory.support.DefaultBeanNameGenerator

*/

String value() default "";

}

发现Configuration注解上存在Component注解,表明Application为Component

接下来执行this.annotatedReader.register(source);

[html] view
plain copy

public void register(Class<?>... annotatedClasses) {

for (Class<?> annotatedClass : annotatedClasses) {

registerBean(annotatedClass);

}

}

调用registerBean注册Application对应的bean信息

[html] view
plain copy

public void registerBean(Class<?> annotatedClass, String name,

@SuppressWarnings("unchecked") 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.equals(qualifier)) {

abd.setPrimary(true);

}

else if (Lazy.class.equals(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);

}

首先来看

[html] view
plain copy

if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {

return;

}

判断是否需要跳过,其代码如下:

[html] view
plain copy

public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {

if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {

return false;

}

if (phase == null) {

if (metadata instanceof AnnotationMetadata &&

ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {

return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);

}

return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);

}

List<Condition> conditions = new ArrayList<Condition>();

for (String[] conditionClasses : getConditionClasses(metadata)) {

for (String conditionClass : conditionClasses) {

Condition condition = getCondition(conditionClass, this.context.getClassLoader());

conditions.add(condition);

}

}

AnnotationAwareOrderComparator.sort(conditions);

for (Condition condition : conditions) {

ConfigurationPhase requiredPhase = null;

if (condition instanceof ConfigurationCondition) {

requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();

}

if (requiredPhase == null || requiredPhase == phase) {

if (!condition.matches(this.context, metadata)) {

return true;

}

}

}

return false;

}

该代码判断Application上是否存在Conditional注解,如果不满足Conditional对应条件则该bean不被创建;


Conditional注解

代码分析到这里可以先看看Conditional注解的使用,其定义为:

[html] view
plain copy

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.TYPE, ElementType.METHOD})

public @interface Conditional {

/**

* All {@link Condition}s that must {@linkplain Condition#matches match}

* in order for the component to be registered.

*/

Class<? extends Condition>[] value();

}

从源码可以看出,首先判断Application上是否存在Conditional,如果存在,则获取Conditional注解中的value数组值,对应的Class必须实现Condition接口:

[html] view
plain copy

public interface Condition {

boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

如果matches返回true 表明该bean需要被创建,否则表明该bean不需要被创建。

明白了该注解的用法后,来一个实际案例

[html] view
plain copy

package com.lkl.springboot.condition;

import org.springframework.context.annotation.Conditional;

import org.springframework.stereotype.Component;

@Component("MyCondition")

@Conditional(MyCondition.class)

public class ConditionBean {

}

创建ConditionBean,使用注解@Conditional(MyCondition.class)调用MyCondition类

[html] view
plain copy

/**

* 自定义condition 修改返回值,查看bean是否创建

*

* @author liaokailin

*/

public class MyCondition implements Condition {

/**

* 返回true 生成bean

* 返回false 不生成bean

*/

@Override

public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

Map<String, Object> map = metadata.getAnnotationAttributes(Component.class.getName());

return "MyCondition".equals(map.get("value").toString());

}

}

MyCondition实现接口Condition,在matches方法中获取bean上注解Component信息,如果bean名称等于MyCondition返回true,否则返回false,bean不会被创建。

回到前面Application的分析,Application上不存在Conditional,因此shouldSkip返回false,代码继续执行

[html] view
plain copy

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);

处理Scope注解信息,默认是单例bean

执行

[html] view
plain copy

AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

处理一些常见注解信息

[html] view
plain copy

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {

if (metadata.isAnnotated(Lazy.class.getName())) {

abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value"));

}

else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) {

abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value"));

}

if (metadata.isAnnotated(Primary.class.getName())) {

abd.setPrimary(true);

}

if (metadata.isAnnotated(DependsOn.class.getName())) {

abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value"));

}

if (abd instanceof AbstractBeanDefinition) {

AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;

if (metadata.isAnnotated(Role.class.getName())) {

absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue());

}

if (metadata.isAnnotated(Description.class.getName())) {

absBd.setDescription(attributesFor(metadata, Description.class).getString("value"));

}

}

}

处理Lazy、Primary、DependsOn、Role、Description等注解

最后调用

[html] view
plain copy

BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

注册bean信息,在注册bean信息之前通过

[html] view
plain copy

String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

获取bean名称

bean的注册调用为

[html] view
plain copy

registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

该代码在上篇中已有说明。

此时Application对应bean已创建完成。

本文转自http://blog.csdn.net/liaokailin/article/details/49048557
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: