1.1、Spring核心组件之MetadataReader

在Spring框架中,类路径扫描和BeanDefinition解析是一个核心流程。为了高效地管理资源,Spring不会将扫描路径下的所有类直接加载到JVM内存中,而是采用了基于字节码分析的技术来实现这一过程。具体来说,Spring利用ASM(字节码 manipulator)技术,直接解析Class文件的字节码,提取所需的元数据信息。
这种设计理念有两个关键优势:

  • 避免了不必要的类加载操作,减少了内存占用;
  • 能够以更高效的方式获取注解信息和接口实现,而无需将完整的类加载到JVM中。

通过这种方式,Spring能够在类加载阶段就筛选出需要注册为Bean的类,从而优化了资源使用效率,既保证了功能的灵活性,又实现了对系统资源的有效管理。

MetaDataReader

MetadataReader是一个接口,它主要定义了三个方法

  1. getResource()
  2. getClassMetadata()
  3. getAnnotationMetadata()

Spring在扫描解析类时,会通过ASM解析并生成MetadataReader的实现类SimpleMetadataReader,而AnnotationMetadata是继承自ClassMetadata的接口,因此通过SimpleMetadataReadergetClassMetadata()getAnnotationMetadata()返回的其实都是AnnotationMetadata对象

final class SimpleMetadataReader implements MetadataReader {

	private static final int PARSING_OPTIONS =
			(ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES);

	private final Resource resource;

	private final AnnotationMetadata annotationMetadata;


	SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
		SimpleAnnotationMetadataReadingVisitor visitor = new SimpleAnnotationMetadataReadingVisitor(classLoader);
		// 这里通过classReader读取resource对应的文件,然后将信息存入visitor中
		getClassReader(resource).accept(visitor, PARSING_OPTIONS);
		this.resource = resource;
		this.annotationMetadata = visitor.getMetadata();
	}

	private static ClassReader getClassReader(Resource resource) throws IOException {
		try (InputStream is = resource.getInputStream()) {
			try {
				return new ClassReader(is);
			}
			catch (IllegalArgumentException ex) {
				throw new ClassFormatException("ASM ClassReader failed to parse class file - " +
						"probably due to a new Java class file version that is not supported yet. " +
						"Consider compiling with a lower '-target' or upgrade your framework version. " +
						"Affected class: " + resource, ex);
			}
		}
	}


	@Override
	public Resource getResource() {
		return this.resource;
	}

	@Override
	public ClassMetadata getClassMetadata() {
		return this.annotationMetadata;
	}

	@Override
	public AnnotationMetadata getAnnotationMetadata() {
		return this.annotationMetadata;
	}

}

ClassMetadata

ClassMetadata主要存储类相关的信息,包括类名,父类名,实现了那些接口的接口名等。具体例子如下

public static void main(String[] args) throws IOException {
        SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.ww.Order");
    
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        // 类名
        String className = classMetadata.getClassName();
        // 实现了那些接口
        String[] interfaceNames = classMetadata.getInterfaceNames();
    
        System.out.println(className);
        System.out.println(interfaceNames[0]);

		// 用SimpleMetadataReaderFactory的类加载器,验证JVM没有加载Order类
		// 使用ClassLoader的findLoadedClass方法,如果jvm加载过类了,该方法将返回类的class对象,没加载过则返回null
		ClassLoader classLoader = SimpleMetadataReaderFactory.class.getClassLoader();
		Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
		findLoadedClass.setAccessible(true);
		System.out.println(findLoadedClass.invoke(classLoader, className) != null);
}
@Service
public class Order implements PriorityOrdered {

	@Value("李四")
	private User user;

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public void print() {
		System.out.println(user.getName());
	}

	@Override
	public int getOrder() {
		return 10;
	}

	@Component
	@Scope(BeanDefinition.SCOPE_PROTOTYPE)
	public class Good{
		private String goodName;

		public String getGoodName() {
			return goodName;
		}

		public void setGoodName(String goodName) {
			this.goodName = goodName;
		}
	}
}

可以看到分别获取到了类名和实现的接口名,同时findLoadedClass方法返回的是null,表示没有加载Order类

AnnotationMetadata

AnnotationMetadata接口,主要保存的是类上注解的相关信息,同时,因为它继承自ClassLoader,因此也有ClassLoader对应的方法。

这里Order类还是上面的类,注意一下Order类上的注解是@Service

	public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
		SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
		MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.ww.Order");

//		ClassMetadata classMetadata = metadataReader.getClassMetadata();
//		// 类名
//		String className = classMetadata.getClassName();
//		// 实现了那些接口
//		String[] interfaceNames = classMetadata.getInterfaceNames();
//
//		System.out.println(className);
//		System.out.println(interfaceNames[0]);
//		// 验证JVM没有加载Order类
//		// 使用ClassLoader的findLoadedClass方法,如果jvm加载过类了,该方法将返回类的class对象,没加载过则返回null
//		ClassLoader classLoader = SimpleMetadataReaderFactory.class.getClassLoader();
//		Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
//		findLoadedClass.setAccessible(true);
//		System.out.println(findLoadedClass.invoke(classLoader, className) != null);
//
//		System.out.println("===========");

		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		System.out.println(annotationMetadata.getClassName());
		System.out.println(annotationMetadata.hasMetaAnnotation(Component.class.getName()));
		System.out.println(annotationMetadata.hasAnnotation(Component.class.getName()));


	}

这里同样能获取类的名字以及是否存在某个注解

hasMetaAnnotation(String metaAnnotationName)方法

hasMetaAnnotation(String metaAnnotationName)方法,主要检查类上注解的元信息中是否存在给定的metaAnnotationName名字的注解。比如现在Order类上的@Service注解中,就包括了@Component注解。因此这个方法这里返回的true

hasAnnotation(String annotationName)方法

hasAnnotation(String annotationName)方法,主要检查类上是否有给定的annotationName名字的注解,这里Order类上是@Service注解,当然不是@Component注解,因此返回的false。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值