ApplicationContext获取对象时注解丢失问题及 Arthas 验证方法

news2025/2/26 9:45:41

引言


在使用 Spring 框架时遇到的一个常见问题:通过 ApplicationContext 获取到的对象无法获取到注解。
本文的目的:探讨这个问题的原因,并展示如何使用 Arthas 工具来验证和解决问题。

问题描述

描述具体的问题场景:通过 ApplicationContext 获取到的 Bean 对象无法获取到其上的注解。

提供一个简单的示例代码来复现问题:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        MyService myService = context.getBean(MyService.class);

        // 尝试获取注解
        MyAnnotation annotation = myService.getClass().getAnnotation(MyAnnotation.class);
        if (annotation != null) {
            System.out.println("Annotation found: " + annotation.value());
        } else {
            System.out.println("Annotation not found.");
        }
        
    }

    public interface MyService {
        void doSomething();
    }
	
	@MyAnnotation(value = "example")
    public static class MyServiceImpl implements MyService {
        @Override
        public void doSomething() {
            System.out.println("Doing something...");
        }
    }
	
    public static class AppConfig {
        // 配置 Bean
    }
    
}

解决方案

Spring AOP 默认使用 CGLIB 或 JDK 动态代理来创建代理对象。如果你通过 ApplicationContext 获取到的是一个代理对象,而不是实际的目标对象,那么你可能无法直接从代理对象上获取到注解。

获取目标类:使用 AopUtils 工具类来获取目标类。
获取目标对象:使用 AopProxyUtils 工具类来获取目标对象。

import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AnnotationExample {

    public static void main(String[] args) {
        // 创建 ApplicationContext
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 获取 Bean
        MyService myService = context.getBean(MyService.class);

        // 获取目标类
        Class<?> targetClass = AopProxyUtils.ultimateTargetClass(myService);
        System.out.println("Target Class: " + targetClass.getName());

        // 获取目标对象
        Object targetObject = AopProxyUtils.getSingletonTarget(myService, MyService.class);
        if (targetObject != null) {
            MyService targetMyService = (MyService) targetObject;
            MyAnnotation annotation = targetMyService.getClass().getAnnotation(MyAnnotation.class);
            if (annotation != null) {
                System.out.println("Annotation found: " + annotation.value());
            } else {
                System.out.println("Annotation not found.");
            }
        } else {
            System.out.println("Target object is null.");
        }
    }

    public interface MyService {
        void doSomething();
    }
	
	@MyAnnotation(value = "example")
    public static class MyServiceImpl implements MyService {
        @Override
        public void doSomething() {
            System.out.println("Doing something...");
        }
    }

    public static class AppConfig {
        // 配置 Bean
    }
    
}

使用 Arthas 验证

这里我以我当时开发时所遇到的问题同时去使用arthas来验证:

上述代码我是从ApplicationContext通过接口类型的方式去获取实现类的,但是有个问题,我其中一个实现类里面用到了事物回滚,所以我这个类会被Spring生成一个CGLIB的代理对象:

使用了回滚的事物注解:

可以断点来验证类型:

我们使用arthas查看cglib对象的结构:

  • 搜索类:使用 sc 命令查找相关的类。
  • 反编译源码:使用 jad 命令反编译代理类和目标类,查看其源码。
# 示例启动 Arthas 并选择目标进程
java -jar arthas-boot.jar

# 搜索实现类的全路径包名加上*可以将代理类也检索出来
sc com.example.MyServiceImpl*

# 示例反编译代理类
jad com.example.MyService$$EnhancerBySpringCGLIB$$c8826fe2

# 示例反编译目标类
jad com.example.MyServiceImpl

本人电脑展示一下:
查找目标类与代理类:

查看代理类:

查看原始类:

总结

  • 注解被保留:注解的 @Retention 应设置为 RUNTIME,否则也会导致获取不到注解的问题。
  • 检查代理对象:使用 AopProxyUtils 和 AopUtils 获取目标类和目标对象。
  • debug调试信息:添加调试信息来查看具体的对象类型和类信息。

