当前位置:   article > 正文

@Component,@service,@autowired等注解的实现原理_@service原理

@service原理

默认情况下bean Name的默认生成策略;

@component @service @Controller @Respository 

入口肯定是BeanNameGenerator接口声明的generateBeanName(BeanDefinition,BeanDefinitionRegistry)方法,该方法做了一个分类判断,处理AnnotationBeanDefinition和DefaultBeanNameGenerator两种方式的。这里只看注解方式。

 

  1. public interface BeanNameGenerator {
  2. String generateBeanName(BeanDefinition var1, BeanDefinitionRegistry var2);
  3. }

AnnotationBeanDefinition.java

  1. public class AnnotationBeanNameGenerator implements BeanNameGenerator {
  2. private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";
  3. @Override
  4. public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
  5. // 判断是AnnotatedBeanDefinition的实现,就从annotation获得。
  6. if (definition instanceof AnnotatedBeanDefinition) {
  7. String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
  8. // 是文本就返回这个beanName,但是也有可能annotation的valuenull,就后从buildDefaultBeanName获得
  9. if (StringUtils.hasText(beanName)) {
  10. return beanName;
  11. }
  12. }
  13. return buildDefaultBeanName(definition, registry);
  14. }
  15. protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
  16. // 获得类或者方法上所有的Annotation
  17. AnnotationMetadata amd = annotatedDef.getMetadata();
  18. // 得到所有annotation的类名
  19. Set<String> types = amd.getAnnotationTypes();
  20. String beanName = null;
  21. for (String type : types) {
  22. // 把annotation里面的字段与value,解读出来成map,字段名是keyvaluevalue
  23. AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
  24. // 判断annotation是否有效,是否存在作为beanName的字段有value
  25. if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
  26. // 从注解中获得value字段的值,
  27. Object value = attributes.get("value");
  28. if (value instanceof String) {
  29. String strVal = (String) value;
  30. if (StringUtils.hasLength(strVal)) {
  31. if (beanName != null && !strVal.equals(beanName)) {
  32. throw new IllegalStateException("Stereotype annotations suggest inconsistent " +"component names: '" + beanName + "' versus '" + strVal + "'");
  33. }
  34. beanName = strVal;
  35. }
  36. }
  37. }
  38. }
  39. return beanName;
  40. }
  41. protected boolean isStereotypeWithNameValue(String annotationType,Set<String> metaAnnotationTypes, Map<String, Object> attributes) {
  42. // 判断annotation的类型是否是这三种.
  43. // org.springframework.stereotype.Component
  44. // javax.annotation.ManagedBean
  45. // javax.inject.Named
  46. boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
  47. (metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
  48. annotationType.equals("javax.annotation.ManagedBean") ||
  49. annotationType.equals("javax.inject.Named");
  50. // 并且value存在值。才会返回true
  51. return (isStereotype && attributes != null && attributes.containsKey("value"));
  52. }
  53. protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
  54. return buildDefaultBeanName(definition);
  55. }
  56. protected String buildDefaultBeanName(BeanDefinition definition) {
  57. // 获得类名
  58. String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
  59. // 把类名第一个字母大写转小写
  60. return Introspector.decapitalize(shortClassName);
  61. }
  62. }

debug测试:容器启动就开始注册bean

然后进入到红色箭头指向的地方 

这里MconfiAop转为mconfiAop 

 

 以后注册进入容器中的beanName

默认的都是类名第一个字母小写,

不是默认策略就是value;里面的值value作为beanName

-------------------------------------------------- -------------------------------------------------- -----------

包扫描注册豆的原理分析

@service @Controller @Respository注解上面都标注了@Component注解它们之间是等效的

只是为了分层标注

@Component的实现原理:

我们知道它们是向IOC容器中注册beanDefiniton,而背景是自定义标签根据之前讲解的自定义标签解析

我们知道自定义标签的解析为如下方法DefaultBeanDefinitionDocumentReader.java

解析自定义标签的时候首先需要获得XML中名称空间BeanDefinitionParserDelegate.java

String namespaceUri = this.getNamespaceURI(ele);//xmlns:context="http://www.springframework.org/schema/context"

