spring boot实战(第九篇)Application创建源码分析
2015-10-11 15:52
441 查看
前言
通过前面的文章了解到在spring boot的启动时,利用的是编写的Application类,使用了注解@SpringBootApplication,本篇将阐述该Bean的加载过程。@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方法中接下来会执行load(context, sources.toArray(new Object[sources.size()]));
这个的sources表示的为Application类,在创建SpringApplication时手动传递
SpringApplication app = new SpringApplication(Application.class);
load方法如下:
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.beanNameGenerator); } if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } if (this.environment != null) { loader.setEnvironment(this.environment); } loader.load(); }
调用loader.load();
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)
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
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,其定义如下
@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注解
@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);
public void register(Class<?>... annotatedClasses) { for (Class<?> annotatedClass : annotatedClasses) { registerBean(annotatedClass); } }
调用registerBean注册Application对应的bean信息
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); }
首先来看
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; }
判断是否需要跳过,其代码如下:
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注解的使用,其定义为:@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接口:
public interface Condition { boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }
如果matches返回true 表明该bean需要被创建,否则表明该bean不需要被创建。
明白了该注解的用法后,来一个实际案例
package com.u51.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类
/** * 自定义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,代码继续执行
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
处理Scope注解信息,默认是单例bean
执行
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
处理一些常见注解信息
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等注解
最后调用
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
注册bean信息,在注册bean信息之前通过
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
获取bean名称
bean的注册调用为
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
该代码在上篇中已有说明。
此时Application对应bean已创建完成。
相关文章推荐
- xcode 7.0 错误提示 The resource could not be loaded because the App Transport Security policy requires
- OC之类别总结
- android实现gif动态图的使用
- android实现gif动态图的使用
- Android中shape的使用
- android资源镜像
- Cocos2d-x 3.X, Android Studio版添加多盟广告平台
- Android NDK 编译时候出现 undefined reference to `__android_log_print
- Unity3d 镜面反射 vertex and frag Shader源代码
- Android读取SD卡中的媒体文件(MP3)
- 16.Swift 播放视频
- iOS5编程--ARC在工程上的相关设置
- Android常用辅助类(三)——存储相关
- php实现微信公众平台账号自定义菜单类
- iOS工程中的info.plist文件
- Android学习第一天之LinearLayout浅析
- Android - Binder机制
- 15.Swift 录制音频
- Android沉浸式状态栏简单实现
- 用Android studio创建Cocos2d-x 3.X项目