Spring更简单的实现Bean对象的存取(利用注解储存和注入Bean对象)

目录

一、前言: 

二、储存Bean对象

5大类注解

@Bean方法注解

三、获取Bean对象

属性注入

优缺点 

Setter注入

优缺点分析 

构造方法注入

 优缺点分析

经典面试题 :属性注入 ,构造方法注入 和 Setter 注入 之间,有什么区别?

@Resource VS @Autowired 的区别


一、前言: 

上篇博客,我们讲了一个spring core项目的大致流程:

创建项目——》将对象储存到Spring容器中 ——》从Spring容器中取出Bean对象

但是吧,上篇讲的这些流程还是太繁琐了,有没有一个更简单的方式来实现对象的存取呢?

当然有,一起来看看吧!

首先,Spring项目的创建——这个没有什么好说的!就按我们上篇博客的步骤来进行。

但注意:与上篇博客相比,spring的配置文件发生了改变——为了更简单的实现Bean对象的存入(把对象存到spring中)

更改后的spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:content="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <content:component-scan base-package="在对象储存中,要扫描的路径"></content:component-scan>
</beans>

二、储存Bean对象

首先我们回忆下,我们执行储存Bean对象的方式。

之前我们存储 Bean 时,需要在 spring-config 中添加⼀⾏ bean 注册内容才⾏,如下图所示:

这种存入 Bean 的方式,并不是很好!
1、需要手动添加 bean 对象 到 配置文件中
2、如果 是配置文件中出现了问题,不好调试。

而现在我们不需要一个一个的在spring配置文件中添加我们要储存的Bean对象。我们直接:

 你以为把扫描路径添加到配置文件中就行了吗?

不你还需要再类中添加注解——再扫描的过程中,只有添加了注解的类才能成功存储到spring中

这就引起了我们注解的概念

一共有两者方法:
1、使用 5 大类注解实现

1、@Controller 【Controller - 控制器】
2、@Service 【service - 服务】
3、@Repository 【repository - 仓库】
4、@Configuration 【configuration - 配置/布局】
5、@Component 【component - 组件】

通过上述五大类注解中的任何一个,都可以将 bean 存储到 Spring 中。

2、通过 方法注解@Bean ,也可以将 一个 bean 存储到 Spring 中。

5大类注解

