Spring:EnclosingClass工具类分辨

news2024/9/25 9:30:28

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) '.'值为46
                    String 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() {
        }

        @Override
        public 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.coloradmin.cn/o/1486737.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机专业必看的几部电影推荐

计算机专业必看的几部电影,就像一场精彩的编程盛宴!《黑客帝国》让你穿越虚拟世界,感受高科技的魅力;《社交网络》揭示了互联网巨头的创业之路,《源代码》带你穿越时间解救世界,这些电影不仅带我们穿越到科…

模型部署 - onnx 的导出和分析 -(1) - PyTorch 导出 ONNX - 学习记录

onnx 的导出和分析 一、PyTorch 导出 ONNX 的方法1.1、一个简单的例子 -- 将线性模型转成 onnx1.2、导出多个输出头的模型1.3、导出含有动态维度的模型 二、pytorch 导出 onnx 不成功的时候如何解决2.1、修改 opset 的版本2.2、替换 pytorch 中的算子组合2.3、在 pytorch 登记&…

SpringBoot+Maven多环境配置模式

我这里有两个配置文件 然后在最外层的父级POM文件里面把这个两个配置文件写上 <profiles><profile><id>druid</id><properties><spring.profiles.active>druid</spring.profiles.active></properties><activation><…

管理系统提升:列表页构成要素,拒绝千篇一律

大家伙&#xff0c;我是大千UI工场&#xff0c;专注UI知识案例分享和接单&#xff0c;本期带来B端系统列表页的分享&#xff0c;欢迎大家关注、互动交流。 一、什么是列表页 管理系统列表页是指管理系统中用于展示和管理数据的页面&#xff0c;通常以表格或列表的形式呈现。列…

经典语义分割(一)利用pytorch复现全卷积神经网络FCN

经典语义分割(一)利用pytorch复现全卷积神经网络FCN 这里选择B站up主[霹雳吧啦Wz]根据pytorch官方torchvision模块中实现的FCN源码。 Github连接&#xff1a;FCN源码 1 FCN模型搭建 1.1 FCN网络图 pytorch官方实现的FCN网络图&#xff0c;如下所示。 1.2 backbone FCN原…

斐波那契数列模型---使用最小花费爬楼梯

746. 使用最小花费爬楼梯 - 力扣&#xff08;LeetCode&#xff09; 1、状态表示&#xff1a; 题目意思即&#xff1a;cost[i]代表从第i层向上爬1阶或者2阶&#xff0c;需要花费多少力气。如cost[0]&#xff0c;代表从第0阶爬到第1阶或者第2阶需要cost[0]的力气。 一共有cost.…

Java - List集合与Array数组的相互转换

一、List 转 Array 使用集合转数组的方法&#xff0c;必须使用集合的 toArray(T[] array)&#xff0c;传入的是类型完全一样的数组&#xff0c;大小就是 list.size() public static void main(String[] args) throws Exception {List<String> list new ArrayList<S…

梯度下降算法(带你 原理 实践)

目录 一、引言 二、梯度下降算法的原理 三、梯度下降算法的实现 四、梯度下降算法的优缺点 优点&#xff1a; 缺点&#xff1a; 五、梯度下降算法的改进策略 1 随机梯度下降&#xff08;Stochastic Gradient Descent, SGD&#xff09; 2 批量梯度下降&#xff08;Batch…

【解读】工信部数据安全能力提升实施方案

近日&#xff0c;工信部印发《工业领域数据安全能力提升实施方案&#xff08;2024-2026年&#xff09;》&#xff0c;提出到2026年底&#xff0c;我国工业领域数据安全保障体系基本建立&#xff0c;基本实现各工业行业规上企业数据安全要求宣贯全覆盖。数据安全保护意识普遍提高…

vue api封装

api封装 由于一个项目里api是很多的&#xff0c;随处都在调&#xff0c;如果按照之前的写法&#xff0c;在每个组件中去调api&#xff0c;一旦api有改动&#xff0c;遍地都要去改&#xff0c;所以api应该也要封装一下&#xff0c;将api的调用封装在函数中&#xff0c;将函数集…

