《SpringBoot 3:入门与应用实战》第 2 章 IOC 思想与实现 阅读笔记 2
2.2 IOC的两种实现方式
Spring Framework IOC 思想的实现方式包含两种,分别是依赖查找 (Dependency Lookup) 与依赖注入 (Dependency Injection)。
2.2.1 依赖查找
依赖查找的含义是,根据指定的对象名称或对象的所属类型,主动从 IOC 容器中获取对应的具体对象。
为了跟 Java new 的对象进去区分,从容器中获取的对象成为 Bean 对象。
1.根据名称查找 (byName)


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yangjunbo</groupId>
<artifactId>spring-ioc-two</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

basic/dl
quickstart-byname.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

package com.yangjunbo.spring.basic.dl;
/**
* ClassName: Person
* Package: com.yangjunbo.spring.basic.dl
* Description:
*
* @Author 杨钧博
* @Create 2026/8/7 16:12
* @Version 1.0
*/
public class Person {
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.yangjunbo.spring.basic.dl.Person"></bean>
</beans>

package com.yangjunbo.spring.basic.dl;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* ClassName: QuickstartByNameApplication
* Package: com.yangjunbo.spring.basic.dl
* Description:
*
* @Author 杨钧博
* @Create 2026/8/7 16:17
* @Version 1.0
*/
public class QuickstartByNameApplication {
public static void main(String[] args){
BeanFactory factory = new ClassPathXmlApplicationContext("basic/dl/quickstart-byname.xml");
Person person = (Person) factory.getBean("person");
System.out.println(person);
}
}
2.根据类型查找 (byType)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.yangjunbo.spring.basic.dl.Person"></bean>
</beans>

package com.yangjunbo.spring.basic.dl;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* ClassName: QuickstartByNameApplication
* Package: com.yangjunbo.spring.basic.dl
* Description:
*
* @Author 杨钧博
* @Create 2026/8/7 16:17
* @Version 1.0
*/
public class QuickstartByTypeApplication {
public static void main(String[] args){
BeanFactory factory = new ClassPathXmlApplicationContext("basic/dl/quickstart-bytype.xml");
Person person = (Person) factory.getBean(Person.class);
System.out.println(person);
}
}

3.接口与实现类

package com.yangjunbo.spring.basic.dl.dao;
import java.util.List;
/**
* ClassName: DemoDao
* Package: com.yangjunbo.dao
* Description:
*
* @Author 杨钧博
* @Create 2026/8/7 11:35
* @Version 1.0
*/
public interface DemoDao {
List<String> findAll();
}

package com.yangjunbo.spring.basic.dl.dao.impl;
import com.yangjunbo.spring.basic.dl.dao.DemoDao;
import java.util.Arrays;
import java.util.List;
/**
* ClassName: DemoDaoImpl
* Package: com.yangjunbo.dao.impl
* Description:
*
* @Author 杨钧博
* @Create 2026/8/7 11:36
* @Version 1.0
*/
public class DemoMysqlDaoImpl implements DemoDao {
@Override
public List<String> findAll() {
//模拟数据
return Arrays.asList("mysql-aaa", "mysql-bbb", "mysql-ccc");
}
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.yangjunbo.spring.basic.dl.Person"></bean>
<bean class="com.yangjunbo.spring.basic.dl.dao.impl.DemoMysqlDaoImpl"></bean>
</beans>

package com.yangjunbo.spring.basic.dl;
import com.yangjunbo.spring.basic.dl.dao.DemoDao;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* ClassName: QuickstartByNameApplication
* Package: com.yangjunbo.spring.basic.dl
* Description:
*
* @Author 杨钧博
* @Create 2026/8/7 16:17
* @Version 1.0
*/
public class QuickstartByTypeApplication {
public static void main(String[] args){
BeanFactory factory = new ClassPathXmlApplicationContext("basic/dl/quickstart-bytype.xml");
//Person person = (Person) factory.getBean(Person.class);
//System.out.println(person);
DemoDao demoDao = factory.getBean(DemoDao.class);
System.out.println(demoDao.findAll());
}
}

2.2.2 依赖注入
1.简单属性值注入
由上面的示例中发现一个问题:以上创建的 bean 对象都是不带属性值的!如果我们要创建的 bean 对象需要一些预设的属性,那么就要涉及IOC 的另一种实现,依赖注入。如果某个 bean 对象需要属性依赖,请不要自行定义,而是将 Bean 定义至 IOC 容器,由 IOC 容器负责加载属性值,并设置到相应的属性上。

package com.yangjunbo.spring.basic.di;
/**
* ClassName: Person
* Package: com.yangjunbo.spring.basic.di
* Description:
*
* @Author 杨钧博
* @Create 2026/8/7 17:16
* @Version 1.0
*/
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.yangjunbo.spring.basic.di.Person">
<property name="name" value="test-person-byset"/>
<property name="age" value="18"/>
</bean>
</beans>

package com.yangjunbo.spring.basic.di;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* ClassName: QuickstartInjectBySetXmlApplication
* Package: com.yangjunbo.spring.basic.di
* Description:
*
* @Author 杨钧博
* @Create 2026/8/7 17:18
* @Version 1.0
*/
public class QuickstartInjectBySetXmlApplication {
public static void main(String[] args) throws Exception {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("basic/di/inject-set.xml");
Person person = beanFactory.getBean(Person.class);
System.out.println(person.getName());
System.out.println(person.getAge());
}
}
2.关联 bean 对象注入

package com.yangjunbo.spring.basic.di;
/**
* ClassName: Cat
* Package: com.yangjunbo.spring.basic.di
* Description:
*
* @Author 杨钧博
* @Create 2026/8/9 20:02
* @Version 1.0
*/
public class Cat {
private String name;
private Person master;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getMaster() {
return master;
}
public void setMaster(Person master) {
this.master = master;
}
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.yangjunbo.spring.basic.di.Person">
<property name="name" value="test-person-byset"/>
<property name="age" value="18"/>
</bean>
<bean id="cat" class="com.yangjunbo.spring.basic.di.Cat">
<property name="name" value="test-cat"/>
<property name="master" ref="person"/>
</bean>
</beans>

package com.yangjunbo.spring.basic.di;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* ClassName: QuickstartInjectBySetXmlApplication
* Package: com.yangjunbo.spring.basic.di
* Description:
*
* @Author 杨钧博
* @Create 2026/8/7 17:18
* @Version 1.0
*/
public class QuickstartInjectBySetXmlApplication {
public static void main(String[] args) throws Exception {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("basic/di/inject-set.xml");
// Person person = beanFactory.getBean(Person.class);
// System.out.println(person.getName());
// System.out.println(person.getAge());
Cat cat = beanFactory.getBean(Cat.class);
System.out.println(cat.getName());
System.out.println(cat.getMaster().getName());
System.out.println(cat.getMaster().getAge());
}
}
2.2.3 依赖查找与依赖注入的对比
- 依赖查找是从 Spring 的 IOC 容器中根据 Bean 的名称或类型找到对应的 Bean。
- 依赖注入是 Spring 的 IOC 容器在创建 Bean 的时候对 Bean 中的属性进行赋值。
2.3 BeanFactory 与 ApplicationContext
顾名思义,IOC 容器即实现了 IOC 思想的容器。
容器可以理解为“一个具备创建 Bean 并管理 Bean 的区域”。
我们将需要创建的 Bean 的信息,以配置文件的方式提供给 Spring Framework,在创建 BeanFactory 或 ApplicationContext 的时候它就会自动帮我们创建这些 Bean,并在我们使用依赖查找(调用getBean方法)时予以返回。
这种从加载和解析配置文件到创建完成容器和内部 Bean 的过程,就是 IOC 容器的基本处理流程。
2.3.2 对比 BeanFactory 与 ApplicationContext
Spring Framework 中的 BeanFactory 就是一个基本的 IOC 容器的实现,而 ApplicationContext 是基于 BeanFactory 的扩展,它拥有BeanFactory 的所有功能,并且还扩展了很多特性。
ApplicationContext 是 BeanFactory 的子接口,它简化了与 AOP 的整合、消息机制、事件机制,以及对 Web 环境的扩 WebApplicationContext等。
2.3.3 理解 Context 与 ApplicationContext
Context 意为“上下文”,简单地说,Context 指的是当程序运行到指定代码时,客观存在的额外数据和信息。
我们可以结合语文来理解,在一篇文章中看到某个故事情节时,可能想要分析情节的作用,这就需要结合当前阅读的部分及其前后章节来综合分析,这里的“前后章节”即上下文,也就是 Context。
在软件开发中 Context 可以理解为代码执行时可以获取的额外信息,包括全局变量、类中的静态成员、ThreadLocal 中的值、配置属性等。
在我们学习 Spring Framework 之后 ApplicationContext 也就成为运行 Spring Framework 应用时的上下文,我们从 ApplicationContext 拿到 IOC 容器中的其他 Bean。
2.4 注解驱动的 IOC
从 Spring Boot 发布以来,使用 XML 配置文件的场景越来越少,取而代之的是基于注解和配置类来驱动 IOC 容器。
Spring Framework 3.0 版本,支持的最低 Java 版本为 Java 5,Java 5 的新特性之一就是引入了注解,从 Spring Framework 3.0 开始也通过引入大量注解代替 XML 的方式进行声明式开发。
2.4.1 注解驱动 IOC 的依赖查找
相较于 XML 配置文件的驱动方式,基于注解驱动的配置会全部编写在配置类中,一个配置类可以理解为一个 XML 配置文件。配置类只需要在类上标注一个 @Configuration 注解。
与 XML 配置文件使用 标签的方式类比,通过配置类注册 Bean 所使用的是 @Bean 注解。
配置类中的方法的返回值代表注册的类型,方法名代表 Bean 的 id。除了使用方法名作为 id 以外,也可以直接在 @Bean 注解中使用 name 属性显式地声明 Bean 的 id。

package com.yangjunbo.spring.annotation;
import com.yangjunbo.spring.basic.di.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuickstartConfiguration {
// 等同于 <bean id="person" class="com.yangjunbo.spring.basic.di.Person"/>
@Bean(name = "person")
public Person person() {
return new Person();
}
}

package com.yangjunbo.spring.annotation;
import com.yangjunbo.spring.basic.di.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AnnotationConfigApplication {
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new AnnotationConfigApplicationContext(QuickstartConfiguration.class);
Person person = ctx.getBean(Person.class);
System.out.println(person);
}
}
2.4.2 注解驱动 IOC 的依赖注入
编写基于 @Bean 注解的依赖注入也非常简单,因为注册 Bean 时使用的是 Java 代码,所以注入哪些属性完全是在代码中编写的。

package com.yangjunbo.spring.annotation;
import com.yangjunbo.spring.basic.di.Cat;
import com.yangjunbo.spring.basic.di.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuickstartConfiguration {
// 等同于 <bean id="person" class="com.yangjunbo.spring.basic.di.Person"/>
// @Bean(name = "person")
// public Person person() {
// return new Person();
// }
@Bean
public Person person() {
Person person = new Person();
person.setName("person");
person.setAge(123);
return person;
}
@Bean
public Cat cat() {
Cat cat = new Cat();
cat.setName("test-cat-anno");
// 直接拿上面的person()方法作为返回值即可,相当于ref
cat.setMaster(person());
return cat;
}
}

package com.yangjunbo.spring.annotation;
import com.yangjunbo.spring.basic.di.Cat;
import com.yangjunbo.spring.basic.di.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AnnotationConfigApplication {
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new AnnotationConfigApplicationContext(QuickstartConfiguration.class);
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
Cat cat = ctx.getBean(Cat.class);
System.out.println(cat.getName());
System.out.println(cat.getMaster().getName());
System.out.println(cat.getMaster().getAge());
}
}
2.4.3 组件注册与扫描机制
翻看 AnnotationConfigApplicationContext 的构造方法,可以发现它还有一个传入 basePackage 的构造方法,要想理解,就需要了解注解驱动中一个非常重要的机制:组件注册与扫描。
1.组件注册的根源:@Component
pring Framework 规定,当一个类上标注了 @Component 注解(并被组件扫描)时,即认定这个类将在 IOC 容器初始化时被创建,并注册到IOC 容器中成为一个 Bean。
默认情况下,组件生成的 beanName 为“首字母小写的类名”(例如 Person 的默认名称是 person,DemoServiceImpl 的默认名称是demoServiceImpl)。如果需要指定 Bean 的名称,就在 @Component 注解中声明 value 属性。
如果 标签不声明 id 属性,默认生成的 Bean 的名称不是“首字母小写的类名”,这一点与注解扫描的规则不同!
在 Spring 框架中,如果 <bean> 标签没有声明 id 属性,默认生成的 Bean 名称(Bean Name)取决于是否声明了 name 属性以及具体的配置方式。具体规则如下:
1. 声明了 name 属性
如果 <bean> 标签没有 id 属性,但声明了 name 属性,那么 Spring 会将 name 属性的值作为该 Bean 的名称。
- 示例: <bean name="myBean" class="com.example.MyBean"/>
- 结果: Bean 的名称为 myBean。
2. id 和 name 都未声明
如果 <bean> 标签既没有 id 也没有 name 属性,Spring 会自动生成一个唯一的 Bean 名称。
- 生成规则: 通常为 Bean 的完整类名 + # + 编号(编号从 0 开始,同种类型的 Bean 依次递增)。
- 示例: 假设定义了 com.example.MyBean 类,且未指定任何名称。
- 结果: 第一个生成的 Bean 名称可能为 com.example.MyBean#0,第二个为 com.example.MyBean#1。
2.组件扫描
如果只是将 @Component 注解标注在类上而不进行扫描,那么 IOC 容器将无法感知到组件注册,当没有扫描组件时强行获取 Bean,一定会抛出 NoSuchBeanDefinitionException 异常,为此需要引入一个新的注解用于组件扫描:@ComponentScan。
@ComponentScan 注解通常标注在配置类上。
我们在配置类上额外标注一个 @ComponentScan 注解,并指定要扫描的包路径,它就可以扫描指定路径包及子包下的所有 @Component 组件。
如果不指定扫描路径,就默认扫描本类所在包及子包下的所有 @Component 组件。可以一次性声明多个扫描的包。

package com.yangjunbo.spring.basic.di;
import org.springframework.stereotype.Component;
/**
* ClassName: Person
* Package: com.yangjunbo.spring.basic.di
* Description:
*
* @Author 杨钧博
* @Create 2026/8/7 17:16
* @Version 1.0
*/
@Component
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}

