参考:https://fangshixiang.blog.csdn.net/article/details/88765470
ClassMetaData
// @since 2.5
public interface ClassMetadata {
	// 返回类名(注意返回的是最原始的那个className)
	String getClassName();
	boolean isInterface();
	// 是否是注解
	boolean isAnnotation();
	boolean isAbstract();
	// 是否允许创建  不是接口且不是抽象类  这里就返回true了
	boolean isConcrete();
	boolean isFinal();
	// 是否是独立的(能够创建对象的)  比如是Class、或者内部类、静态内部类
	boolean isIndependent();
	// 是否有内部类之类的东东
	boolean hasEnclosingClass();
	@Nullable
	String getEnclosingClassName();
	boolean hasSuperClass();
	@Nullable
	String getSuperClassName();
	// 会把实现的所有接口名称都返回  具体依赖于Class#getSuperclass
	String[] getInterfaceNames();
	// 基于:Class#getDeclaredClasses  返回类中定义的公共、私有、保护的内部类
	String[] getMemberClassNames();
}
MethodsMetadata
// @since 2.1 可以看到它出现得更早一些
public interface MethodsMetadata extends ClassMetadata {
	// 返回该class所有的方法
	Set<MethodMetadata> getMethods();
	// 方法指定方法名的方法们(因为有重载嘛~)
	Set<MethodMetadata> getMethods(String name);
}
AnnotatedTypeMetadata
// @since 4.0
public interface AnnotatedTypeMetadata {
	// 此元素是否标注有此注解~~~~
	// annotationName:注解全类名
	boolean isAnnotated(String annotationName);
	
	// 这个就厉害了:取得指定类型注解的所有的属性 - 值(k-v)
	// annotationName:注解全类名
	// classValuesAsString:若是true表示 Class用它的字符串的全类名来表示。这样可以避免Class被提前加载
	@Nullable
	Map<String, Object> getAnnotationAttributes(String annotationName);
	@Nullable
	Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString);
	// 参见这个方法的含义:AnnotatedElementUtils.getAllAnnotationAttributes
	@Nullable
	MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName);
	@Nullable
	MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString);
}
MethodMetadata
// @since 3.0
public interface MethodMetadata extends AnnotatedTypeMetadata {
	String getMethodName();
	String getDeclaringClassName();
	String getReturnTypeName();
	boolean isAbstract();
	boolean isStatic();
	boolean isFinal();
	boolean isOverridable();
}
AnnotationMetadata
// @since 2.5
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
	//拿到当前类上所有的注解的全类名(注意是全类名)
	Set<String> getAnnotationTypes();
	// 拿到指定的注解类型
	//annotationName:注解类型的全类名
	Set<String> getMetaAnnotationTypes(String annotationName);
	
	// 是否包含指定注解 (annotationName:全类名)
	boolean hasAnnotation(String annotationName);
	//这个厉害了,用于判断注解类型自己是否被某个元注解类型所标注
	//依赖于AnnotatedElementUtils#hasMetaAnnotationTypes
	boolean hasMetaAnnotation(String metaAnnotationName);
	
	// 类里面只有有一个方法标注有指定注解,就返回true
	//getDeclaredMethods获得所有方法, AnnotatedElementUtils.isAnnotated是否标注有指定注解
	boolean hasAnnotatedMethods(String annotationName);
	// 返回所有的标注有指定注解的方法元信息。注意返回的是MethodMetadata 原理基本同上
	Set<MethodMetadata> getAnnotatedMethods(String annotationName);
}
StandardAnnotationMetadata
// @since 2.5
public class StandardAnnotationMetadata extends StandardClassMetadata implements AnnotationMetadata {
	
	// 很显然它是基于标准反射类型:java.lang.annotation.Annotation
	// this.annotations = introspectedClass.getAnnotations()
	private final Annotation[] annotations;
	private final boolean nestedAnnotationsAsMap;
	...
	
