从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 新闻合订本
    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 新闻合订本
    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

    • Spring 介绍
    • 程序中的耦合
    • IoC 的概念和作用
    • Spring 中的依赖注入
    • 基于注解的 IoC
    • 使用基于 XML 的 IoC 完成单表的 CRUD
    • 使用基于注解的 IoC 完成单表的 CRUD
    • IoC 的纯注解配置
      • @Configuration
      • @ComponentScan
      • @Bean 注入容器
      • 获取容器
      • 配置多例模式
      • @Configuration 的细节
      • @Import
      • @PropertySource
      • 总结
      • 源码
    • Spring 整合 Junit
    • 事务问题
    • 代理模式
    • AOP 的概念和入门
    • 基于注解的 AOP
    • Spring 的 JdbcTemplate
    • JdBCDaoSupport
    • 基于 XML 的 AOP 实现事务控制
    • 基于注解的 AOP 实现事务控制
    • Spring 的事务控制
    • 基于 XML 的声明式事务控制
    • 基于注解的声明式事务控制
    • 纯注解实现事务控制
    • Spring 编程式事务控制
    • Spring5 新特性
  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java
  • Spring
2023-05-08
目录

IoC 的纯注解配置

# 45.IoC 的纯注解配置

在上一篇博客中,基于注解的 IoC 配置已经完成,但是大家都发现了一个问题:我们依然离不开 Spring 的 XML 配置文件,另外,数据源和 JdbcTemplate 的配置也需要靠注解来实现。那么能不能不写这个 bean.xml,所有配置都用注解来实现呢?

# @Configuration

我们新建一个配置类:(类名和包名随意取)

package com.peterjxl.config;
public class SpringConfiguration {}
1
2

接下来,我们就可以用 Spring 提供的注解,来替代 bean.xml 文件了。我们使用@Configuration 注解,该注解用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解:

@Configuration
public class SpringConfiguration {}
1
2

# @ComponentScan

我们已经把配置文件用类来代替了,但是如何配置创建容器时要扫描的包呢?用 @ComponentScan。该注解用于通过注解指定 Spring 在创建容器时要扫描的包,作用和在 Spring 的 XML 配置文件中的配置扫描包是一样的:

<context:component-scan base-package="com.peterjxl"/>
1

@ComponentScan 的属性:basePackages,用于指定创建容器时要扫描的包:

@Configuration
@ComponentScan(basePackages = {"com.peterjxl"})
public class SpringConfiguration {}
1
2
3

‍ 其实在 ComponentScan 的源码中,basePackages 是 value 属性的别名:

    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};
1
2
3
4
5

AliasFor 就是别名的意思,所以使用该注解时,使用 value 属性和 basePackages 是一样的,他们互为别名。

因此,该注解的写法可以简写为:

@Configuration
@ComponentScan("com.peterjxl")
public class SpringConfiguration {}
1
2
3

‍ 注意:可以配置多个要扫描的包,这里由于只有一个,因此简写了下,没有大括号 {}。

# @Bean 注入容器

现在,bean.xml 文件中,还剩下 QueryRunner 和 DataSource 没有使用注解配置。由于这几个都是第三方依赖,我们很难在里面加上注解;

此时我们可以用@Bean 注解:

  • 作用:该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 Spring 容器。
  • 属性 : name 属性,用于给当前@Bean 注解方法创建的对象指定一个名称(即 bean 的 id)。默认值是当前方法的名称 ‍ 至此,我们就可以新建方法,创造这些对象了:
@Configuration
@ComponentScan("com.peterjxl")
public class SpringConfiguration {