package com.yangjunbo.spring.annotation;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* ClassName: ComponentScanConfiguration
* Package: com.yangjunbo.spring.annotation
* Description:
*
* @Author 杨钧博
* @Create 2026/8/10 1:49
* @Version 1.0
*/
@Configuration
@ComponentScan("com.yangjunbo.spring.basic.di")
public class ComponentScanConfiguration {
}
除了在配置类中使用 @ComponentScan 注解,Spring Framework 还给我们提供了第二种组件扫描的使用方式。在构造方法中有一个类型为String 可变参数的构造方法,当我们传入需要扫描的包之后,也可以直接扫描到那些标注了 @Component 的 Bean 并注册到 IOC 容器中。

package com.yangjunbo.spring.annotation;
import com.yangjunbo.spring.basic.di.Cat;
import com.yangjunbo.spring.basic.di.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AnnotationConfigApplication {
public static void main(String[] args) throws Exception {
// ApplicationContext ctx = new AnnotationConfigApplicationContext(QuickstartConfiguration.class);
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
// Cat cat = ctx.getBean(Cat.class);
// System.out.println(cat.getName());
// System.out.println(cat.getMaster().getName());
// System.out.println(cat.getMaster().getAge());
ApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanConfiguration.class);
Person person = ctx.getBean(Person.class);
System.out.println(person);
}
}