	// 获取本Class类上的注解的元注解们
	@Override
	public Set<String> getMetaAnnotationTypes(String annotationName) {
		return (this.annotations.length > 0 ?
				AnnotatedElementUtils.getMetaAnnotationTypes(getIntrospectedClass(), annotationName) : Collections.emptySet());
	}
	@Override
	public boolean hasAnnotation(String annotationName) {
		for (Annotation ann : this.annotations) {
			if (ann.annotationType().getName().equals(annotationName)) {
				return true;
			}
		}
		return false;
	}
	...
}
MetadataReader
// @since 2.5
public interface MetadataReader {
	// 返回此Class文件的来源(资源)
	Resource getResource();
	// 返回此Class的元数据信息
	ClassMetadata getClassMetadata();
	// 返回此类的注解元信息(包括方法的)
	AnnotationMetadata getAnnotationMetadata();
}
SimpleMetadataReader
final class SimpleMetadataReader implements MetadataReader {
	private final Resource resource;
	private final ClassMetadata classMetadata;
	private final AnnotationMetadata annotationMetadata;
	// 唯一构造函数:给上面三个私有属性赋值,下面就只需提供get方法即可
	SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
		InputStream is = new BufferedInputStream(resource.getInputStream());
		ClassReader classReader;
		try {
			classReader = new ClassReader(is);
		} catch (IllegalArgumentException ex) {
			throw new NestedIOException("ASM ClassReader failed to parse class file - " + "probably due to a new Java class file version that isn't supported yet: " + resource, ex);
		} finally {
			is.close();
		}
		//通过流构建出一个AnnotationMetadataReadingVisitor,咀咒读取从而获取到各种信息
		// 它实现了ClassVisitor,所以可以作为入参传给ClassReader ASM去解析
		AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(classLoader);
		classReader.accept(visitor, ClassReader.SKIP_DEBUG);
		this.annotationMetadata = visitor;
		// (since AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor)
		this.classMetadata = visitor;
		this.resource = resource;
	}
	... // 省略三个get方法
}
MethodsMetadataReader
public interface MethodsMetadataReader extends MetadataReader {
	MethodsMetadata getMethodsMetadata();
	...
}
// 它所有的实现都是委托给静态内部类MethodsMetadataReadingVisitor去做的
MetadataReaderFactory
// @since 2.5
public interface MetadataReaderFactory {
	//className: the class name (to be resolved to a ".class" file)
	MetadataReader getMetadataReader(String className) throws IOException;
	MetadataReader getMetadataReader(Resource resource) throws IOException;
}
SimpleMetadataReaderFactory
public class SimpleMetadataReaderFactory implements MetadataReaderFactory {
	// ResourceLoader这个资源加载类应该不陌生了吧
	// 默认使用的是DefaultResourceLoader,当然你可以通过构造器指定
	private final ResourceLoader resourceLoader;
	// 根据类名找到一个Resource
	@Override
	public MetadataReader getMetadataReader(String className) throws IOException {
		try {
			// 把..形式换成//.class形式。使用前缀是:classpath:  在类路径里找哦
			String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
			Resource resource = this.resourceLoader.getResource(resourcePath);
			return getMetadataReader(resource); // 调用重载方法
		} catch (FileNotFoundException ex) {
			// Maybe an inner class name using the dot name syntax? Need to use the dollar syntax here...
			// ClassUtils.forName has an equivalent check for resolution into Class references later on.
			... // 此处是兼容内部类形式,代码略
		}
	}
	// 默认使用的是SimpleMetadataReader哦~~~
	@Override
	public MetadataReader getMetadataReader(Resource resource) throws IOException {
		return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
	}
}
CachingMetadataReaderFactory
它继承自SimpleMetadataReaderFactory,没有其它特殊的,就是提供了缓存能力private Map<Resource, MetadataReader> metadataReaderCache,提高访问效率。
 因为有了它,所以SimpleMetadataReaderFactory就不需要被直接使用了,用它代替。Spring内自然也使用的便是效率更高的它喽~