然后根据名称空间找到对应的找到对应的NameSpaceHandler来进行处理

NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

默认在/ META-INF下spring.handler

我们最终找到了ContextNamespaceHandler

  1. public class ContextNamespaceHandler extends NamespaceHandlerSupport {
  2. public void init() {
  3. this.registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
  4. this.registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
  5. this.registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
  6. this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
  7. 。。。。。。。

}

这段代码中注册了许多解析器,我们重点关注ComponentScanBeanDefinitionParser

锁定解析()方法

  1. public BeanDefinition parse(Element element, ParserContext parserContext) {
  2.     String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE); // 获取base-package属性
  3.     basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage); // 处理包路径 中的特殊符号,如${}
  4.     // 分割
  5.     String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
  6.             ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
  7.             /* 配置Scanner */
  8.     ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
  9.     /* 扫描 */
  10.     Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
  11.     /* 注册一些注解相关的PostProcessor,将BeanDefinition注册完成的事件通知给相关监听器 */
  12.     registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
  13.     return null;
  14. }

  1. protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
  2. return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters, readerContext.getEnvironment(), readerContext.getResourceLoader());
  3. }
直到  ClassPathScanningCandidateComponentProvider.java

protected void registerDefaultFilters(){
    //添加默认的组件注解的过滤器
    this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
}

我们看到了默认的@Component注解过滤器的添加,而我们常用的@服务,@控制器等注解都使用了@Component注解,所以同样会匹配这个过滤器。

protected Set <BeanDefinitionHolder> doScan(String ... basePackages){
    Assert.notEmpty(basePackages,“必须至少指定一个基本包”);
    设置<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet <BeanDefinitionHolder>();
    for(String basePackage:basePackages){
        / *获取候选的BeanDefinition * /
        Set <BeanDefinition> candidates = findCandidateComponents(basePackage);
        for(BeanDefinition candidate:candidate){
            / *处理@Scope注解元数据* /
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            //生成beanName
            String beanName = this.beanNameGenerator.generateBeanName(candidate,this.registry);
            if(候选instanceof AbstractBeanDefinition){
                postProcessBeanDefinition((AbstractBeanDefinition)candidate,beanName);
            }
            如果(候选的instanceof AnnotatedBeanDefinition){
            //其他注解的处理
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)候选);
            }
            //检查BeanDefinition
            if(checkCandidate(beanName,candidate)){
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate,beanName);
                definitionHolder =
                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry);
                beanDefinitions.add(definitionHolder);
                //注册BeanDefinition
                registerBeanDefinition(definitionHolder,this.registry);
            }

        }
    }
    返回的BeanDefinitions;
findCandidateComponents()方法会获取basePackage的值

里面的isCandidateComponent()方法用来过滤之前添加的过滤器过滤资源

protected boolean isCandidateComponent(MetadataReader metadataReader)throws IOException {
    // excludeFilter过滤
    for(TypeFilter tf:this.excludeFilters){
        if(tf.match(metadataReader,this.metadataReaderFactory)){
            return false;
        }
    }
    //
    includeFilter 过滤for(TypeFilter tf:this.includeFilters){
        if(tf.match(metadataReader,this.metadataReaderFactory)){
            // @Conditional注解解析和判断
            return isConditionMatch(metadataReader);
        }
    }
    返回false;
}
默认情况excludeFilters是空的,includeFilters包含之前添加的@Component注解的AnnotationTypeFilter,所以这里会过滤掉不包含@Component注解的类。然后就是生成beanDifiniton和注册beanDefinition

@Autowired

我们知道在整合SSM项目中我们一般是在实现类上加上@Component等组件,但是我们使用@Autowired注解注入的时候其实注入得是类型的接口下面看看演示:

如果使用@resource需要改变注入到beanName ---按名称装配

在@Autowired的定义中有下面一段话:链接

  1. Note that actual injection is performed through a BeanPostProcessor
  2. which in turn means that you cannot use @Autowired to inject references into BeanPostProcessor
  3. or BeanFactoryPostProcessor types.
  4. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class
  5. (which, by default, checks for the presence of this annotation).

 