package com.yangjunbo.spring.annotation;
import com.yangjunbo.spring.basic.di.Cat;
import com.yangjunbo.spring.basic.di.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AnnotationConfigApplication {
public static void main(String[] args) throws Exception {
// ApplicationContext ctx = new AnnotationConfigApplicationContext(QuickstartConfiguration.class);
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
// Cat cat = ctx.getBean(Cat.class);
// System.out.println(cat.getName());
// System.out.println(cat.getMaster().getName());
// System.out.println(cat.getMaster().getAge());
// ApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanConfiguration.class);
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
ApplicationContext ctx = new AnnotationConfigApplicationContext("com.yangjunbo.spring.basic.di");
Person person = ctx.getBean(Person.class);
System.out.println(person);
}
}
组件扫描不是注解驱动 IOC 容器的专利,对于 XML 配置文件驱动的 IOC 容器同样可以启用组件扫描,只需要在 XML配置文件中声明一个标签context:component-scan,之后使用 ClassPathXmlApplicationContext 驱动 IOC 容器,同样可以获取 person 对象。

<?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://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component–scan base–package="com.yangjunbo.spring.basic.di"/>
</beans>

package com.yangjunbo.spring.annotation;
import com.yangjunbo.spring.basic.di.Cat;
import com.yangjunbo.spring.basic.di.Person;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationConfigApplication {
public static void main(String[] args) throws Exception {
// ApplicationContext ctx = new AnnotationConfigApplicationContext(QuickstartConfiguration.class);
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
// Cat cat = ctx.getBean(Cat.class);
// System.out.println(cat.getName());
// System.out.println(cat.getMaster().getName());
// System.out.println(cat.getMaster().getAge());
// ApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanConfiguration.class);
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
// ApplicationContext ctx = new AnnotationConfigApplicationContext("com.yangjunbo.spring.basic.di");
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
BeanFactory beanFactory = new ClassPathXmlApplicationContext("basic/di/inject-scan.xml");
beanFactory.getBean(Person.class);
System.out.println(beanFactory.getBean(Person.class));
}
}
3.组件注册的其他注解
Spring Framework 为了迎合 Web 应用开发时所采用的经典三层架构,额外提供了三个注解:@Controller、@Service、@Repository,分别对应三层架构中的表现层、业务层、持久层。这三个注解的作用与 @Component 完全一致,其实它们的底层也都是 @Component。

