Spring:EnclosingClass工具类分辨

Spring:EnclosingClass工具类分辨

1 前言

通过Spring的工具分辨EnclosingClass类。

测试类如下:

package com.xiaoxu.test.enclosingClass;/*** @author xiaoxu* @date 2024-01-18* java_demo2:com.xiaoxu.test.enclosingClass.Outter*/
public class Outter {public static class Inner{}public class Jug{}private static class Real{}private class Fal{}interface Apple{}private static interface Apple2{}private interface Apple3{}}

测试demo:

package com.xiaoxu.test.enclosingClass;import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;/*** @author xiaoxu* @date 2024-01-18* java_demo2:com.xiaoxu.test.enclosingClass.TestEnclosingClass*/
public class TestEnclosingClass {public static void main(String[] args) throws Exception {System.out.println(Outter.class.getEnclosingClass());System.out.println(Outter.Inner.class.getEnclosingClass());System.out.println(Outter.Jug.class.getEnclosingClass());System.out.println(Outter.class.isMemberClass());System.out.println(Outter.Inner.class.isMemberClass());System.out.println(Outter.Jug.class.isMemberClass());PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();Resource[] resources = pathMatchingResourcePatternResolver.getResources("classpath*:com/xiaoxu/test/enclosingClass/*.class");for (Resource resource : resources) {System.out.println(resource);if(resource.isReadable()) {System.out.println("哈哈");MetadataReader metadataReader = new CachingMetadataReaderFactory().getMetadataReader(resource);System.out.println(metadataReader);AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();System.out.println(annotationMetadata.getEnclosingClassName());System.out.println(annotationMetadata.getClassName());System.out.println(annotationMetadata.isIndependent());System.out.println("----------------------------------------------------------\n");}}}}

Spring-core的MetadataReader,是通过字节码分析一个类的,其中如果是内部类(或者内部接口),那么就有EnclosingClassName的属性。

上面调用的是Spring-core的SimpleAnnotationMetadata的isIndependent方法,independent意即独立的:

如果是内部类,那么只有静态内部类isIndependent才返回true,无论公私有类,非静态的内部类有EnclosingClassName属性,即上述定义的Outter类,但是isIndependent为false。

因为内部类接口,默认就是static的,所以内部接口,即便有EnclosingClassName属性,但isIndependent依然返回true。

@Override
public boolean isIndependent() {return (this.enclosingClassName == null || this.independentInnerClass);
}

执行结果:

null
class com.xiaoxu.test.enclosingClass.Outter
class com.xiaoxu.test.enclosingClass.Outter
false
true
true
file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Apple.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@725bef66
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Apple
true
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Apple2.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@2aaf7cc2
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Apple2
true
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Apple3.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@6e3c1e69
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Apple3
true
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Fal.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@d7b1517
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Fal
false
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Inner.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@16c0663d
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Inner
true
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Jug.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@23223dd8
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Jug
false
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Real.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@4ec6a292
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Real
true
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@1b40d5f0
null
com.xiaoxu.test.enclosingClass.Outter
true
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\TestEnclosingClass.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@ea4a92b
null
com.xiaoxu.test.enclosingClass.TestEnclosingClass
true
----------------------------------------------------------

mybatis的自动配置扫描逻辑,判断@Mapper注解标注的必须是接口,同时isIndependent必须返回true,也就是说只有@Mapper注解标注的接口或者@Mapper注解标注的内部接口,才会被mybatis扫描到。

如果静态内部类被注册为ScannedGenerciBeanDefinition(上面工具类演示了Spring可以读取到内部类或内部接口的.Class文件),那么BeanDefinitionMap的key如下:

package com.xiaoxu.test.enclosingClass;import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;/*** @author xiaoxu* @date 2024-01-18* java_demo2:com.xiaoxu.test.enclosingClass.TestEnclosingClass*/
public class TestEnclosingClass {public static void main(String[] args) throws Exception {System.out.println(Outter.class.getEnclosingClass());System.out.println(Outter.Inner.class.getEnclosingClass());System.out.println(Outter.Jug.class.getEnclosingClass());System.out.println(Outter.class.isMemberClass());System.out.println(Outter.Inner.class.isMemberClass());System.out.println(Outter.Jug.class.isMemberClass());PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();Resource[] resources = pathMatchingResourcePatternResolver.getResources("classpath*:com/xiaoxu/test/enclosingClass/*.class");for (Resource resource : resources) {System.out.println(resource);if(resource.isReadable()) {System.out.println("哈哈");MetadataReader metadataReader = new CachingMetadataReaderFactory().getMetadataReader(resource);System.out.println(metadataReader);AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();System.out.println(annotationMetadata.getEnclosingClassName());System.out.println(annotationMetadata.getClassName());System.out.println(annotationMetadata.isIndependent());// annotationMetadata.isIndependent() && annotationMetadata.isConcrete() 判断必须是具体实现类,并且是静态内部类或者外部类// annotationMetadata.getEnclosingClassName()!=null 排除掉外部类,只保留静态内部类if(annotationMetadata.isIndependent() && annotationMetadata.isConcrete() && annotationMetadata.getEnclosingClassName()!=null){System.out.println((char) 46);System.out.println("我是静态内部类");String enclosingClassName = annotationMetadata.getEnclosingClassName();String outterClassName = enclosingClassName.substring(enclosingClassName.lastIndexOf((char) 46) + 1);//从Spring的BeanFactory中的beanDefinitionMap中获取BeanDefinition时,静态内部类的 BeanDefinition名称//是外部类的类名(非全限定类名)  + "." + 静态内部类的类名(非全限定类名)String staticClassName = annotationMetadata.getClassName();// (int) '$'值为 36  (int) '.'值为46String innerClassName = staticClassName.substring(staticClassName.lastIndexOf((char) 36) + 1);System.out.println((int) '$');System.out.println("我是内部类的ScannedGenericBeanDefinition的名称:" + outterClassName + "." + innerClassName);}System.out.println("----------------------------------------------------------\n");}}}}

执行结果如下:

null
class com.xiaoxu.test.enclosingClass.Outter
class com.xiaoxu.test.enclosingClass.Outter
false
true
true
file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Apple.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@725bef66
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Apple
true
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Apple2.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@2aaf7cc2
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Apple2
true
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Apple3.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@6e3c1e69
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Apple3
true
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Fal.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@d7b1517
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Fal
false
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Inner.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@16c0663d
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Inner
true
.
我是静态内部类
36
我是内部类的ScannedGenericBeanDefinition的名称:Outter.Inner
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Jug.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@23223dd8
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Jug
false
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter$Real.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@4ec6a292
com.xiaoxu.test.enclosingClass.Outter
com.xiaoxu.test.enclosingClass.Outter$Real
true
.
我是静态内部类
36
我是内部类的ScannedGenericBeanDefinition的名称:Outter.Real
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\Outter.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@1b40d5f0
null
com.xiaoxu.test.enclosingClass.Outter
true
----------------------------------------------------------file [D:\java_demo2\target\classes\com\xiaoxu\test\enclosingClass\TestEnclosingClass.class]
哈哈
org.springframework.core.type.classreading.SimpleMetadataReader@ea4a92b
null
com.xiaoxu.test.enclosingClass.TestEnclosingClass
true
----------------------------------------------------------

比如下面的XImportAutoSelector类,即便XImportAutoConfiguration没有@Configuration注解,依然会被Spring扫描到(Spring会优先扫描用户定义的Bean,递归processImports再处理@Import注解等逻辑),它的BeanDefinitionMap中的key,即name,也就是上面的Outter类名 + “.” + 静态内部类Inner类名:

package com.xiaoxu.test.impo.autoconfigure;import com.xiaoxu.test.impo.core.XImportRegistrar;
import com.xiaoxu.test.impo.ifc.EnableSqlMapperProxy;
import com.xiaoxu.test.impo.ifc.RegistrarImport;
import com.xiaoxu.test.impo.ifc.XImport;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Configuration;/*** @author xiaoxu* @date 2023-12-26* java_demo:com.xiaoxu.test.impo.autoconfigure.XImportAutoConfiguration*/
@RegistrarImport
public class XImportAutoConfiguration {@Configuration@XImport@EnableSqlMapperProxy@ConditionalOnMissingBean(XImportRegistrar.class)public static class XImportAutoSelector implements InitializingBean {public XImportAutoSelector() {}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("Not found registrar for registering sqlMapper.");}}}

如下代码执行:

@SpringBootApplication
public class MainApplication {public static void main(String[] args) throws Exception {ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);XImportAutoConfiguration.XImportAutoSelector bean = run.getBean("XImportAutoConfiguration.XImportAutoSelector", XImportAutoConfiguration.XImportAutoSelector.class);bean.afterPropertiesSet();}}

执行结果如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/508199.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue2 element 实现表格点击详情,返回时保留查询参数

先直观一点,上图 列表共5条数据,准备输入Author过滤条件进行查询 进入查看详情页,就随便搞了个按钮 啥都没调啦 点击返回后 一开始准备用vuex做这个功能,后来放弃了,想到直接用路由去做可能也不错。有时间再整一套…

Onenote软件新建笔记本时报错:无法在以下位置新建笔记本

报错现象: 当在OneNote软件上,新建笔记本时: 然后,尝试重新登录微软账户,也不行,提示报错: 解决办法: 打开一个新的记事本,复制粘贴以下内容: C:\Users\Adm…

pytest多重断言插件-pytest-assume

最近准备废弃之前用metersphere做的接口自动化,转战pytest了,先来分享下最近接触到的一个插件:pytest-assume。 在使用这个插件之前,如果一个用例里面有多个断言的话,前面的断言失败了,就不会去执行后面的断…

MATLAB环境下基于区域椭圆拟合的细胞分割方法

使用图像分割技术可以找到图像中的目标区域,目标区域可以定义为具有特定值的单个区域,也可以定义为具有相同值的多个区域。目前图像分割已经融入到生活中的方方面面,在遥感领域,它应用于航拍图中的地形、地貌的分割;在…

如何防止 Elasticsearch 服务 OOM ?

ES 和传统关系型数据库有很多区别, 比如传统数据中普遍都有一个叫“最大连接数”的设置。目的是使数据库系统工作在可控的负载下,避免出现负载过高,资源耗尽,谁也无法登录的局面。 那 ES 在这方面有类似参数吗?答案是…

中科大计网学习记录笔记(十七):拥塞控制原理 | TCP 拥塞控制

前言: 学习视频:中科大郑烇、杨坚全套《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》课程 该视频是B站非常著名的计网学习视频,但相信很多朋友和我一样在听完前面的部分发现信…

LeetCode第125场双周赛个人题解

目录 100231. 超过阈值的最少操作数 I 原题链接 思路分析 AC代码 100232. 超过阈值的最少操作数 II 原题链接 思路分析 AC代码 100226. 在带权树网络中统计可连接服务器对数目 原题链接 思路分析 AC代码 100210. 最大节点价值之和 原题链接 思路分析 AC代码 10023…

Linux:kubernetes(k8s)部署CNI网络插件(4)

在上一章进行了node加入master Linux:kubernetes(k8s)node节点加入master主节点(3)-CSDN博客https://blog.csdn.net/w14768855/article/details/136420447?spm1001.2014.3001.5501 但是他们显示还是没准备好 看一下…

python科学计算库之Numpy库的使用的简单习题

Numpy库 Numpy(Numerical Python的缩写)是一个开源的Python库,用于进行科学计算。它提供了一个高性能的多维数组对象(ndarray)及用于处理这些数组的各种工具和函数。由于其高效和灵活的数据结构以及丰富的功能&#x…

芯片的制造详解(1)——沙子到晶圆

哔哩哔哩视频 up:谈三圈(2021/8月内容) 芯片的制造流程、工艺、设备 面临困境: 国产芯片卡脖子的地方:制造芯片(制造过程中的一系列设备和和材料)包括但不限于:光刻机、光刻胶、薄膜沉积设备、…

NIO核心三:Selector

一、基本概念 选择器提供一种选择执行已经就绪的任务的能力。selector选择器可以让单线程处理多个通道。如果程序打开了多个连接通道,每个连接的流量都比较低,可以使用Selector对通道进行管理。 二、如何创建选择器 1.创建Selector Selector select…

类加载器分类

类加载器(Class Loader)是Java虚拟机(JVM)的一个重要组件,负责加载Java类到内存中并使其可以被JVM执行。类加载器是Java程序的核心机制之一。 主要有一下四种类加载器: (1)启动类加…