通过这些方法就成功地从 Spring 的 ApplicationContext 获取的对象中读取到注解。

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

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

相关文章

MySQL—关于数据库的CRUD—(增删改查)

文章目录 关于数据库的使用&#xff1a;1. 数据库的背景知识&#xff1a;2. MYSQL数据库软件的使用&#xff08;MYSQL安装的问题在另一篇博客中讲解&#xff09;。&#xff08;1&#xff09;启动MYSQL数据库软件&#xff08;2&#xff09;开始使用数据库程序&#xff1a;1&…

【微信小程序_13_页面配置与网络数据请】

摘要:本文介绍了微信小程序的页面配置与网络数据请求。页面配置文件可对单个页面进行个性化设置,与全局配置冲突时以页面配置为准。网络数据请求有严格限制,包括只能用 HTTPS 接口并添加到信任列表。可通过wx.request()发起 GET 和 POST 请求,能在页面加载时自动请求数据。…

机器学习-决策树详解

决策树 决策树简介 学习目标 1.理解决策树算法的基本思想 2.知道构建决策树的步骤 【理解】决策树例子 决策树算法是一种监督学习算法&#xff0c;英文是Decision tree。 决策树思想的来源非常朴素&#xff0c;试想每个人的大脑都有类似于if-else这样的逻辑判断&#xff…

使用 python 下载 bilibili 视频

本文想要达成的目标为&#xff1a;运行 python 代码之后&#xff0c;在终端输入视频链接&#xff0c;可自动下载高清 1080P 视频并保存到相应文件夹。 具体可分为两大步&#xff1a;首先&#xff0c;使用浏览器开发者工具 F12 获取请求链接相关信息&#xff08;根据 api 接口下…

Java多线程--实现跑马小游戏

线程的实现方式 继承Thread类&#xff1a;void run()方法没有返回值&#xff0c;无法抛异常实现Runnable接口&#xff1a;void run()方法没有返回值&#xff0c;无法抛异常实现Callable接口&#xff1a;V call() throws Exception 返回结果&#xff0c;能够抛异常 实现Callab…

分类预测|基于鹦鹉优化宽度神经网络的数据分类预测Matlab程序 PO-BLS多特征输入多类别输出

分类预测|基于鹦鹉优化宽度神经网络的数据分类预测Matlab程序 PO-BLS多特征输入多类别输出 文章目录 前言分类预测|基于鹦鹉优化宽度神经网络的数据分类预测Matlab程序 PO-BLS多特征输入多类别输出 一、PO-BLS模型PO-BLS&#xff1a;鹦鹉优化宽度神经网络分类预测原理1. 宽度神…

06DSP学习-利用syscfg配置DAC

在做实验的过程中&#xff0c;有些变量(例如逆变器的电压相位、计算过程中的数字量)是没有办法通过示波器观察的&#xff0c;因此需要将数字量转换为模拟量&#xff0c;一般转换成电压。 DSP有三个片上DAC&#xff0c;本篇博客学习如何使用syscfg配置DAC F28379D DAC介绍 TM…

【opencv】以A4纸为参照物测量物体尺寸(包含:偏移纠正,轮廓检测,绘制轮廓函数)

文章目录 测试结果原图python代码ObjectMeasuremetn.pyutils.py测试结果 原图 python代码 ObjectMeasuremetn.py import cv2 import numpy as np import utilswebcam = False path = ../da

记录一次hiveserver2卡死(假死)问题

问题描述 给开发人员开通了个账号&#xff0c;连接hive进行查询&#xff0c;后来发现&#xff0c;hive服务有时候会卡死&#xff0c;查询不了&#xff0c;连不上&#xff08;所有账号/客户端都连不上hive&#xff09;&#xff0c;但在chd里面看监控&#xff0c;服务器资源状态…

SpringBoot 之 配置 RestTemplate + 跳过https 验证

