Spring学习6-纯注解及测试类

基于一个实例,实现客户信息的增删改查。

dbUtils 中的各种 Handler

  • ArrayHandler:把结果集中的第一行数据转成对象数组。
  • ArrayListHandler:把结果集中的每一行数据都转成一个对象数组,再存放到List中。
  • BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
  • BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
  • ColumnListHandler:将结果集中某一列的数据存放到List中。
  • KeyedHandler:将结果集中的每一行数据都封装到一个Map里,然后再根据指定的key把每个Map再存放到一个Map里。
  • MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
  • MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List。
  • ScalarHandler:将结果集中某一条记录的其中某一列的数据存成Object。

业务层测试

项目搭建完毕,还没有进行spring的配置,为了查看业务层是否有问题,新建测试类,在业务层接口右键,新建JUnit Test Case,放到test目录下,next,全选,finish。此时结构目录为:

纯注解

目前问题

使用上一节使用的注解,我们可以实现部分注解,即替换bean.xml中的配置业务层和持久层的内容,基于注解的 IoC 配置已经完成,但是大家都发现了一个问题:我们依然离不开 spring 的 xml 配置文件,那么能不能不写这个 bean.xml,所有配置都用注解来实现呢?

当然,也需要注意一下,我们选择哪种配置的原则是简化开发和配置方便,而非追求某种技术。

我们发现,之所以我们现在离不开 xml 配置文件,是因为我们有一句很关键的配置:

1
2
<!-- 告知spring框架在,读取配置文件,创建容器时,扫描注解,依据注解创建对象,并存入容器中 -->
<context:component-scan base-package="com.gsynf"></context:component-scan>

另外,数据源和 JdbcTemplate 的配置也需要靠注解来实现。

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 配置QueryRunner -->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>

<!-- 配置C3p0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://服务器IP:3306/spring5?useSSL=false"></property>
<property name="user" value="账户名"></property>
<property name="password" value="密码"></property>
</bean>

新注解

@ComponentScan

作用:
用于指定 spring 在初始化容器时要扫描的包。作用和在 spring 的 xml 配置文件中的:
<context:component-scan base-package="com.gsynf"></context:component-scan>是一样的。
属性:
basePackages:用于指定要扫描的包。和该注解中的 value 属性作用一样。

@Configuration

作用:
用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration 注解的类.class)。
属性:
value:用于指定配置类的字节码

@Bean

作用:
该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。
属性:
name:给当前@Bean 注解方法创建的对象指定一个名称(即 bean 的 id)。

注意:

我们已经把数据源和连接池从配置文件中移除了,此时可以删除 bean.xml 了。但是由于没有了配置文件,创建数据源的配置又都写死在类中了。如何把它们配置出来呢?请看下一个注解。

@PropertySource

作用:用于加载.properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。
属性:value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath

注意:
此时我们已经有了两个配置类,但是他们还没有关系。如何建立他们的关系呢?请看下一个注解。

@Import

作用:
用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration 注解。当然,写上也没问题。
属性:
value[]:用于指定其他配置类的字节码。

注意:
我们已经把要配置的都配置好了,但是新的问题产生了,由于没有配置文件了,如何获取容器呢?如下。

通过注解获取容器

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

测试类中的问题和解决思路

问题

在测试类中,每个测试方法都有以下两行代码:

1
2
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService",IAccountService.class);

这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。

解决思路分析

针对上述问题,我们需要的是程序能自动帮我们创建容器。一旦程序能自动为我们创建spring 容器,我们就无须手动创建了,问题也就解决了。
我们都知道,junit 单元测试的原理,但显然,junit 是无法实现的,因为它自己都无法知晓我们是否使用了 spring 框架,更不用说帮我们创建 spring 容器了。不过好在,junit 给我们暴露了一个注解,可以让我们替换掉它的运行器。
这时,我们需要依靠 spring 框架,因为它提供了一个运行器,可以读取配置文件(或注解)来创建容器。我们只需要告诉它配置文件在哪就行了。

配置步骤

第一步:拷贝整合junit的必备jar包到lib目录

jar包为spring-test-xxx.RELEASE.jar

第二步:使用@RunWith注解替换原有运行器

1
2
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})

第三步:使用@ContextConfiguration指定Spring配置文件的位置

1
2
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})

@ContextConfiguration 注解:
locations 属性:用于指定配置文件的位置。如果是类路径下,需要用 classpath:表明
classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。

第四步:使用@Autowired给测试类中的变量注入数据

1
2
@Autowired
private ICustomerService cs =null;

另:

以上并不适合我,因为我是spring5整合JUint5,解决方案如下:

1
2
3
4
import org.springframework.test.context.junit.jupiter.SpringExtension;
………………
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {SpringConfiguration.class})

官方解释The *SpringExtension* class is provided by Spring 5 and integrates the Spring TestContext Framework into JUnit 5. The *@ExtendWith* annotation accepts any class that implements the *Extension* interface.

为什么不把测试类配置到xml中

在解释这个问题之前,先解除大家的疑虑,配到 XML 中能不能用呢?
答案是肯定的,没问题,可以使用。
那么为什么不采用配置到 xml 中的方式呢?
这个原因是这样的:
第一:当我们在 xml 中配置了一个 bean,spring 加载配置文件创建容器时,就会创建对象。
第二:测试类只是我们在测试功能时使用,而在项目中它并不参与程序逻辑,也不会解决需求上的问题,所以创建完了,并没有使用。那么存在容器中就会造成资源的浪费。
所以,基于以上两点,我们不应该把测试配置到 xml 文件中。

:转载文章请注明出处,谢谢~