AnnotationMetaData&mybatis-spring扫描包逻辑

参考:https://fangshixiang.blog.csdn.net/article/details/88765470、https://blog.csdn.net/weixin_42189048/article/details/108288213

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);

	/*上面hasAnnotation与hasM*/
	
	// 类里面只有有一个方法标注有指定注解,就返回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

MetadataReader 接口抽象元数据的读取,其实现基于 ASM 直接扫描对应文件字节码实现

// @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)

 }e'mem
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值