上截图 目录文件结构 在配置文件下创建下面两个文件 文件内容 HttpsClientHttpRequestFactory.java package org.fri.config;import org.apache.http.ssl.SSLContexts; import org.apache.http.ssl.TrustStrategy; import org.springframework.context.annotation.Configur…

用自己的数据集复现YOLOv5

yolov5已经出了很多版本了&#xff0c;这里我以目前最新的版本为例&#xff0c;先在官网下载源码&#xff1a;GitHub - ultralytics/yolov5: YOLOv5 &#x1f680; in PyTorch > ONNX > CoreML > TFLite 然后下载预训练模型&#xff0c;需要哪个就点击哪个模型就行&am…

JavaSE——String类详解

目录 一、String类简介 二、关于字符串拼接的号 三、StringJoiner类——通过连接符拼接字符串 四、String类常用方法详解 五、instanceof关键字 一、String类简介 String是被final修饰的类&#xff0c;不能被继承&#xff0c;因此不能使用匿名内部类。String是一个常量&a…

leetocode二叉树(六)-翻转二叉树

题目 226.翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。、 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#x…

【STM32项目】基于stm32四足跳舞机器人设计与实现(完整工程资料源码)

目录 前言 一、设计目的&#xff1a; 1.1 设计背景 1.2 设计意义 1.3 设计功能 二、硬件部分 2.1 sg90舵机&#xff08;8个&#xff09; 2.2 stm32f103c8t6&#xff08;1个&#xff09; 2.3 OLED显示屏&#xff08;1个&#xff09; 2.4 HC-05蓝牙模块&#xff08;1个&#xff…

C语言malloc超级详细用法和calloc 扩展

前提 在C语言中&#xff0c;malloc&#xff08;内存分配&#xff09;用于动态分配内存。它是标准库中的一部分&#xff0c;包含在 <stdlib.h> 头文件中。使用 malloc 可以在运行时请求所需的内存空间&#xff0c;而不是在编译时就确定内存大小。 语法 在cplusplus中mall…

LeetCode岛屿数量

题目描述 给你一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此外&#xff0c;你可以假设该网…

Elasticsearch生产应用(进阶版),不知道怎么提升生产ES集群性能,看这篇就可以了

这里借助kibana进行修改相应的配置 elasticsearch集群的部署&#xff0c;详情请看上一篇文章&#xff1a; Elasticsearch最新版快速入门看这个就可以了-CSDN博客 基础ES集群运维篇可以查看 Elasticsearch 生产应用&#xff08;实用版&#xff09;&#xff0c;知晓这些&…

“探索Adobe Photoshop 2024:订阅方案、成本效益分析及在线替代品“

设计师们对Adobe Photoshop这款业界领先的图像编辑软件肯定不会陌生。如果你正考虑加入Photoshop的用户行列&#xff0c;可能会对其价格感到好奇。Photoshop的价值在于其强大的功能&#xff0c;而它的价格也反映了这一点。下面&#xff0c;我们就来详细了解一下Adobe Photoshop…

Python语言实现梯度提升树 (Gradient Boosting Machines, GBM)算法

梯度提升树&#xff08;Gradient Boosting Machines, GBM&#xff09;是一种集成学习方法&#xff0c;通过迭代地训练决策树&#xff0c;并让每棵新的树拟合前一棵树的残差&#xff0c;从而逐步提高模型的准确率。下面是一个简单的Python实现GBM的例子&#xff1a; 实现思路&a…

机器人大功率主轴SycoTec 4060 ER-S汽车电机机芯焊缝铣削打磨加工

在汽车制造的精密领域&#xff0c;每一个细节都关乎着整车的性能与品质&#xff0c;而汽车电机机芯的焊缝加工更是其中至关重要的一环。在机器人末端加装德国进口电主轴 SycoTec 4060 ER-S&#xff0c;为汽车电机机芯焊缝铣削打磨加工带来全新的解决方案。 SycoTec 4060 ER-S转…