注解@Autowired注入属性

通过注解@Autowired注入属性信息

前言

在目前 IOC、AOP 两大核心功能模块的支撑下,完全可以管理 Bean 对象的注册和获取,不过这样的使用方式总感觉像是刀耕火种有点难用。因此在上一章节我们解决需要手动配置 Bean 对象到 spring.xml 文件中,改为可以自动扫描带有注解 @Component 的对象完成自动装配和注册到 Spring 容器的操作。

那么在自动扫描包注册 Bean 对象之后,就需要把原来在配置文件中通过 property name="token" 配置属性和Bean的操作,也改为可以自动注入。这就像我们使用 Spring 框架中 @Autowired@Value 注解一样,完成我们对属性和对象的注入操作

本节需要添加 @Autowired@Value@Qualifier 等注解功能

  • @Autowired 默认根据类型进行 Bean 注入,因此如果有多个类型相同的 Bean 候选者,则需要指定其中一个候选者,不然 Spring 抛出异常
  • @Qualifier 限定描述符除了能根据名字进行注入,更能通过更细粒度的控制如何选择候选者
  • @Resource 默认按照名称进行装配,名称可以通过 name 属性指定。如果没有指定 name 属性,当注解标注在字段上,默认取字段名进行名称查找;注解写在setter 方法上,默认取属性名进行装配,当找不到名称相符的 bean 才按照类型进行装配,但需要注意的是 name 属性一旦指定,就只会按照名称进行装配

设计

在完成 Bean 基础功能之后。后续陆续添加的内容都是基于 Bean 生命周期进行的。比如修改 Bean 定义信息的 BeanFactoryPostProcessor,处理 Bean 属性需要的 BeanPostProcessor,完成个性的属性操作则专门继承 BeanPostProcessor 提供新的接口,因为这样才能通过 instanceof 判断出具有标记性的接口。所以关于 Bean 等等的操作,以及监听 Aware、获取 BeanFactory,都需要在 Bean 的生命周期中完成。那么我们在设计属性和 Bean 对象的注入时候,也会用到 BeanPostProcessor 来完成在设置 Bean 属性之前,允许 BeanPostProcessor 修改属性值。

  • 要处理自动扫描注入,包括属性注入、对象注入,则需要在对象属性 applyPropertyValues 填充之前 ,把属性信息写入到 PropertyValues 的集合中去。这一步的操作相当于是解决了以前在 spring.xml 配置属性的过程。
  • 而在属性的读取中,需要依赖于对 Bean 对象的类中属性的配置了注解的扫描,field.getAnnotation(Value.class); 依次拿出符合的属性并填充上相应的配置信息。这里有一点 ,属性的配置信息需要依赖于 BeanFactoryPostProcessor 的实现类 PropertyPlaceholderConfigurer,把值写入到 AbstractBeanFactory的embeddedValueResolvers集合中,这样才能在属性填充中利用 beanFactory 获取相应的属性值
  • 还有一个是关于 @Autowired 对于对象的注入,其实这一个和属性注入的唯一区别是对于对象的获取 beanFactory.getBean(fieldType),其他就没有什么差一点了。
  • 当所有的属性被设置到 PropertyValues 完成以后,接下来就到了创建对象的下一步,属性填充,而此时就会把我们一一获取到的配置和对象填充到属性上,也就实现了自动注入的功能。

小疑问

Q:

Spring 框架中的 @Value 能将 properties k-v 结构转换成 map形式嘛

以下内容来自 Chatgpt

A:

Spring 框架中的 @Value 注解不支持直接将 properties 文件中的 k-v 结构转换成 Map 形式。

@Value 注解主要用于从配置文件或环境变量中读取配置值,然后将这些值注入到 Spring 管理的 Bean 中的属性中。它支持基本类型、字符串、数组和集合等类型的注入,但不支持直接将 properties 文件中的 k-v 结构转换成 Map 形式。

如果需要将 properties 文件中的 k-v 结构转换成 Map 形式,可以使用 Spring 的 PropertiesFactoryBean 类来实现。PropertiesFactoryBean 是一个工厂 Bean,它可以将 properties 文件中的内容转换成一个 Properties 对象,并且将该对象注入到其他 Bean 的属性中。通过在其他 Bean 中注入该 Properties 对象,我们就可以方便地访问其中的 k-v 结构,从而实现将 properties 文件中的 k-v 结构转换成 Map 形式的功能。

下面是一个使用 PropertiesFactoryBean 将 properties 文件中的 k-v 结构转换成 Map 形式的示例代码:

javaCopy code@Configuration
@PropertySource("classpath:config.properties")
public class AppConfig {

@Bean
public PropertiesFactoryBean configProperties() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("config.properties"));
return bean;
}

@Bean
public MyBean myBean() throws IOException {
MyBean bean = new MyBean();
bean.setConfigProperties(configProperties().getObject());
return bean;
}
}

在上面的示例中,我们通过使用 @PropertySource 注解来指定 properties 文件的路径,然后通过在 AppConfig 类中定义一个 configProperties() 方法来创建 PropertiesFactoryBean 实例。最后,我们通过在 MyBean 类中注入 configProperties 对象来使用这些配置信息。