    @Bean(name = "runner")
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean(name = "dataSource")
    public DataSource createDataSource() {
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass("com.mysql.jdbc.Driver");
            ds.setJdbcUrl("jdbc:mysql://localhost:3306/learnSpring");
            ds.setUser("learnSpringUser");
            ds.setPassword("learnSpringPassword");
            return ds;
        } catch (PropertyVetoException e) {
            throw new RuntimeException(e);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

我们已经把数据源从配置文件中移除了,此时可以删除 bean.xml 了。

# 获取容器

我们之前讲过,ApplicationContext 有一个实现类是基于注解的:AnnotationConfigApplicationContext

因此,我们获取容器就是用这个实现类,我们修改下测试方法:

@Test
public void testFindAll() {
    ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    IAccountService as = ac.getBean("accountService", IAccountService.class);
    List<Account> allAccount = as.findAllAccount();
    for (Account account : allAccount) {
        System.out.println(account);
    }
}
1
2
3
4
5
6
7
8
9

‍ 其他测试方法同理,改下获取容器的代码,就可以运行其他测试方法了。

# 配置多例模式

我们可以测试下,QueryRunner 是否多例模式:

public class QueryRunnerTest {

    @Test
    public void testQueryRunner() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        // 获取 QueryRunner 对象
        QueryRunner runner = ac.getBean("runner", QueryRunner.class);
        QueryRunner runner2 = ac.getBean("runner", QueryRunner.class);
        System.out.println(runner == runner2);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12

‍ 由于我们并没有配置是否多例,所以运行结果是 true。为此,我们需要加上一个 scope 注解:

public class SpringConfiguration {

    @Bean(name = "runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }
}
1
2
3
4
5
6
7
8

‍ 此时我们再次运行测试方法,可以看到输出了 false,也就是目前是多例模式了。

# @Configuration 的细节

当我们的配置类,作为容器对象创建的参数时,其实不写@Configuration 也可以:

//@Configuration
@ComponentScan(basePackages = "com.peterjxl")
public class SpringConfiguration {}
1
2
3

‍ 那么什么时候必须写呢?有多个配置类的情况。例如,我们的项目中配置是有很多的,单个配置类难以维护,我们可以新建一个配置类:

@Configuration
public class JdbcConfig {

    @Bean(name = "runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean(name = "dataSource")
    public DataSource createDataSource() {
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass("com.mysql.jdbc.Driver");
            ds.setJdbcUrl("jdbc:mysql://localhost:3306/learnSpring");
            ds.setUser("learnSpringUser");
            ds.setPassword("learnSpringPassword");
            return ds;
        } catch (PropertyVetoException e) {
            throw new RuntimeException(e);
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

‍ 注意,此时必须加上@Configuration 注解,不然扫描的时候,Spring 不会认为该类是一个配置类,也就不会扫描里面的方法,并创建对象放入容器里。

综上所述,主要当配置类是作为容器创建的参数的时候,才不用写@Configuration。当然,创建容器的时候支持传入多个配置类对象,此时两个配置类都不用写@Configuration:

ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class, JdbcConfig.class);
1

但这样,这两个配置类是平级的;而我们想要的是,SpringConfiguration 是一个父配置,其他都是子配置,这时候就需要@Import ‍

# @Import

我们可以使用@Import 注解,将配置类分成几个。 ‍ 作用:用于导入其他的配置类

属性:value 用于指定其他配置类的字节码,可以是一个字节码数组,本例中只有一个。

当我们使用 Import 的注解之后,有 Import 注解的类就父配置类,而导入的都是子配置类

@Configuration
@ComponentScan(basePackages = "com.itheima.spring") 
@Import(JdbcConfig.class)
public class SpringConfiguration {
1
2
3
4

# @PropertySource

在数据源信息的配置类中,我们的数据库地址、用户密码都是放在代码中的;如果要修改,还得重新编译一次代码,不太方便。此时我们可以用@Property 注解,导入配置文件中的数据。

作用:用于加载.properties 文件中的配置。我们可以把连接数据库的信息写到 properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。

属性 : value[],用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath。 ‍ 我们在 resources 目录下新建 jdbcConfig.properties 文件:

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/learnSpring
jdbc.username=learnSpringUser
jdbc.password=learnSpringPassword
1
2
3
4

‍ 然后我们使用@PropertySource 注解,指定配置文件的位置;并且新建一些成员变量,使用@Value 和 EL 表达式,读取配置文件的内容并注入:

@PropertySource("classpath:jdbcConfig.properties")  //注意不能用空格
public class JdbcConfig {

    @Value("${jdbc.driver}")
    private String driver;
  
    @Value("${jdbc.url}")
    private String url;
  
    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Bean(name = "runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean(name = "dataSource")
    public DataSource createDataSource() {
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        } catch (PropertyVetoException e) {
            throw new RuntimeException(e);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 总结

‍ 使用注解配置,并没有比使用 XML 配置更简便一些,特别是对于第三方依赖的情况。此时可能既使用 XML,也使用注解是不错的选择。

关于实际的开发中到底使用 XML 还是注解,则得具体情况具体分析了,一般哪个更方便,就用哪个。

至此,关于 IoC 的概念,我们基本讲完了。 ‍

# 源码

本项目已将源码上传到 GitHub (opens new window) 和 Gitee (opens new window) 上。并且创建了分支 demo7,读者可以通过切换分支来查看本文的示例代码。

上次更新: 2025/6/3 09:31:54
使用基于注解的 IoC 完成单表的 CRUD
Spring 整合 Junit

← 使用基于注解的 IoC 完成单表的 CRUD Spring 整合 Junit→

最近更新
01
新闻合订本 2025-10
10-31
02
2025 年 10 月记
10-30
03
用 AI 批量优化思源笔记排版
10-15
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式