从01开始 从01开始
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)

peterjxl

人生如逆旅,我亦是行人
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)
  • 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新特性
    • Java
  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java并发

  • Java源码

  • JVM

  • 韩顺平

  • Java
  • 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,读者可以通过切换分支来查看本文的示例代码。

在GitHub上编辑此页 (opens new window)
上次更新: 2023/6/7 11:49:40
使用基于注解的IoC完成单表的CRUD
Spring整合Junit

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

Theme by Vdoing | Copyright © 2022-2023 粤ICP备2022067627号-1 粤公网安备 44011302003646号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式