【Spring】@Autowired注⼊流程
@Autowired注⼊流程
与xml配置⽅式相⽐,开启注解处理之后在加载BeanDefinition时会额外添加⼏个⽤于处理注解的组件,⼀个
BeanDefinitionRegistryPostProcessor和若⼲个BeanPostProcessor,这些组件⽤于在bean的各个⽣命周期中对标注的注解做相应的处理。
⼤体流程与不使⽤注解的⽅式类似,使⽤注解的⽅式只是在某些阶段额外做了⼀些对于注解的处理。开启注解扫描其实就是在原有的基础上增加了⼀些功能。
初始化⼯⼚,加载BeanDefinition
同样使⽤XmlBeanDefinitionReader先将xml配置⽂件封装为Resource,然后将Resource转成流并使⽤DOM解析得到Document,然后从根节点开始遍历所有节点。
当扫描到<context:component-scan base-package=“bean”/>标签时,会加载⽤来解析该节点所属namespace的NamespaceHandler,namespace与NamespaceHandler的对应关系在META-INF\spring.h
andlers⽂件中,因此会加载ContextNamespaceHandler⽤来处理<context:component-scan/>标签。
通过调⽤Class.forName()实例化ContextNamespaceHandler,并调⽤其init()⽅法,在init()⽅法中会注册该namespace下每个标签对应的BeanDefinitionParser,保存在⼀个Map中。
@Override
public void init(){
registerBeanDefinitionParser("property-placeholder",new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override",new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config",new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan",new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver",new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured",new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export",new MBeanExportBeanDefinitionParser());
resource和autowired注解的区别registerBeanDefinitionParser("mbean-server",new MBeanServerBeanDefinitionParser());
}
然后到与<context:component-scan>标签对应的BeanDefinitionPaser,调⽤parse()⽅法开始解析。
public BeanDefinition parse(Element element, ParserContext parserContext){
//...
// Actually scan for bean definitions and register them.
ClassPathBeanDefinitionScanner scanner =configureScanner(parserContext, element);
//扫描并注册BeanDefinition
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
/
/注册处理注解相关的其他组件
ReaderContext(), beanDefinitions, element);
return null;
}
doScan()⽅法会扫描并注册BeanDefinition,流程如下:
⾸先获取标签的base-package属性的值,扫描该包下的所有*.class⽂件并包装成Resource,遍历每个Resource,获取其元数据,判断该类上是否有@Component注解(@Service、@Repository、@Controller其实都被@Component标注),并且判断是否有
@Conditional注解,如果不符合条件则跳过,符合条件则将该Resource转换为BeanDefinition注册到beanFactory的Map中。
protected Set<BeanDefinitionHolder> basePackages){
Set<BeanDefinitionHolder> beanDefinitions =new LinkedHashSet<>();
//遍历指定的每个包
for(String basePackage : basePackages){
//扫描当前包下含有@Component的类并封装为BeanDefinition
Set<BeanDefinition> candidates =findCandidateComponents(basePackage);
//处理每个BeanDefinition并判断是否需要注册到容器中
for(BeanDefinition candidate : candidates){
ScopeMetadata scopeMetadata =solveScopeMetadata(candidate);
candidate.ScopeName());
String beanName =ateBeanName(istry);
if(candidate instanceof AbstractBeanDefinition){
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if(candidate instanceof AnnotatedBeanDefinition){
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//判断该BeanDefinition是否应该注⼊到容器中
if(checkCandidate(beanName, candidate)){
BeanDefinitionHolder definitionHolder =new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, istry);
beanDefinitions.add(definitionHolder);
/
/将BeanDefinition注册到容器中
registerBeanDefinition(istry);
}
}
}
return beanDefinitions;
}
在findCandidateComponents()⽅法中会调⽤isCandidateComponent()⽅法根据Resource的元数据判断当前类上是否含有
@Component注解,如果没有则跳过该类,如果有则判断当前类是否还标注了@Conditional注解,如果标注了则会去处理@Conditional 注解判断当前类是否需要跳过。如果该类符合条件则将其封装为BeanDefinition返回。对于每⼀个BeanDefinition都要根据其类型做相应的处理,例如依据@Lazy注解
设置该BeanDefinition的属性。对BeanDefinition做完相应的处理之后会判断每⼀个BeanDefinition是否应该被注⼊到容器中,判断条件是:如果容器中不存在beanName相同的BeanDefinition则直接将该BeanDefinition注⼊到容器中,否则不注册。
⾄此,doScan()⽅法结束,也就是说@Component所标记的类已经被封装为BeanDefinition注册到容器中,接下来会调⽤registerComponents()⽅法向容器中注⼊⼀些处理注解所需要的组件。
registerComponents()⽅法⾸先会判断<context:component-scan>标签的annotation-config的属性是否为true(默认为true,除⾮在xml 中显⽰配置为false),该属性表⽰将来是否需要处理已加载到容器中的bean中包含的注解。如果此属性配置为true,则会在注册完
@Component标记的类之后会注册⼀系列处理注解需要的组件,新注册的组件为:ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、EventListenerMethodProcessor、DefaultEventListenerFactory。
⾄此,<context:component-scan>标签处理完毕,接着会处理xml中的其他标签,直到对应的BeanDefinition全部注册到容器中。
实例化并有序调⽤BeanFactoryPostProcessor
步骤同xml配置,分类->排序->调⽤,⾸先会实例化并调⽤BeanDefinitionRegistryPostProcessor接⼝的实现类,在这⾥会调⽤之前注册的ConfigurationClassPostProcessor,因为这个类实现了BeanDefinitionRegistryPostProcessor接⼝(BeanFactoryPostProcessor接⼝的扩展),可以在所有BeanDefinition注册到容器之后做⼀些操作。这个类⽤于处理与配置相关的注解,⽐如@Configuration、@PropertySources、@ComponentScans、@ImportResource等注解。
BeanDefinitionRegistryPostProcessor接⼝的实现类实例化并调⽤完成后,会实例化并调⽤仅实现了BeanFactoryPostProcessor接⼝的类的对应⽅法。
实例化并有序注册BeanPostProcessor
步骤同xml配置,分类->排序->注册,这⾥会将之前添加的AutowiredAnnotationBeanPostProcessor实例化并注册,这个BeanPostProcessor主要⽤来处理@Autowired注解。
实例化Bean
实例化bean之前会调⽤InstantiationAwareBeanPostProcessor接⼝的postProcessBeforeInstantiation()⽅法,然后从BeanDefinition中拿到Class并实例化对象,实例化之后会调⽤MergedBeanDefinitionPostProcessor接⼝的postProcessMergedBeanDefinition()⽅法。Autowi
redAnnotationBeanPostProcessor也实现了该接⼝,在这个⽅法中会扫描被实例化的这个bean的注解信息并包装成InjectionMetadata,⾥⾯包含所有字段和⽅法上的注解信息,然后以beanName为key、封装的注解元数据为value缓存到injectionMetadataCache中。
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName){
InjectionMetadata metadata =findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz,@Nullable PropertyValues pvs){
//...
InjectionMetadata metadata =(cacheKey);
dsRefresh(metadata, clazz)){
synchronized(this.injectionMetadataCache){
metadata =(cacheKey);
dsRefresh(metadata, clazz)){
if(metadata != null){
metadata.clear(pvs);
}
//构建⾃动注⼊元数据
//使⽤反射处理所有属性和⽅法,将注解信息包装为InjectionMetadata
metadata =buildAutowiringMetadata(clazz);
//将InjectionMetadata添加⾄Map缓存
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
所有的MergedBeanDefinitionPostProcessor调⽤完成后,会将实例化后但没填充属性的bean保存到三级缓存中⽤来解决循环依赖,最后调⽤InstantiationAwareBeanPostProcessor接⼝的postProcessAfterInstantiation()⽅法。
接着在填充属性之前会调⽤所有InstantiationAwareBeanPostProcessor接⼝实现类的postProcessProperties()⽅法,在这⾥会调⽤AutowiredAnnotationBeanPostProcessor的postProcessProperties()⽅法。
在这个⽅法中,⾸先会依据beanName为key从之前构建的injectionMetadataCache中到该bean对应的注解元数据InjectionMetadata,注解元数据中指明了哪些成员变量或⽅法包含了哪些注解,拿到InjectionMetadata后会处理每⼀个标有
@Autowired的成员变量(或⽅法)。这种被标注的成员变量被封装为InjectedElement,然后为每⼀个element调⽤inject()⽅法寻并注⼊所需bean。
protected void inject(Object bean,@Nullable String beanName,@Nullable PropertyValues pvs)throws Throwable {
Field field =(ber;
Object value;
//缓存过则直接从缓存中拿
if(this.cached){
value =resolvedCachedArgument(beanName,this.cachedFieldValue);
}
else{
//...
try{
//解析需要注⼊的依赖值
value = solveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
//将获取的依赖缓存起来
//...
}
if(value != null){
ReflectionUtils.makeAccessible(field);
//使⽤反射直接为成员变量赋值,因此@Autowired注⼊不需要提供setXX()⽅法
field.set(bean, value);
}
}
inject()⽅法中会调⽤solveDependency()来解析需要注⼊的依赖值,⾥⾯调⽤doResolveDependency()⽅法,主要解析步骤如下:
⾸先会使⽤反射查看该变量是否有@Value注解,如果有则获取注解中指定的值并返回。如果没有@Value注解则说明该变量需要注⼊容器中的bean,那么就会调⽤findAutowireCandidates()⽅法去容器中寻所需类型的bean,如果容器中存在已经完全实例化过的bean则将bean实例返回,否则会从BeanDefinition中到Class并返回。如果返回的是该bean的Class,则会在resolveCandidate()⽅法中调⽤Bean()⽅法来获取bean的实例(如果发⽣循环引⽤则会在三级缓存中得到bean的提前引⽤)。最后使⽤反射将获取到的bean注⼊到@Autowired标注的变量⾥(这⾥可以看出@Autowired不需要提供set⽅法,⽽xml设置属性必须提供对应的set⽅法,因为xml设置属性值是通过反射调⽤对应属性的setXX⽅法实现的)。
public Object doResolveDependency(DependencyDescriptor descriptor,@Nullable String beanName,
@Nullable Set<String> autowiredBeanNames,@Nullable TypeConverter typeConverter)throws BeansException {
try{
//...
Class<?> type = DependencyType();
//尝试从@Value注解中获取到应被注⼊的值
Object value =getAutowireCandidateResolver().getSuggestedValue(descriptor);
if(value != null){
//...
//解析得到的值,判断是否需要转换
//如果需要转换则转换成功后直接return
//...
}
//判断需要注⼊的成员变量是否为数组、Collection、Map,查值并做相应的转换操作
Object multipleBeans =resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if(multipleBeans != null){
return multipleBeans;
}
//如果以上都不是则说明需要注⼊⼀个容器中的其他bean
//寻符合条件的bean,返回的可能是bean实例,也可能是Class
Map<String, Object> matchingBeans =findAutowireCandidates(beanName, type, descriptor);
//多个bean符合条件则判断应该使⽤哪⼀个
if(matchingBeans.size()>1){
//根据BeanDefinition的isPrimary属性判断应该使⽤哪个
autowiredBeanName =determineAutowireCandidate(matchingBeans, descriptor);
//...
//根据符合条件的name从众多候选bean中得到符合条件的bean
instanceCandidate = (autowiredBeanName);
}
else{
//只到唯⼀的⼀个符合条件的bean或Class
Map.Entry<String, Object> entry = Set().iterator().next();
autowiredBeanName = Key();
instanceCandidate = Value();
}
//如果前⾯得到的是符合条件的Class,则在这⾥调⽤resolveCandidate()⽅法
//⾥⾯调⽤了Bean(beanName)⽅法获取bean
//如果该bean未实例化则跳转去执⾏bean的实例化操作(getBean()⽅法都能做到)
if(instanceCandidate instanceof Class){
instanceCandidate = solveCandidate(autowiredBeanName, type,this);
}
Object result = instanceCandidate;
//省略判null操作...
return result;
}
}
⾄此@Autowired注解已经处理完毕,接着会继续⾛bean的⽣命周期流程,如果在xml中指定了bean成员变量的值,则在这⾥会将xml中指定的值赋给bean的成员变量(如果之前通过@Value指定初始值则在这⾥会被xml中指定的值覆盖)。
关于xml和注解同时定义bean的优先级问题
1. 如果xml⾥先定义了⼀个bean,之后在处理<context:component-scan/>标签时(即扫描注解指定的bean时)不能再注册同名的
bean。
2. 如果先通过注解注册了⼀个bean(即<context:component-scan/>标签位于<bean>标签之上,所以先被解析),之后在处理
<bean>标签时,会先判断allowBeanDefinitionOverriding标志是否为true(默认为true),如果允许覆盖则xml⾥定义的bean会覆盖注解注⼊的bean,如果不允许覆盖则抛异常。
总结:如果容器允许覆盖BeanDefinition则xml中定义的bean会覆盖掉注解定义的bean,反之不成⽴。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论