• Spring源码分析之@Component注解自动扫描的处理


    前言

    在项目中使用Spring,我们都会使用它的自动扫描Bean的功能,今天就来分析一下自动扫描的原理。

    简单使用

    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
    import org.springframework.stereotype.Component;
    import org.springframework.util.ClassUtils;
    
    public class TestComponentScan {
    
      public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(
            beanFactory, true);
        String packageName = ClassUtils.getPackageName(TestComponentScan.class);
        scanner.scan(packageName);
        UserService userService = (UserService) beanFactory.getBean("userService");
        userService.users();
      }
    
      @Component("userService")
      public static class UserService {
    
        public void users() {
          System.out.println("UserService.users()");
        }
      }
    }
    

    使用ClassPathBeanDefinitionScanner(扫描器)来扫描指定package下的Bean,默认会扫描包含@Component注解的Class。
    根据扫描到的Class创建BeanDefinition,并注册到BeanFactory中。我们也可以自定义要扫描的条件,如扫描指定的接口的实现类。

    import java.util.Map;
    import java.util.Map.Entry;
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
    import org.springframework.core.type.classreading.MetadataReader;
    import org.springframework.core.type.classreading.MetadataReaderFactory;
    import org.springframework.core.type.filter.TypeFilter;
    import org.springframework.util.ClassUtils;
    
    public class TestComponentScan2 {
    
      public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(
            beanFactory, true);
        //扫描类型为IService的Class
        scanner.addIncludeFilter(new ClassTypeFilter(IService.class));
        String packageName = ClassUtils.getPackageName(TestComponentScan2.class);
        scanner.scan(packageName);
        Map<String, IService> iServiceMap = beanFactory.getBeansOfType(IService.class);
        for (Entry<String, IService> entry : iServiceMap.entrySet()) {
          System.out.println(entry);
        }
      }
    
      public static class ClassTypeFilter implements TypeFilter {
    
        private Class<?> targetType;
    
        public ClassTypeFilter(Class<?> targetType) {
          this.targetType = targetType;
        }
    
        @Override
        public boolean match(MetadataReader metadataReader,
            MetadataReaderFactory metadataReaderFactory) {
          try {
            //获取Class
            Class<?> aClass = ClassUtils
                .forName(metadataReader.getClassMetadata().getClassName(),
                    ClassUtils.getDefaultClassLoader());
            return !metadataReader.getClassMetadata().isInterface() &&
                targetType.isAssignableFrom(aClass);
          } catch (ClassNotFoundException e) {
            e.printStackTrace();
          }
          return false;
        }
      }
    
      public interface IService {
    
      }
    
      public static class AddressService {
    
      }
    
      public static class UserService implements IService {
    
        public void users() {
          System.out.println("UserService.users()");
        }
      }
    }
    

    扫描接口IService的实现类,只有UserService,不包含AddressService。SpringDataJPA就是通过这种方式来扫描Repository接口的。

    源码分析

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
    			Environment environment, @Nullable ResourceLoader resourceLoader) {
    		this.registry = registry;
                    //注册默认类型过滤器,过滤@Component注解
    		if (useDefaultFilters) {
    			registerDefaultFilters();
    		}
    		setEnvironment(environment);
    		setResourceLoader(resourceLoader);
    	}
    

    开始扫描

    public int scan(String... basePackages) {
    		int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
                    //实际扫描
    		doScan(basePackages);
    		//注册一些处理注解相关的BeanPostProcessor
    		if (this.includeAnnotationConfig) {
    			AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    		}
    		return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    	}
    

    查看自动注册了哪些BeanPostProcessor

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    			BeanDefinitionRegistry registry, @Nullable Object source) {
                    //获取DefaultListableBeanFactory,这个例子中registry的实际类型就是DefaultListableBeanFactory
                    //如果我们是在ApplicationContext中调用此方法,registry的类型就是ApplicationContext的具体实现类
    		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    		if (beanFactory != null) {
    			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
    				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
    			}
    			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                                    //处理@Value注解的属性注入
    				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
    			}
    		}
    
    		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
    
    		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                            //处理@Configuration注解,@ComponentScan注解,@Bean注解等
    			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    		}
    
    		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                            //处理@Autowired注解的属性注入
    			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    		}
    
    		////支持@PostConstruct(Bean初始化)和@PreDestroy(Bean销毁)
    		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                            
    			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    		}
    
    		//处理JPA相关注解
    		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition();
    			try {
    				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
    						AnnotationConfigUtils.class.getClassLoader()));
    			}
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    		}
                    //处理@EventListener注解相关
    		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    		}
                    //也是事件监听相关,暂时不管
    		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    		}
    
    		return beanDefs;
    	}
    

    真正扫描的过程

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    		//保存扫描到的所有BeanDefinition
    		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    		for (String basePackage : basePackages) {
                            //扫描指定package下的所有class,根据类型过滤器过滤,根据Class创建BeanDefinition
    			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    			for (BeanDefinition candidate : candidates) {
                                    //处理@Scope注解相关
    				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
    				candidate.setScope(scopeMetadata.getScopeName());
    				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    				if (candidate instanceof AbstractBeanDefinition) {
    					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    				}
    				if (candidate instanceof AnnotatedBeanDefinition) {
                                            //处理@Primary注解,@Lazy注解(是否懒加载)等
    					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
    				}
    				if (checkCandidate(beanName, candidate)) {
    					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                                            //@Scope注解可以配置对当前Bean是否创建动态代理
    					definitionHolder =
    							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    					beanDefinitions.add(definitionHolder);
                                            //将BeanDefinition注册到BeanFactory中
    					registerBeanDefinition(definitionHolder, this.registry);
    				}
    			}
    		}
    		return beanDefinitions;
    	}
    

    继续跟进去findCandidateComponents()方法

    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
                    //componentsIndex不知道是什么情况下使用,暂时不管
    		if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
    			return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    		}
    		else {
                            //真正扫描Class
    			return scanCandidateComponents(basePackage);
    		}
    	}
    

    继续scanCandidateComponents()方法

    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    		Set<BeanDefinition> candidates = new LinkedHashSet<>();
    		try {
                            //使用PathMatchingResourcePatternResolver(支持通配符)从classpath下查找所有class文件
    			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
    					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
                            //实际的查找路径为classpath*:xx/**/*.class
    			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
    			for (Resource resource : resources) {
    				if (resource.isReadable()) {
    					try {
    						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                                                    //根据类型过滤器判断,如我们自己定义的ClassTypeFilter,其实这里还会根据@Conditional注解来判断,但先不管
    						if (isCandidateComponent(metadataReader)) {
                                                            //创建BeanDefinition
    							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
    							sbd.setResource(resource);
    							sbd.setSource(resource);
                                                            //当前Class必须是独立的(非内部类,或者是静态内部类)
    							if (isCandidateComponent(sbd)) {
    								candidates.add(sbd);
    							}
    						}
    					}
    				}
    			}
    		}
    		return candidates;
    	}
    

    至此就扫描完了,总结起来就是查找到所有的class,根据类型过滤器来过滤,根据class创建BeanDefinition并注册到BeanFactory(实际上是BeanDefinitionRegistry类型)中。

    Spring中的使用

    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan
    public class BeanConfig {
    }
    

    我们使用Spring或者SpringBoot的时候,都是通过@ComponentScan注解来开启扫描的,不需要手动创建ClassPathBeanDefinitionScanner对象且调用scan()方法。

    总结

    @Controller注解,@Service,@Repository,这三个注解都是被@Component注解所标记的,Spring也会扫描到。

  • 相关阅读:
    2018第九届蓝桥杯C/C++ B国赛 —— 第三题:格雷码
    数据结构和算法 —— 谈谈算法
    数据结构和算法 —— 谈谈算法
    数据结构和算法 —— 绪论
    数据结构和算法 —— 绪论
    2018第九届蓝桥杯C/C++ B国赛 —— 第二题:激光样式
    2018第九届蓝桥杯C/C++ B国赛 —— 第二题:激光样式
    2018第九届蓝桥杯C/C++ B国赛 —— 第一题:换零钞
    围棋
    恶搞造句
  • 原文地址:https://www.cnblogs.com/strongmore/p/16229542.html
Copyright © 2020-2023  润新知