sql 行列互换

在SQL中进行行列互换可以使用PIVOT函数。下面是一个示例查询及其对应的结果&#xff1a; 创建测试表格 CREATE TABLE test_table (id INT PRIMARY KEY,name VARCHAR(50),category VARCHAR(50) );向测试表格插入数据 INSERT INTO test_table VALUES (1, A, Category A); INSE…

Go语言必知必会100问题-15 缺少代码文档

缺少代码文档 文档&#xff08;代码注释&#xff09;是编码的一个重要方面&#xff0c;它可以降低客户端使用API的复杂度&#xff0c;也有助于项目维护。在Go语言中&#xff0c;我们应该遵循一些规则使得我们的代码更地道。下面一起来看看这些规则。 每个可导出的元素必须添加…

YOLOv9有效提点|加入MobileViT 、SK 、Double Attention Networks、CoTAttention等几十种注意力机制(五)

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文只有代码及注意力模块简介&#xff0c;YOLOv9中的添加教程&#xff1a;可以看这篇文章。 YOLOv9有效提点|加入SE、CBAM、ECA、SimA…

JVM相关问题

JVM相关问题 一、Java继承时父子类的初始化顺序是怎样的&#xff1f;二、JVM类加载的双亲委派模型&#xff1f;三、JDK为什么要设计双亲委派模型&#xff0c;有什么好处&#xff1f;四、可以打破JVM双亲委派模型吗&#xff1f;如何打破JVM双亲委派模型&#xff1f;五、什么是内…

【数据结构】前缀树的模拟实现

目录 1、什么是前缀树&#xff1f; 2、模拟实现 2.1、前缀树节点结构 2.2、字符串的添加 2.3、字符串的查寻 2.3.1、查询树中有多少个以字符串"pre"作为前缀的字符串 2.3.2、查询某个字符串被添加过多少次 2.4、字符串的删除 3、完整代码 1、什么是前缀树&…

(资源篇)2025届暑假实习春招全攻略路线

绝对的全攻略&#xff0c;资源完善程度绝对的全网唯一。 觉得有帮助的&#xff1a;随手一键三连关注就是对up主最大的激励。 绝对的宝藏up主&#xff01;&#xff01;&#xff01;&#xff0c;up主每天都会进行更新视频&#xff0c;算法视频or校招信息or八股讲解。 【暴躁老…

数字化转型导师坚鹏:如何制定证券公司数字化转型年度培训规划

如何制定与实施证券公司数字化转型年度培训规划 ——以推动证券公司数字化转型战略落地为核心&#xff0c;实现知行果合一 课程背景&#xff1a; 很多证券公司都在开展数字化转型培训工作&#xff0c;目前存在以下问题急需解决&#xff1a; 缺少针对性的证券公司数字化转型…

账单怎么记账软件下载,佳易王账单记账汇总统计管理系统软件教程

账单怎么记账软件下载&#xff0c;佳易王账单记账汇总统计管理系统软件教程 一、前言 以下软件以 佳易王账单记账汇总统计管理系统软件V17.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 软件特色&#xff1a; 1、功能实用&#xff0c;操作…

第二天 Kubernetes落地实践之旅

第二天 Kubernetes落地实践之旅 本章学习kubernetes的架构及工作流程&#xff0c;重点介绍如何使用Workload管理业务应用的生命周期&#xff0c;实现服务不中断的滚动更新&#xff0c;通过服务发现和集群内负载均衡来实现集群内部的服务间访问&#xff0c;并通过ingress实现外…

one4all 排坑记录

one4all 排坑记录 任务踩坑回顾动作踩坑动作踩坑动作新一步测试Habitat-sim 测试habitat-lab继续ONE4ALL 任务 看了《One-4-All: Neural Potential Fields for Embodied Navigation》这篇论文&#xff0c;感觉挺有意思&#xff0c;他也开源了代码。视觉语言导航是我一直想做的…