MethodsMetadataReaderFactory
它继承自SimpleMetadataReaderFactory,唯一区别是它生产的是一个MethodsMetadataReader(DefaultMethodsMetadataReader),从而具有了读取MethodsMetadata的能力。
 此类可认为从没有被Spring内部使用过,暂且可忽略(spring-data工程有用)
Factory工厂的实现都是非常简单的,毕竟只是为了生产一个实例而已。
Spring注解编程中AnnotationMetadata的使用
Spring从3.0开始就大量的使用到了注解编程模式,所以可想而知它对元数据(特别是注解元数据)的使用是非常多的,此处我只给出非常简单的总结。
对于MetadataReaderFactory的应用主要体现在几个地方:
ConfigurationClassPostProcessor
该属性值最终会传给ConfigurationClassParser,用于@EnableXXX / @Import等注解的解析上~
// 私有成员变量,默认使用的CachingMetadataReaderFactory
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
ClassPathScanningCandidateComponentProvider
它用于@ComponentScan的时候解析,拿到元数据判断是否是@Component的派生注解
public final MetadataReaderFactory getMetadataReaderFactory() {
	if (this.metadataReaderFactory == null) {
		this.metadataReaderFactory = new CachingMetadataReaderFactory();
	}
	return this.metadataReaderFactory;
}
Mybatis的SqlSessionFactoryBean
它在使用上非常简单,只是为了从Resouece里拿到ClassName而已。classMetadata.getClassName()
private static final MetadataReaderFactory METADATA_READER_FACTORY = new CachingMetadataReaderFactory();
private Set<Class<?>> scanClasses(String packagePatterns, Class<?> assignableType) {
		...
          ClassMetadata classMetadata = METADATA_READER_FACTORY.getMetadataReader(resource).getClassMetadata();
          Class<?> clazz = Resources.classForName(classMetadata.getClassName());
		...
}
SourceClass
它是对source对象一个轻量级的包装,持有AnnotationMetadata 元数据,如下一般实际为一个StandardAnnotationMetadata,比如@EnableTransactionManagement用的就是它
	private class SourceClass implements Ordered {
		private final Object source;  // Class or MetadataReader
		private final AnnotationMetadata metadata;
		public SourceClass(Object source) {
			this.source = source;
			if (source instanceof Class) {
				this.metadata = new StandardAnnotationMetadata((Class<?>) source, true);
			} else {
				this.metadata = ((MetadataReader) source).getAnnotationMetadata();
			}
		}
	}