4.@Configuration 也是 @Component

2.4.4 注解驱动与 XML 驱动互通
如果一个应用中既有注解驱动配置,又有 XML 配置文件,则可能出现由一方引入另一方配置的情况。下面分别演示互相引入的两种场景。
1.XML 配置文件引入注解驱动
在 XML 中要引入注解驱动,需要开启注解配置,同时注册对应的配置类。

package com.yangjunbo.spring.annotation;
import com.yangjunbo.spring.basic.di.Cat;
import com.yangjunbo.spring.basic.di.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//@Configuration
public class XmlConfiguration {
// 等同于 <bean id="person" class="com.yangjunbo.spring.basic.di.Person"/>
// @Bean(name = "person")
// public Person person() {
// return new Person();
// }
@Bean
public Person person() {
Person person = new Person();
person.setName("person");
person.setAge(123);
return person;
}
@Bean
public Cat cat() {
Cat cat = new Cat();
cat.setName("test-cat-anno");
// 直接拿上面的person()方法作为返回值即可,相当于ref
cat.setMaster(person());
return cat;
}
}


package com.yangjunbo.spring.annotation;
import com.yangjunbo.spring.basic.di.Cat;
import com.yangjunbo.spring.basic.di.Person;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationConfigApplication {
public static void main(String[] args) throws Exception {
// ApplicationContext ctx = new AnnotationConfigApplicationContext(QuickstartConfiguration.class);
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
// Cat cat = ctx.getBean(Cat.class);
// System.out.println(cat.getName());
// System.out.println(cat.getMaster().getName());
// System.out.println(cat.getMaster().getAge());
// ApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanConfiguration.class);
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
// ApplicationContext ctx = new AnnotationConfigApplicationContext("com.yangjunbo.spring.basic.di");
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
// BeanFactory beanFactory = new ClassPathXmlApplicationContext("basic/di/inject-scan.xml");
// beanFactory.getBean(Person.class);
// System.out.println(beanFactory.getBean(Person.class));
BeanFactory beanFactory = new ClassPathXmlApplicationContext("basic/di/inject-config.xml");
Person person = beanFactory.getBean(Person.class);
System.out.println(person.getName());
System.out.println(person.getAge());
Cat cat = beanFactory.getBean(Cat.class);
System.out.println(cat.getName());
System.out.println(cat.getMaster().getName());
System.out.println(cat.getMaster().getAge());
}
}
2.注解配置类引入 XML 配置文件
在注解配置类中引入 XML 配置文件,需要在配置类上标注 @ImportResource 注解,并声明配置文件的路径。