有图可知AutowiredAnnotationBeanPostProcessor实现了BeanPostProcessor的,IOC容器启动时候@Autowired注解会工作

@autowired注释会自动装配按类型

这种类型有多个则会按照注册的属相值作为id注入:容器中有两个UserDao类型userdao1 userdao2,@ U​​serDao userdao2

则注入的userdao2类型加上@Qualifier( “userdao1”):使用@Qualifier指定需要装配的组件的ID,而不是使用属性名,明确指定使用userdao1自动装配默认一定要将属性赋值好,没有就会报错;可以使用@Autowired(required = false);

@Primary:让春天进行自动装配的时候,默认使用首选的豆;

下面看看原理:我们知道AutowiredAnnotationBeanPostProcessor实现的,查看该类的源码会发现它实现了MergedBeanDefinitionPostProcessor接口,进而实现了接口中的postProcessMergedBeanDefinition方法。

来源

根据对Spring源码的分析我们知道BeanPostProcessor原理在对豆的实例化和初始化时AbstractAutowireCapableBeanFactory.java中的doCreateBean方法中有这样一段代码

  1. synchronized(mbd.postProcessingLock) {
  2. if(!mbd.postProcessed) {
  3. try {
  4. this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
  5. } catch (Throwable var17) {
  6. throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
  7. }
  8. mbd.postProcessed = true;
  9. }
  10. }

在这段代码中会执行applyMergedBeanDefinitionPostProcessors(mbd,beanType,beanName),深入这段代码又会执行postProcessMergedBeanDefinition

  1. protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
  2. Iterator var4 = this.getBeanPostProcessors().iterator();
  3. while(var4.hasNext()) {
  4. BeanPostProcessor bp = (BeanPostProcessor)var4.next();
  5. if(bp instanceof MergedBeanDefinitionPostProcessor) {
  6. MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor)bp;
  7. bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
  8. }
  9. }
  10. }

接口

  1. public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {
  2. void postProcessMergedBeanDefinition(RootBeanDefinition var1, Class<?> var2, String var3);
  3. }

实现类

  1. public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
  2. 。。。。。。
  3. public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
  4. if(beanType != null) {
  5. //找到@autowired注解
  6. InjectionMetadata metadata = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);
  7. metadata.checkConfigMembers(beanDefinition);
  8. }
  9. }
  10. 。。。。。。。
  11. }

上述信息:找到beanName(也重要)

如何找到策略有疑惑

 

 

  1. AnnotationAttributes ann = AutowiredAnnotationBeanPostProcessor.this.findAutowiredAnnotation(bridgedMethod);
  2. //找到所有的注解方法
  3. private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
  4. if(ao.getAnnotations().length > 0) {
  5. //遍历所有的@autowired注解类型
  6. Iterator var2 = this.autowiredAnnotationTypes.iterator();
  7. while(var2.hasNext()) {
  8. Class<? extends Annotation> type = (Class)var2.next();
  9. AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
  10. if(attributes != null) {
  11. return attributes;
  12. }
  13. }
  14. }

同样,在doCreateBean方法中执行populateBean方法实现对属性的注入。


深入populateBean方法,有如下一段代码。

这段代码中会遍历所有注册过的BeanPostProcessor的接口实现类的实例,如果实例属于InstantiationAwareBeanPostProcessor类型的,则执行实例类的postProcessPropertyValues方法.AutowiredAnnotationBeanPostProcessor继承了InstantiationAwareBeanPostProcessorAdapter,而AutowiredAnnotationBeanPostProcessor间接实现了InstantiationAwareBeanPostProcessor接口,所以这里会执行到AutowiredAnnotationBeanPostProcessor类的postProcessPropertyValues方法,具体代码如下。

findAutowiringMetadata方法获取该bean的InjectionMetadata实例(也就是有哪些属性需要被自动装配,也就是查找被@Autowired注解标记的元素) 