说明:Spring的@EnableXXX模块注解很多都使用到了ImportSelector这个接口,此接口的回调方法参数第一个便是AnnotationMetadata代表着@Import所在类的注解的一些元数据们。通常我们会这样使用它:
// 1、转换成AnnotationAttributes(LinkedHashMap),模糊掉注解类型(常用)
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
// 2、拿到指定类型注解的元数据信息(也较为常用)
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true))
// 3、直接使用MetaData
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(EnableConfigurationProperties.class.getName(), false);
使用示例
ClassMetadata&AnnotatedTypeMetadata&AnnotationMetadata
// 准备一个Class类 作为Demo演示
@Repository("repositoryName")
@Service("serviceName")
@EnableAsync
class MetaDemo extends HashMap<String, String> implements Serializable {
    private static class InnerClass {
    }
    @Autowired
    private String getName() {
        return "demo";
    }
}
public static void main(String[] args) {
    StandardAnnotationMetadata metadata = new StandardAnnotationMetadata(MetaDemo.class, true);
    // 演示ClassMetadata的效果
    System.out.println("==============ClassMetadata==============");
    ClassMetadata classMetadata = metadata;
    System.out.println(classMetadata.getClassName()); //com.fsx.maintest.MetaDemo
    System.out.println(classMetadata.getEnclosingClassName()); //null  如果自己是内部类此处就有值了
    System.out.println(StringUtils.arrayToCommaDelimitedString(classMetadata.getMemberClassNames())); //com.fsx.maintest.MetaDemo$InnerClass 若木有内部类返回空数组[]
    System.out.println(StringUtils.arrayToCommaDelimitedString(classMetadata.getInterfaceNames())); // java.io.Serializable
    System.out.println(classMetadata.hasSuperClass()); // true(只有Object这里是false)
    System.out.println(classMetadata.getSuperClassName()); // java.util.HashMap
    System.out.println(classMetadata.isAnnotation()); // false(是否是注解类型的Class,这里显然是false)
    System.out.println(classMetadata.isFinal()); // false
    System.out.println(classMetadata.isIndependent()); // true(top class或者static inner class,就是独立可new的)
    // 演示AnnotatedTypeMetadata的效果
    System.out.println("==============AnnotatedTypeMetadata==============");
    AnnotatedTypeMetadata annotatedTypeMetadata = metadata;
    System.out.println(annotatedTypeMetadata.isAnnotated(Service.class.getName())); // true(依赖的AnnotatedElementUtils.isAnnotated这个方法)
    System.out.println(annotatedTypeMetadata.isAnnotated(Component.class.getName())); // true
    System.out.println(annotatedTypeMetadata.getAnnotationAttributes(Service.class.getName())); //{value=serviceName}
    System.out.println(annotatedTypeMetadata.getAnnotationAttributes(Component.class.getName())); // {value=repositoryName}(@Repository的value值覆盖了@Service的)
    System.out.println(annotatedTypeMetadata.getAnnotationAttributes(EnableAsync.class.getName())); // {order=2147483647, annotation=interface java.lang.annotation.Annotation, proxyTargetClass=false, mode=PROXY}
    // 看看getAll的区别:value都是数组的形式
    System.out.println(annotatedTypeMetadata.getAllAnnotationAttributes(Service.class.getName())); // {value=[serviceName]}
    System.out.println(annotatedTypeMetadata.getAllAnnotationAttributes(Component.class.getName())); // {value=[, ]} --> 两个Component的value值都拿到了,只是都是空串而已
    System.out.println(annotatedTypeMetadata.getAllAnnotationAttributes(EnableAsync.class.getName())); //{order=[2147483647], annotation=[interface java.lang.annotation.Annotation], proxyTargetClass=[false], mode=[PROXY]}
    // 演示AnnotationMetadata子接口的效果(重要)
    System.out.println("==============AnnotationMetadata==============");
    AnnotationMetadata annotationMetadata = metadata;
    System.out.println(annotationMetadata.getAnnotationTypes()); // [org.springframework.stereotype.Repository, org.springframework.stereotype.Service, org.springframework.scheduling.annotation.EnableAsync]
    System.out.println(annotationMetadata.getMetaAnnotationTypes(Service.class.getName())); // [org.springframework.stereotype.Component, org.springframework.stereotype.Indexed]
    System.out.println(annotationMetadata.getMetaAnnotationTypes(Component.class.getName())); // [](meta就是获取注解上面的注解,会排除掉java.lang这些注解们)
    System.out.println(annotationMetadata.hasAnnotation(Service.class.getName())); // true
    System.out.println(annotationMetadata.hasAnnotation(Component.class.getName())); // false(注意这里返回的是false)
    System.out.println(annotationMetadata.hasMetaAnnotation(Service.class.getName())); // false(注意这一组的结果和上面相反,因为它看的是meta)
    System.out.println(annotationMetadata.hasMetaAnnotation(Component.class.getName())); // true
    System.out.println(annotationMetadata.hasAnnotatedMethods(Autowired.class.getName())); // true
    annotationMetadata.getAnnotatedMethods(Autowired.class.getName()).forEach(methodMetadata -> {
        System.out.println(methodMetadata.getClass()); // class org.springframework.core.type.StandardMethodMetadata
        System.out.println(methodMetadata.getMethodName()); // getName
        System.out.println(methodMetadata.getReturnTypeName()); // java.lang.String
    });
}
MetadataReaderFactory->MetadataReader->AnnotationMetadata
public static void main(String[] args) throws IOException {
    CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
    // 下面两种初始化方式都可,效果一样
    //MetadataReader metadataReader = readerFactory.getMetadataReader(MetaDemo.class.getName());
    MetadataReader metadataReader = readerFactory.getMetadataReader(new ClassPathResource("com/fsx/maintest/MetaDemo.class"));
    ClassMetadata classMetadata = metadataReader.getClassMetadata();
    AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
    Resource resource = metadataReader.getResource();
    System.out.println(classMetadata); // org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor@79079097
    System.out.println(annotationMetadata); // org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor@79079097
    System.out.println(resource); // class path resource [com/fsx/maintest/MetaDemo.class]
}
Spring扫描包的大致逻辑
public class ScanTest {
    @Test
    public void test_01() throws IOException {
        // 详细的扫包逻辑可参见:ClassPathScanningCandidateComponentProvider,
        // 里面有扩展出TypeFilter接口,过来排除(excludeFilters)、匹配(includeFilters)、条件(conditionEvaluator.shouldSkip(metaReader))(先排除,再匹配,最后看条件是否满足)
        PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resourcePatternResolver.getResources("classpath*:com/zzhua/test/"+"**/*.class");
        CachingMetadataReaderFactory metaDataReaderFactory = new CachingMetadataReaderFactory();
        for (Resource resource : resources) {
            MetadataReader metadataReader = metaDataReaderFactory.getMetadataReader(resource);
            AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
            System.out.println(annotationMetadata.isAnnotated(Component.class.getName()) + "->"
                    + metadataReader.getClassMetadata().getClassName());
        }
 /*
输出:
	false->com.zzhua.test.CommaTest
	true->com.zzhua.test.Hat
	true->com.zzhua.test.Person
	false->com.zzhua.test.Weapon
*/
    }
	@Test
    public void test_02() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // ClassPathBeanDefinitionScanner有个配置问要不要注册注解配置相关的后置处理器,默认true,       
        // 就会调用:AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        // 所以后面有另外几个beanDefinition
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
        scanner.addExcludeFilter( // 不处理Controller注解的bd
                (metadataReader,metadataReaderFactory)->
                    metadataReader.getAnnotationMetadata()
                    .isAnnotated(Controller.class.getName())
        );
        int size = scanner.scan("com.zzhua.test");
        System.out.println(size);
        Stream.of(beanFactory.getBeanDefinitionNames()).forEach(System.out::println);
    }