package com.yangjunbo.spring.annotation;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
/**
* ClassName: ImportXmlConfiguration
* Package: com.yangjunbo.spring.annotation
* Description:
*
* @Author 杨钧博
* @Create 2026/8/10 10:50
* @Version 1.0
*/
@Configuration()
@ImportResource("classpath:basic/di/inject-set.xml")
public class ImportXmlConfiguration {
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.yangjunbo.spring.basic.di.Person">
<property name="name" value="test-person-byset"/>
<property name="age" value="18"/>
</bean>
<bean id="cat" class="com.yangjunbo.spring.basic.di.Cat">
<property name="name" value="test-cat"/>
<property name="master" ref="person"/>
</bean>
</beans>

package com.yangjunbo.spring.annotation;
import com.yangjunbo.spring.basic.di.Cat;
import com.yangjunbo.spring.basic.di.Person;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationConfigApplication {
public static void main(String[] args) throws Exception {
// ApplicationContext ctx = new AnnotationConfigApplicationContext(QuickstartConfiguration.class);
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
// Cat cat = ctx.getBean(Cat.class);
// System.out.println(cat.getName());
// System.out.println(cat.getMaster().getName());
// System.out.println(cat.getMaster().getAge());
// ApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanConfiguration.class);
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
// ApplicationContext ctx = new AnnotationConfigApplicationContext("com.yangjunbo.spring.basic.di");
// Person person = ctx.getBean(Person.class);
// System.out.println(person);
// BeanFactory beanFactory = new ClassPathXmlApplicationContext("basic/di/inject-scan.xml");
// beanFactory.getBean(Person.class);
// System.out.println(beanFactory.getBean(Person.class));
// BeanFactory beanFactory = new ClassPathXmlApplicationContext("basic/di/inject-config.xml");
// Person person = beanFactory.getBean(Person.class);
// System.out.println(person.getName());
// System.out.println(person.getAge());
// Cat cat = beanFactory.getBean(Cat.class);
// System.out.println(cat.getName());
// System.out.println(cat.getMaster().getName());
// System.out.println(cat.getMaster().getAge());
ApplicationContext ctx = new AnnotationConfigApplicationContext(ImportXmlConfiguration.class);
Person person = ctx.getBean(Person.class);
System.out.println(person.getName());
System.out.println(person.getAge());
Cat cat = ctx.getBean(Cat.class);
System.out.println(cat.getName());
System.out.println(cat.getMaster().getName());
System.out.println(cat.getMaster().getAge());
}
}