metadata.inject(bean,beanName,pvs)代码的执行会进入如下注入方法中,在这里完成依赖的注入。

  1. AutowiredAnnotationBeanPostProcessor.java
  2. protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
  3. Field field = (Field)this.member;//bookDao1
  4. Object value;
  5. if(this.cached) {
  6. value = AutowiredAnnotationBeanPostProcessor.this.resolvedCachedArgument(beanName, this.cachedFieldValue);
  7. } else {
  8. DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
  9. desc.setContainingClass(bean.getClass());
  10. Set<String> autowiredBeanNames = new LinkedHashSet(1);
  11. TypeConverter typeConverter = AutowiredAnnotationBeanPostProcessor.this.beanFactory.getTypeConverter();
  12. try {
  13. value = AutowiredAnnotationBeanPostProcessor.this.beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
  14. } catch (BeansException var12) {
  15. throw new UnsatisfiedDependencyException((String)null, beanName, new InjectionPoint(field), var12);
  16. }
  17. synchronized(this) {
  18. if(!this.cached) {
  19. if(value == null && !this.required) {
  20. this.cachedFieldValue = null;
  21. } else {
  22. this.cachedFieldValue = desc;
  23. AutowiredAnnotationBeanPostProcessor.this.registerDependentBeans(beanName, autowiredBeanNames);
  24. if(autowiredBeanNames.size() == 1) {
  25. String autowiredBeanName = (String)autowiredBeanNames.iterator().next();
  26. if(AutowiredAnnotationBeanPostProcessor.this.beanFactory.containsBean(autowiredBeanName) && AutowiredAnnotationBeanPostProcessor.this.beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
  27. this.cachedFieldValue = new AutowiredAnnotationBeanPostProcessor.ShortcutDependencyDescriptor(desc, autowiredBeanName, field.getType());
  28. }
  29. }
  30. }
  31. this.cached = true;
  32. }
  33. }
  34. }
  35. if(value != null) {
  36. ReflectionUtils.makeAccessible(field);
  37. field.set(bean, value);
  38. }
  39. }
  40. }

 

 

嗯关键的一步是BookDaoImpl怎么找到的,我看看。调试了三个小时终于找到真正得到BookDaoimpl的地方,非常精彩

使用spring特有的通过getBean方法传入beanName和接口类型得到然后放到map中,之后从map中的到key和value

最后实现上面的注册。

直接从注入的缓存中那个通过BeanName得到对象(实现类)

上述的bean当于XML

protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
  1. value = AutowiredAnnotationBeanPostProcessor.this.beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);//这个方法会返回BookDaoimpl
  2. }

意思为:BookDao1字段设置一个BookDaoImpl对象的值,相似代码如下:

流程1读取所有bean,2实例化bean,3为字段设置值

原理总结:就是给BookServeimpl(实现类)中的属性bookDao1注入一个实现类(相当于new对象实例化)

在setter方法注入原理相当于调用method.invoke(bean,value)方法

bean相当于BookServiceImpl对象,值表示BookService类里面BookDao对象的属性

666666666完结撒花

----------------------------------

链接拓展

Spring Import三种用法与源码解读

继续:

我们知道可以通过@import注解导入组件,只能加载类上

(1)注册了蓝组件

还可以通过ImportSelector注入组件和使用ImportBeanDefinitionRegistrar注册

(2)注册了Nimen和Car组件

(3)注册了黄色这个组件

(2),(3)需要使用进口标签

我们知道进口标签是朝春容器中注册组件,春季注册豆是在初始化之前

ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,BeanDefinitionRegistryPostProcessor

继承了BeanFactoryPostProcessor
  1. public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
  2. void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
  3. }

源码分析

  1. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  2. int registryId = System.identityHashCode(registry);
  3. if(this.registriesPostProcessed.contains(Integer.valueOf(registryId))) {
  4. throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
  5. } else if(this.factoriesPostProcessed.contains(Integer.valueOf(registryId))) {
  6. throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
  7. } else {
  8. this.registriesPostProcessed.add(Integer.valueOf(registryId));
  9. this.processConfigBeanDefinitions(registry);
  10. }
  11. }

this.processConfigBeanDefinitions()方法:处理配置配置

ConfigurationClassParser.java解析@import标签

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/524639
推荐阅读
相关标签
  

闽ICP备14008679号