/*
输出:
	8
	hat
	person
	org.springframework.context.annotation.internalConfigurationAnnotationProcessor
	org.springframework.context.annotation.internalAutowiredAnnotationProcessor
	org.springframework.context.annotation.internalRequiredAnnotationProcessor
	org.springframework.context.annotation.internalCommonAnnotationProcessor
	org.springframework.context.event.internalEventListenerProcessor
	org.springframework.context.event.internalEventListenerFactory
*/
	
}
ConfigurationClassUtils
/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.context.annotation;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.core.Conventions;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
/**
 * Utilities for processing @{@link Configuration} classes.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 */
abstract class ConfigurationClassUtils {
	private static final String CONFIGURATION_CLASS_FULL = "full";
	private static final String CONFIGURATION_CLASS_LITE = "lite";
	private static final String CONFIGURATION_CLASS_ATTRIBUTE =
			Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
	private static final String ORDER_ATTRIBUTE =
			Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "order");
	private static final Log logger = LogFactory.getLog(ConfigurationClassUtils.class);
	private static final Set<String> candidateIndicators = new HashSet<String>(4);
	static {
		candidateIndicators.add(Component.class.getName());
		candidateIndicators.add(ComponentScan.class.getName());
		candidateIndicators.add(Import.class.getName());
		candidateIndicators.add(ImportResource.class.getName());
	}
	/**
	 * Check whether the given bean definition is a candidate for a configuration class
	 * (or a nested component class declared within a configuration/component class,
	 * to be auto-registered as well), and mark it accordingly.
	 * @param beanDef the bean definition to check
	 * @param metadataReaderFactory the current factory in use by the caller
	 * @return whether the candidate qualifies as (any kind of) configuration class
	 */
	public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
		String className = beanDef.getBeanClassName();
		if (className == null || beanDef.getFactoryMethodName() != null) {
			return false;
		}
		AnnotationMetadata metadata;
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
			// Can reuse the pre-parsed metadata from the given BeanDefinition...
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			// Check already loaded Class if present...
			// since we possibly can't even load the class file for this Class.
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			metadata = new StandardAnnotationMetadata(beanClass, true);
		}
		else {
			try {
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				metadata = metadataReader.getAnnotationMetadata();
			}
			catch (IOException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Could not find class file for introspecting configuration annotations: " + className, ex);
				}
				return false;
			}
		}
		if (isFullConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		else if (isLiteConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			return false;
		}
		// It's a full or lite configuration candidate... Let's determine the order value, if any.
		Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
		if (orderAttributes != null) {
			beanDef.setAttribute(ORDER_ATTRIBUTE, orderAttributes.get(AnnotationUtils.VALUE));
		}
		return true;
	}
	/**
	 * Check the given metadata for a configuration class candidate
	 * (or nested component class declared within a configuration/component class).
	 * @param metadata the metadata of the annotated class
	 * @return {@code true} if the given class is to be registered as a
	 * reflection-detected bean definition; {@code false} otherwise
	 */
	public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
		return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
	}
	/**
	 * Check the given metadata for a full configuration class candidate
	 * (i.e. a class annotated with {@code @Configuration}).
	 * @param metadata the metadata of the annotated class
	 * @return {@code true} if the given class is to be processed as a full
	 * configuration class, including cross-method call interception
	 */
	public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
		return metadata.isAnnotated(Configuration.class.getName());
	}
	/**
	 * Check the given metadata for a lite configuration class candidate
	 * (e.g. a class annotated with {@code @Component} or just having
	 * {@code @Import} declarations or {@code @Bean methods}).
	 * @param metadata the metadata of the annotated class
	 * @return {@code true} if the given class is to be processed as a lite
	 * configuration class, just registering it and scanning it for {@code @Bean} methods
	 */
	public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
		// Do not consider an interface or an annotation...
		if (metadata.isInterface()) {
			return false;
		}
		// Any of the typical annotations found?
		for (String indicator : candidateIndicators) {
			if (metadata.isAnnotated(indicator)) {
				return true;
			}
		}
		// Finally, let's look for @Bean methods...
		try {
			return metadata.hasAnnotatedMethods(Bean.class.getName());
		}
		catch (Throwable ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
			}
			return false;
		}
	}
	/**
	 * Determine whether the given bean definition indicates a full {@code @Configuration}
	 * class, through checking {@link #checkConfigurationClassCandidate}'s metadata marker.
	 */
	public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
		return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
	}
	/**
	 * Determine whether the given bean definition indicates a lite {@code @Configuration}
	 * class, through checking {@link #checkConfigurationClassCandidate}'s metadata marker.
	 */
	public static boolean isLiteConfigurationClass(BeanDefinition beanDef) {
		return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
	}
	/**
	 * Determine the order for the given configuration class bean definition,
	 * as set by {@link #checkConfigurationClassCandidate}.
	 * @param beanDef the bean definition to check
	 * @return the {@link @Order} annotation value on the configuration class,
	 * or {@link Ordered#LOWEST_PRECEDENCE} if none declared
	 * @since 4.2
	 */
	public static int getOrder(BeanDefinition beanDef) {
		Integer order = (Integer) beanDef.getAttribute(ORDER_ATTRIBUTE);
		return (order != null ? order : Ordered.LOWEST_PRECEDENCE);
	}
}
实现mybatis扫包大致逻辑
@Dao
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Target(ElementType.TYPE)
public @interface Dao {
    String value() default "";
}
EnableDao
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyDaoRegistrar.class)
public @interface EnableDao {
    String value();
}
MyDaoRegistrar
public class MyDaoRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata anoMetaData, BeanDefinitionRegistry registry) {
        Map<String, Object> attrs = anoMetaData.getAnnotationAttributes(EnableDao.class.getName());
        Object value = attrs.get("value");
        Assert.notNull(value, "value can't be null");
        DaoScanner daoScanner = new DaoScanner(registry);
        daoScanner.setBeanNameGenerator(new MyDaoBeanNameGenerator());
        daoScanner.addIncludeFilter((a,b)->true);
        Set<BeanDefinitionHolder> bdfs = daoScanner.doScan(value.toString());
        for (BeanDefinitionHolder bdh : bdfs) {
            ScannedGenericBeanDefinition sbd = (ScannedGenericBeanDefinition) bdh.getBeanDefinition();
            String rawClassName = sbd.getBeanClassName();
            sbd.setBeanClass(DaoFactoryBean.class);
            AnnotationMetadata metadata = sbd.getMetadata();
            try {
                sbd.getConstructorArgumentValues().addGenericArgumentValue(Class.forName(rawClassName));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
}
DaoScanner
public class DaoScanner extends ClassPathBeanDefinitionScanner {
    public DaoScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        return super.doScan(basePackages);
    }
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isAnnotated(Dao.class.getName());
    }
}
DaoFactoryBean
public class DaoFactoryBean<T> implements FactoryBean {
    private Class<T> intf;
    public DaoFactoryBean(Class<T> intf) {
        Assert.notNull(intf,"intf can't be null");
        Assert.isTrue(intf.isInterface(),"intf must be defined as a interface");
        this.intf = intf;
    }
    @Override
    public  T getObject() {
        // 返回接口实例
        return (T) Proxy.newProxyInstance(DaoFactoryBean.class.getClassLoader(), new Class[]{intf},
            (proxy, method, args) -> {
                // 这里可置入sqlSession来作查询(mybatis-spring中为实现事务同步有作特别处理),这里仅简单构造返回
                Constructor<?> cons = method.getReturnType().getConstructor();
                return cons.newInstance();
            }
        );
    }
    @Override
    public Class<?> getObjectType() {
        return intf;
    }
    @Override
    public boolean isSingleton() {
        return true;
    }
}
MyDaoBeanNameGenerator
public class MyDaoBeanNameGenerator extends AnnotationBeanNameGenerator {
    protected boolean isStereotypeWithNameValue(String annotationType,
                                                Set<String> metaAnnotationTypes, @Nullable Map<String, Object> attributes){
        return super.isStereotypeWithNameValue(annotationType, metaAnnotationTypes, attributes) || Dao.class.getName().equals(annotationType);
    }
}
EmployeeDao
@Dao("myEmpDao")
public interface EmployeeDao {
    Employee getEmpById(Integer id);
}
DaoConfig
@EnableDao("com.zzhua.mapper")
@Configuration
public class DaoConfig {
}
测试
@Test
public void test_04() {
     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DaoConfig.class);
     EmployeeMapper empMapper = (EmployeeMapper) context.getBean("myEmpDao");
     Employee emp = empMapper.getEmpById(1);
     System.out.println(emp);
     // 输出:Employee(id=null, lastName=null, email=null, gender=null, hireDate=null)
 }