<think> 首先,用户的问题是关于Spring框架的:他们遇到了一个问题,Spring获取的bean代理没有注解信息,他们想知道如何解决这个问题。用户提供了几个引用,我必须参考这些引用来帮助解答。 回顾引用内容: - 引用[1]:讨论了Spring中存储Bean的相关注解,特别是@ComponentScan用于配置扫描路径以使五大注解生效。还提到了@SpringBootApplication如何获取bean。 - 引用[2]:详细讲解了@Bean注解,说明它用在方法上或注释类型声明上。 - 引用[3]:关于存取Bean注解,包括类注解方法注解,如@Controller@Bean,并展示了如何从XML配置中获取bean。 - 引用[4]:提到了使用XML配置扫描包路径,如<context:component-scan base-package="com.lin">,以存储Bean对象。 用户的问题是:“Spring获取的bean代理没有注解信息的解决方案”。意思是,当Spring创建bean的代理时,代理对象上没有原始bean注解信息。这可能是由于代理机制导致的,比如AOP代理或CGLIB代理。 关键点: - 在Spring中,bean可以通过JDK动态代理或CGLIB代理来创建,特别是对于AOP或事务管理。 - 代理对象可能不直接暴露原始bean注解,因为代理是原始bean的包装。 解决方案: 1. **检查代理类型**:确定代理是如何创建的。如果是CGLIB代理,可能需要特殊方式访问原始对象。 2. **访问原始bean**:通过AopContext.currentProxy()或其他方法来获取原始bean。 3. **使用AnnotationUtils**:Spring提供了工具类如AnnotationUtils来查找注解,即使bean被代理。 4. **配置方面**:确保扫描路径正确,bean被正确加载。 从引用中提取相关信息: - 引用[1]强调@ComponentScan配置扫描路径的重要性。如果bean没有正确扫描到,可能导致代理问题。 - 引用[2]提到@Bean注解用于方法上,这可能在代理场景中有影响。 - 引用[3]展示了如何从上下文中获取bean。 - 引用[4]提到XML配置扫描路径。 构建回答: - **结构化回答**:既然系统指令要求结构清晰,我应该逐步解决问题。 - **步骤**: 1. 确认bean是否被正确扫描加载。 2. 理解代理机制。 3. 提供解决方案:使用AnnotationUtils或其他工具。 - **参考引用**:在回答中自然地添加引用标识。 生成相关问题: - 系统指令要求生成相关问题,所以我需要在回答后添加一些相关问题。 最终回答框架: 1. 解释问题原因。 2. 提供解决方案步骤。 3. 添加代码示例(如果需要)。 4. 生成相关问题。 具体解决方案: - **原因**:代理对象是原始对象的包装,直接访问代理可能看不到注解。 - **解决方案**: - 使用AnnotationUtils.findAnnotation(bean.getClass(), annotationType) 来获取注解。 - 或者,通过AopProxyUtils.ultimateTargetClass(proxy) 来获取原始类。 - 确保bean类被正确扫描(引用@ComponentScan或XML配置)。 - **代码示例**:展示如何使用AnnotationUtils。 参考引用: - 在相关部分添加[^1]、[^2]等。 相关问题: - 基于用户查询,生成如: 1. 如何配置Spring以正确扫描bean? 2. Spring中代理机制的工作原理是什么? 3. 如何使用AnnotationUtils处理代理bean注解? </think> ### Spring获取的bean代理没有注解信息的解决方案 在Spring框架中,当bean被代理(如使用AOP、事务管理或动态代理机制)时,代理对象可能不直接暴露原始bean注解信息。这是因为代理对象是原始bean的包装,可能隐藏或覆盖部分元数据[^1][^2]。以下是逐步解决此问题的方案: #### 1. **确认bean扫描路径是否正确配置** - **问题**:如果Spring未正确扫描到bean类,代理可能无法继承原始注解信息。确保使用`@ComponentScan`或XML配置指定了正确的包扫描路径[^1][^4]。 - **解决方案**: - 在Java配置类中添加`@ComponentScan`: ```java @ComponentScan("com.example") // 替换为你的包名 @SpringBootApplication public class Application { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(Application.class, args); } } ``` - 在XML配置中设置`<context:component-scan>`: ```xml <context:component-scan base-package="com.example"/> <!-- 替换为你的包名 --> ``` - **验证**:检查Spring日志,确保目标bean被成功加载(如输出`Bean 'beanName' of type [...] is not eligible for getting processed by all BeanPostProcessors`)[^1][^4]。 #### 2. **使用Spring工具类访问原始注解** - **问题**:代理对象可能无法直接通过`bean.getClass().getAnnotations()`获取注解。 - **解决方案**:使用Spring的`AnnotationUtils`工具类,它能穿透代理层访问原始注解[^2]。 - **示例代码**: ```java import org.springframework.core.annotation.AnnotationUtils; import com.example.MyAnnotation; // 假设你的自定义注解 // 获取bean代理对象 MyBeanInterface proxy = context.getBean(MyBeanInterface.class); // 使用AnnotationUtils获取原始注解 MyAnnotation annotation = AnnotationUtils.findAnnotation(proxy.getClass(), MyAnnotation.class); if (annotation != null) { System.out.println("注解值: " + annotation.value()); } ``` - **关键点**: - `AnnotationUtils.findAnnotation()` 能处理JDK动态代理CGLIB代理。 - 适用于类注解(如`@Controller`)方法注解(如`@Bean`)[^2][^3]。 #### 3. **获取原始bean对象** - **问题**:代理对象可能包装了原始bean,导致注解丢失。 - **解决方案**:通过`AopProxyUtils`获取原始对象。 - **示例代码**: ```java import org.springframework.aop.framework.AopProxyUtils; // 获取代理对象 Object proxy = context.getBean("myBean"); // 获取原始目标类 Class<?> targetClass = AopProxyUtils.ultimateTargetClass(proxy); // 直接访问原始注解 MyAnnotation annotation = targetClass.getAnnotation(MyAnnotation.class); ``` - **适用场景**:适用于需要直接操作原始bean的情况(如反射调用)[^3]。 #### 4. **检查代理机制配置** - **问题**:某些代理配置(如`proxyTargetClass=true`)可能影响注解的可见性。 - **解决方案**: - 在AOP配置中,显式设置`proxyTargetClass=false`以优先使用JDK代理(默认行为易处理注解)。 - 在`@EnableAspectJAutoProxy`中调整: ```java @EnableAspectJAutoProxy(proxyTargetClass = false) public class AppConfig {} ``` - **注意**:CGLIB代理(`proxyTargetClass=true`)可能需额外依赖(如`cglib`库)[^1]。 #### 5. **调试与验证** - **步骤**: 1. 使用`context.getBeanDefinitionNames()`打印所有bean名称,确认目标bean存在。 2. 检查bean定义:`BeanDefinition beanDef = context.getBeanDefinition("beanName")`。 3. 确保自定义注解带有`@Retention(RetentionPolicy.RUNTIME)`,否则运行时不可见。 - **常见错误**: - 扫描路径未覆盖bean包(引用`@ComponentScan`配置错误)[^1]。 - 注解未正确应用到类或方法上(如`@Bean`方法需在配置类中)[^2][^3]。 如果以上步骤仍无效,请提供多上下文(如代理类型、注解定义),以便进一步诊断。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是小鱼儿哈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值