Spring 自动化装配 Bean

Spring 从两个角度来实现自动化装配:

  • 组件扫描:Spring 会自动发现应用上下文中所创建的 bean。
  • 自动装配:Spring 会自动满足 bean 之间的依赖关系。

组件

Spring 中使用 @Component 注解将一个类标注为组件类,并告知 Spring 要为这个类创建 bean,这样就不用显式配置了。代码如下: 首先,我们创建一个 CompactDisc 接口

java 复制代码
package org.example.autoconfig;

public interface CompactDisc {
	void play();
}

然后,创建一个 CompactDisc 接口的实现类 SgtPeppers,并使用 @Component 注解将该类标注为一个组件类。

java 复制代码
package org.example.autoconfig;

import org.springframework.stereotype.Component;

@Component
public class SgtPeppers implements CompactDisc {
    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";
    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}

Spring 应用上下文会为所有的 bean 创建一个 ID,默认值就是类名的首字母小写。如果想要为 bean 设置 ID 值,只需要在 @Component 注解中传入 ID 的值即可。例如:

java 复制代码
package org.example.autoconfig;

import org.springframework.stereotype.Component;

// 设置 SgtPeppers 类的 bean 的 ID 为 lonelyHeartsClub
@Component("lonelyHeartsClub") 
public class SgtPeppers implements CompactDisc {
    ...
}

组件扫描

Spring 的组件扫描默认是不开启的,需要显式地配置,从而 命令 Spring 去寻找带有 @Component 注解的类。有两种方式开启组件扫描。

  1. 在配置类(@Configuration 注解标注的类)中使用 @ComponentScan 注解,开启组件扫描。 @ComponentScan 默认会扫描与配置类相同的包以及这个包下的所有子包,带有 @Component 注解的类,并自动为其创建一个 bean。代码如下:
java 复制代码
package org.example.autoconfig;

@Configuration
@ComponentScan
public class CDPlayerConfig {
	...
}

如果想扫描指定的包,可以在 @ComponentScan 注解的 value 属性中,使用 String 类型的值指明包名称:

java 复制代码
package org.example.autoconfig;

@Configuration
@ComponentScan("org.example.autoconfig")
public class CDPlayerConfig {
	...
}

如果想要更加清晰地表明设置的是基础包,可以通过 basePackages 属性进行设置,可以设置一个或者多个基础包:

java 复制代码
package org.example.autoconfig;

@Configuration
// 设置一个基础包
@ComponentScan(basePackages = "org.example.autoconfig")
// 设置多个基础包
// @ComponentScan(basePackages = {"org.example.autoconfig", "org.example.xmlconfig"})
public class CDPlayerConfig {
}

除了使用字符串设置包名称外,还可以将 basePackageClasses 属性设置为包中所包含的类或者接口,这些类所在的包将会作为组件扫描的基础包。

java 复制代码
@Configuration
@ComponentScan(basePackageClasses = { CompactDisc.class, SgtPeppers.class})
public class CDPlayerConfig {
}
  1. 在 Spring 的 XML 配置文件中使用 <context:component-scan> 元素,开启组件扫描。这需要引入 Spring 的 context 命名空间。代码如下:
xml 复制代码
<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd 
       http://http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd">
       
	<!-- 开启组件扫描, 并指定扫描的基础包为 soundsystem -->
    <context:component-scan base-package="soundsystem"/>
</beans>

自动装配

简单来说,自动装配就是让 Spring 自动满足 bean 依赖的一种方法,在满足依赖的过程中,会在 Spring 应用上下文中寻找匹配某个 bean 需求的其他 bean。为了声明要进行自动装配,可以使用 Spring 的 @Autowired 注解。 首先,先声明一个 MediaPlayer 接口,代码如下:

java 复制代码
package org.example.javaconfig;

public interface MediaPlayer {
    void play();
}

然后,在它的实现类的构造函数上使用 @autowired 注解,当 Spring 创建 CDPlayer 类的 bean 的时候,会通过这个构造器来进行实例化并且传入一个 CompactDisc 类的 bean,实现自动装配,代码如下:

java 复制代码
package org.example.javaconfig;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class CDPlayer implements MediaPlayer {
    private CompactDisc cd;

    // 使用在构造函数上,当Spring要创建CDPlayer的bean时,会自动注入CompactDisc的bean
    @Autowired
    public CDPlayer(CompactDisc cd){
        this.cd = cd;
    }
    @Override
    public void play() {
        cd.play();
    }
}

@Autowired 注解不仅能够用在构造器上,还能在属性的 Setter 方法上,如果 CDPlayer 类有一个 setCompactDisc() 方法,可以采用下面的注解形式进行自动装配:

java 复制代码
@Autowired
public void setCompactDisc(CompactDisc cd){
	this.cd = cd;
}

在 Spring 初始化 bean 之后,它会尽可能的去满足 bean 的依赖。不管是构造器、Setter 方法还是其他的方法,Spring 都会尝试满足方法参数上所声明的依赖。假如有且只有一个 bean 匹配依赖需求的话,那么这个 bean 将会被装配进来。 如果没有匹配的 bean,那么在应用上下文创建的时候,Spring 会抛出一个异常。为了避免异常的出现,可以将 @Autowired 的 required 属性设置为 false:

java 复制代码
@Autowired(required=false)
public CDPlayer(CompactDisc cd){
	this.cd = cd;
}

将 required 属性设置为 false 时,Spring 会尝试执行自动装配,但是如果没有匹配的 bean 的话,Spring 将会让这个 bean 处于未装配状态。但是,把 required 属性设置为 false 时,需要谨慎对待。如果在代码中没有进行 null 检查的话,这个处于未装配状态的属性有可能会出现 NullPointerException。 如果有多个 bean 都能满足依赖的话,Spring 将会抛出一个异常,表明没有明确指定要选择哪个 bean 进行自动装配。

相关推荐
javadaydayup1 小时前
明明说好的国际化,可你却还是返回了中文
spring boot·后端·spring
程序员秘密基地2 小时前
基于vscode,idea,java,html,css,vue,echart,maven,springboot,mysql数据库,在线考试系统
java·vue.js·spring boot·spring·web app
吾日三省吾码2 小时前
Spring 团队详解:AOT 缓存实践、JSpecify 空指针安全与支持策略升级
java·spring·缓存
花月C5 小时前
Mysql-定时删除数据库中的验证码
数据库·后端·mysql·spring
风铃儿~15 小时前
Spring AI 入门:Java 开发者的生成式 AI 实践之路
java·人工智能·spring
hstar952719 小时前
三十三、面向对象底层逻辑-SpringMVC九大组件之HandlerExceptionResolver接口设计
java·spring·设计模式·架构
面朝大海,春不暖,花不开19 小时前
Spring Security默认配置覆盖指南
java·后端·spring
IT_Octopus21 小时前
多线程下使用缓存+锁Lock, 出现“锁失效” + “缓存未命中竞争”的缓存击穿情况,双重检查缓存解决问题
java·spring·缓存
qq_338032921 天前
Spring Boot/Spring应用中配置自定义RedisTemplate
spring boot·redis·spring
考虑考虑1 天前
Springboot3.5.x版本actuator新属性
spring boot·后端·spring