spring容器加载分析 一容器构造

2018-01-20 11:07:20来源:https://www.jianshu.com/p/86b53e3f0264作者:wangjie2016人点击

分享

目前的spring应用很少有使用XML进行配置的,springboot就是使用AnnotationConfigApplicationContext和AnnotationConfigEmbeddedWebApplicationContext作为非web应用和web应用的容器。所以就以AnnotationConfigApplicationContext为列来分析容器的加载过程。
构造方法:


public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
// 构造函数
this();
// 向容器注册新的注解Bean
register(annotatedClasses);
// 刷新容器, 整个容器的加载都在这个方法中了
refresh();
}

step 1、this()无参构造方法:


public AnnotationConfigApplicationContext() {
// 初始化:基于注解的BeanDefinition读取器
// this就是AnnotatedBeanDefinitionReader中的BeanDefinitionRegistry
this.reader = new AnnotatedBeanDefinitionReader(this);
// 初始化:基于路径的BeanDefinition扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

同时也调用了父类的无参构造方法:


public GenericApplicationContext() {
// 实例化了默认的beanFactory
this.beanFactory = new DefaultListableBeanFactory();
}

AnnotatedBeanDefinitionReader初始化方法:


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;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)是一个关键的方法,在这个方法中向向容器中注册6个默认的BeanDefinition:
ConfigurationClassPostProcessor(实现自接口BeanFactoryPostProcessor)
AutowiredAnnotationBeanPostProcessor(实现自接口BeanPostProcessor)
RequiredAnnotationBeanPostProcessor(实现自接口BeanPostProcessor)
CommonAnnotationBeanPostProcessor(实现自接口BeanPostProcessor)
EventListenerMethodProcessor(实现自接口ApplicationContextAware)
DefaultEventListenerFactory(实现自接口EventListenerFactory)
这6个BeanDefinition对Spring至关重要,后面会有更详尽的阐述。


step 2、register(annotatedClasses)向容器注解新的annotatedClasses:
调用的是AnnotatedBeanDefinitionReader中的方法。


public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
// 创建BeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
// 判断是否需要跳过(Condition注解)
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// scopeMetadataResolver = AnnotationScopeMetadataResolver
// 解析注解Bean定义的作用域,
// 若@Scope("prototype"),则Bean为原型类型
// 若@Scope("singleton"),则Bean为单态类型
// 默认为singleton
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 注解Bean定义生成Bean名称
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 处理通用注解 如:Lazy DependsOn 等
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 解析限定符注解
// 主要是配置的关于autowiring自动依赖注入装配的限定条件,即@Qualifier注解
// Spring的autowiring默认是按类型装配,如果使用@Qualifier则按名称 和@Resource一样
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
// 如果配置了@Primary注解,设置该Bean为autowiring自动依赖注入装//配时的首选
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
//如果配置了@Lazy注解,则设置该Bean为延迟初始化,否则则该Bean为预实例化
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
// 如果使用了除@Primary和@Lazy以外的其他注解,则为该Bean添加一 个autowiring自动依赖注入装配限定符
// 该Bean在进autowiring自动依赖注入装配时,根据名称装配限定符指定的Bean
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
// 创建bean持有类
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 根据注解Bean定义类中配置的作用域,创建BeanDefinition相应的代理对象
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注册BeanDefinition,这个方法中会注册所有的alias
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

annotatedClass已经注册到容器,但是还没有实例化。
this.conditionEvaluator.shouldSkip(abd.getMetadata())) 来判断是否满足Bean创建的条件,如果不满足则跳过。
一个Condition的示例:


/**
* 条件:Linux操作系统
*/
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Linux");
}
}

使用方式:


@Configuration
@Conditional(LinuxCondition.class)
public class LinuxStartupConfig{
... ...
}

如果当前的操作系统不是Linux,那么LinuxStartupConfig这个Bean将不会创建。springboot提供的6个@ConditionalOnxxx就基于@Conditional注解和Condition接口实现的。


step 3、refresh() 容器刷新
所有Bean的加载和各种依赖的注入都在这个方法中实现的,之前先了解下两个接口BeanFactoryPostProcessor和BeanPostProcessor,它们都是Spring容器初始化时对外暴露的扩展点。


BeanFactoryPostProcesso接口:


public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

只有一个方法postProcessBeanFactory(),它是在容器注册了Bean定义(BeanDefinition)之后,实例化之前执行的。通过这个接口可以获取Bean定义的元数据并且修改它们,如Bean的scope属性、property值等,也可以操作beanFactory。


BeanPostProcessor接口:


public interface BeanPostProcessor {
// 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
// 实例化、依赖注入、初始化完毕时执行。
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

BeanPostProcessor会在Bean实例化完毕后执行,所以任何BeanPostProcessor都是在BeanFactoryPostProcessor之后执行的。
BeanPostProcessor的作用可大了,比如自动注入、各种代理(AOP)等等,凡是对需要Bean进行增强操作的大都可以通过它来实现。


码字不易,转载请保留原文连接https://www.jianshu.com/p/86b53e3f0264





微信扫一扫

第七城市微信公众平台