接下来,介绍基于注解与Java Config配置IoC容器。
相比XML配置IoC容器,只是配置方式的不同,其底层原理是一样的。
一、基于注解配置IoC容器
1.1 注解
1.定义
JDK1.5 以后,提供了一种特殊的语法:在类、属性、方法上,通过@符号,增加的某一个特定的类名,称为注解。
作用:为类、属性、方法,在不改变其里面代码的情况下,实现额外的功能扩展、增强。
本质:注解就是写在源代码中的配置信息。
2.优势
左右是鱼与熊掌的问题,不可兼得
因为Spring框架,主要面向Java工程师:首先考虑的是爱用、体验,迎合市场、程序员口味。
对比 | 基于XML | 基于注解 |
---|---|---|
劣势 | XML中,要书写大量的bean标签; | 写死在程序中,不易维护 |
劣势 | 程序员的开发体验不好。因为源码中每次使用一个bean时,都要去翻阅XML找beanId;同时,在XML中对象设置时,也要与源代码中不断切换。 | |
优势 | 后期维护性好 | 前期开发体验好 |
适合场景 | “声明式”的原则,更适合轻量级的现代企业应用 |
之前,学习MyBatis、Servlet时,除了配置文件形式,也有注解形式。
Spring同理。
程序员喜欢的开发体验:
在编写源代码过程中,顺便就把这个bean进行了配置。
1.2 注解的种类:3类
Spring中,按照功能划分,可分为三种注解:
(1)组件类型的注解---------------声明当前类的功能、职责------------------------------ 用于实例化(创建)对象
(2)自动装配的注解---------------根据属性特征,完成值或对象的注入
(3)元数据的注解------------------更细化的辅助IoC容器,管理bean对象的注解
二、基于注解1:组件类型
就是放在Java类上的注解。
用途:简单补上一个组件注解,IoC容器就会自动的实例化(创建)对象,确实清爽简便
2.1 分类:4个
- mapper层其实就是dao层
- 红框其实是通用注解
@Component
的细化 - 组件类型的注解,实例化对象的beanId默认是类名的首字母小写。
Component
a part or element of a larger whole, especially a part of a machine or vehicle.
2.2 在XML中,开启组件扫描
上述4类组件类型的注解,要想被Spring IoC识别,必须有个前置条件:在applicationContext.xml
种,开启组件扫描。
组件扫描原理:扫描该路径下所有的java类,一旦某个Java类上有上述四类组件类型的注解,就对其进行实例化对象,并管理到IoC容器中。
语法:
主要是确定扫描的位置,即基准包
2.3 示例:基于组件类型的注解,来完成IoC容器的对象实例化
1.
新建Maven工程s07;
在工程的配置文件pom.xml
中,引入如下依赖:
2.
新建Spring的配置文件applicationContext.xml
:
利用注解配置IoC容器时,一些基础配置还是要写在XML文件中,并不是完全摆脱它。
加入官网的格式头:基于注解的schema
相比于之前基于XML的schema,基于注解的schema多了一个context的命名空间:
就像Java中的包名,是为了区分重名的类一样;这里context的命名空间,是为了区分重名的bean。
注意标签context:component-scan
的含义:
不需要再增加bean标签了,而只需一句话,设置基准包的名称即可
即:在applicationContext.xml
中,加载读取上述属性文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<!--在IoC容器初始化时,自动扫描四种组件类型的注解,并完成实例化
@Component @Controller @Service @Repository-->
<context:component-scan base-package="com.imooc"/>
</beans>
新建包,必须是以com.imooc
开头的:
在com.imooc.spring.ioc
下,新建四个包:
3.分别在上述包中创建对应的类:
(1)
在dao包下,新建类UserDao
,用于用户表的增删改查:
bean对象总要有一个beanId:组件类型的注解,beanId默认是类名的首字母小写。
package com.imooc.spring.ioc.dao; // 类名的前缀是以com.imooc开头的,所以能扫描到
import org.springframework.stereotype.Repository;
@Repository // beanId默认是userDao
public class UserDao {
}
也可以人为指定beanId:
package com.imooc.spring.ioc.dao; // 类名的前缀是以com.imooc开头的,所以能扫描到
import org.springframework.stereotype.Repository;
@Repository("udao") // 人为指定beanId
public class UserDao {
}
新建应用入口类SpringApplication
,加载XML文件以初始化IoC容器:
public class SpringApplication {
public static void main(String[] args) {
// 加载XML文件以初始化IoC容器
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// 获取到容器内所有有效的beanId,返回一个数组
String[] ids = context.getBeanDefinitionNames();
for (String id : ids) {
System.out.println(id + ":" + context.getBean(id));
}
}
}
问题1:
这里不用确定对象的类型?
当默认beanId时,结果为:
userDao:com.imooc.spring.ioc.dao.UserDao@4b53f538 // 默认beanId,是userDao,是UserDao类的实例化对象
当人为指定beanId时,结果为:
udao:com.imooc.spring.ioc.dao.UserDao@4b53f538 // 人为指定beanId,即udao生效了,也是UserDao类的实例化对象
实际的工作场景,常使用的是默认beanId。因为这样所有的开发人员,都遵循了统一的标准,不用额外相互询问。
(2)
在service
包中,新建类UserService
,即用户的业务逻辑类:
简单补上一个@Service
,就会自动完成IoC容器的对象实例化与管理的工作,确实清爽简便:
package com.imooc.spring.ioc.service;
@Service
public class UserService {
}
(3)
在controller
包中,新建类UserController
,即用户控制器:
常用于Web领域,目前未搭建web环境,所以只简单演示下:
package com.imooc.spring.ioc.controller;
@Controller
public class UserController {
}
(4)
在utils
包中,新建类StringUtils
:
因为也包含了被IoC管理的对象,但是它却没有明确的分类:
package com.imooc.spring.ioc.utils;
@Component // 所以,使用通用注解
public class StringUtils {
}
同理,上述四类注解,都可以自定义beanId。
运行下,结果为:
userController:com.imooc.spring.ioc.controller.UserController@382db087
userDao:com.imooc.spring.ioc.dao.UserDao@73d4cc9e
userService:com.imooc.spring.ioc.service.UserService@80169cf
stringUtils:com.imooc.spring.ioc.utils.StringUtils@5427c60c
4.
上述的bean对象,是单例还是多例?
单例。因为只有是单例,才会在IoC容器初始化的过程中,进行创建。如果是多例,则会延迟到getbean或对象注入时创建。
三、基于注解2:装配注解
目的:自动的为某个属性注入数据。
3.1 分类:2个
@Autowired
是Spring自家定义的,其他的三个是JSR规范的,是Java的行业标准- 不推荐使用按类型装配,建议使用强大的
@Resource
- 上述两者,都是不依赖set方法,完成属性注入,而是通过反射技术,将属性的修饰符从private改为public,最后改回private
Autowired:
wire=line,自动连线的
Resource:
a stock or supply of money, materials, staff, and other assets that can be drawn on by a person or organization in order to function effectively
相比之下,以前的基于XML的依赖注入:
在book-shop
工程中:
3.2 放置装配注解Autowired
的两种位置
1.如果装配注解放在属性上
MVC都是分层,且必须逐层调用。
结果为什么没有setter方法?
将UserDao的属性uDao的值,通过getter方法提取出来:
确实能成功提取出来,说明已经完成了属性注入。但是,为啥没调用setter方法呢?
2.如果装配注解放在set方法上
调整注解@Autowired
的位置,放到setter方法上:
既完成了属性注入,又调用了setter方法
3.比较不同
比较 | 如果装配注解放在属性上 | 如果装配注解放在set方法上 |
---|---|---|
就不再执行set方法 | 会执行set方法,对set方法的参数进行注入 (自动按类型/名称) | |
原理 | 运行时动态完成:Spring通过反射技术,将属性的修饰符从private改为public,这样外界可以直接对该属性赋值 | |
多数常用 | 通常不用 |
接下来,基于多数常用的装配注解放在属性上,来进行属性注入,进行介绍。
3.3 装配注解Autowired
:按类型class匹配,来属性注入,不推荐
1.
在dao包下,新建接口IUserDao
,这是所有UserDao
类都要实现的接口:
public interface IUserDao {
}
@Repository()
public class UserDao implements IUserDao { // 实现上述接口
public UserDao() {
System.out.println("正在创建UserDao:" + this);
}
}
与此同时,因为有了接口,按照面向对象编程理念,属性类型就应该从具体的类,变为接口:
@Service
public class UserService {
// @Autowired
// private UserDao uDao; // 属性类型原先是具体的类
@Autowired
private IUserDao uDao; // 属性类型就应该从具体的类,变为接口
public UserService() {
System.out.println("正在创建UserService:" + this);
}
public IUserDao getuDao() {
return uDao;
}
}
2.
如果原有的UserDao,是基于MySQL进行的开发;但是,随着技术发展,公司的数据要迁移到其他数据库,比如Oracle等,那么:
首先想到的是,是基于接口,再创建一个新的实现类UserOracleDao
:
建一个新的实现类`UserOracleDao`@Repository
public class UserOracleDao implements IUserDao { // 新建一个新的实现类`UserOracleDao`
public UserOracleDao(){
System.out.println("正在创建UserOracleDao" + this);
}
}
此时,程序运行就会报错:
原因:因为装配注解Autowired
,是按类型来寻找匹配的
NoUniqueBeanDefinitionException: No qualifying bean of type 'com.imooc.spring.ioc.dao.IUserDao' available: expected single matching bean but found 2: userDao,userOracleDao
即:
3.
解决:
方式1:把UserDao
的@Repository()
注解,去掉:
暴力,你先写别实例化对象了
方式2:通过引入额外的注解@Primary
,来表示:如果有多个相同类型的对象就特指某一个对象
顾虑:开发新的类时,程序员还要考虑是否会出现类型冲突的情况。
上述根源:出现了多个相同类型(接口类型也算类型)的对象。稍不注意,就会出错。
3.4 装配注解@Resource
:按名称name匹配,来属性注入,推荐
1.用法
很智能:优先按名称装配,如果匹配不到,再去按照类型装配。具体为:
注解@Resource
的规则:
1.如果该注解人为设置了name属性,则按照name在IoC容器中寻找对应的bean,完成属性注入;如果没找到对应的bean,就会报错
2.如果该注解没有设置name属性:
2.1 默认的,以属性名作为bean name,在IoC容器中进行匹配,完成属性注入;
2.2 如果属性名找不到,只能按照兜底的类型匹配,同@Autowired
,必要时加入@Primary
来解决类型冲突
推荐:使用1或2.1,用的都挺多,但是尽量避免使用2.2类型匹配。
2.示例
新建DepartmentService
,提供与部门相关的业务方法:
方式1:
@Service
public class DepartmentService {
@Resource(name = "userOracleDao") // 人为设置了name属性
private IUserDao uDao; //部门,会涉及员工信息的操作
}
方式2:
规范属性的命名
3.试验
这印证了,2.1:默认的,以属性名作为bean name
四、基于注解3:元数据
作用:为Spring IoC容器管理对象时,提供一些辅助信息
4.1 分类:5个
4.2 演示
1.
对于@Scope
、@PostConstruct
元数据注解
@Service
@Scope("prototype") // 跟XML中的bean scope完全相同,多例模式
public class UserService {
@Autowired
private IUserDao uDao;
public UserService() {
System.out.println("正在创建UserService:" + this);
}
@PostConstruct // 跟XML中的init-method完全相同,用于属性值注入
public void init(){
System.out.println("初始化UserService对象");
}
public IUserDao getuDao() {
return uDao;
}
}
结果为:
初始化UserService对象
2.
对于@Value
元数据注解,可以这样使用:
写死在成程序中
也可以这样使用:
基于属性文件,进行调用:
(1)
新建config.properties
属性文件,代表应用程序的配置信息:
属性文件,是基于键值对的形式,且必须保证每一个key是不同的:
metaData=imooc.com
(2)
在applicationContext.xml
中,加载读取上述属性文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<!-- 通知Spring IoC容器,在初始化时加载这个属性文件-->
<context:property-placeholder location="classpath:config.properties"/>
<context:component-scan base-package="com.imooc"/>
</beans>
(3)
在需要用到这个静态数值的地方,将key放入其中:
@Service
@Scope("prototype")
public class UserService {
@Autowired
private IUserDao uDao;
@Value("${metaData}") // 将key放入其中
private String metaData;
public UserService() {
System.out.println("正在创建UserService:" + this);
}
@PostConstruct // 初始化对象=为对象的属性赋值
public void init(){
System.out.println("初始化UserService对象,metaData=" + metaData);
}
public IUserDao getuDao() {
return uDao;
}
}
结果为:
这样在运行时,就成功为属性注入了静态数据,即成功的初始化了对象。
初始化UserService对象,metaData=imooc.com
对于上述将应用程序的配置信息放于
config.properties
属性文件的写法,很常见:比如:以前连接JDBC时:
metaData=imooc.com connection.driver=xxxxx // 通过前缀,来体现其作用或范围 connection.url=xxxxx connection.username=xxxxx connection.password=xxxxx
综上所述,Spring的核心注解,已介绍完毕。
本质:注解,就是XML的一种延申。更简单、好用。摆脱了频繁切换源代码与XML配置的问题。
五、基于Java Config来配置IoC容器
java Config,是Spring 3.0 以后推出的新的配置方式。
5.1 Java Config概述
1.
本质:用Java类,来完全替代传统的XML文件。
2.
场景:敏捷开发,适合快速迭代、快速上线的工程。比如以后学习的Spring Boot就是Spring生态中进行敏捷开发的框架,默认就是基于Java Config来配置IoC容器。---------------------------------------------------------前期开发体验好
相比,XML更适合大型项目的团队协作中,切分开、各司其职。------------后期维护性好。
3.
优势:
(1)完全摆脱XML的束缚,使用独立的Java类来创建对象、管理依赖(属性赋值)
(2)能对配置进行集中创建管理:由于之前基于注解的配置形式,注解分散在每一个类中,工程一大很麻烦
(3)可在编译时进行依赖检查,不易出错:XML只有在运行时才能知道配置是否正确
缺点:写死在程序中
5.2 分类:4个
Java Config 来初始化对象的语法:
5.3 示例 :基于Java Config来实例化对象
1.
新建Maven工程s08:
在工厂的配置文件pom.xml
中,引入依赖spring-context
、阿里云镜像仓库:
2.
新建包,并创建演示用的三个Java类:
只创建类,不用实现:
新建mapper层的类UserDao
:
public class UserDao {
}
新建service层的类UserService
:
public class UserService {
private UserDao userDao; // 因为依赖UserDao,所以持有它的属性
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
新建controll层的类UserController
:
public class UserController {
private UserService userService; // 因为依赖UserService,所以持有它的属性
public UserService getUserService() {
return userService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}
3.
让上述三个类,在IoC容器初始化时,完成对象的创建、以及关联(属性赋值)。
新建一个独立的Java类Config.java
:
不要看作是工程的一部分,而是视为配置文件。
(初始化以后,代码的运行阶段,所有工程都是基于IoC容器。严格意义上,下面的new关键词的那些代码,并不是IoC管理的范畴?)
@Configuration // 表明当前类是一个配置类,用于完全替代 applicationContext.xml
public class Config {
@Bean // 通过定义一些方法,来创建对象,将方法返回的对象放入IoC容器。实例化的对象beanId=方法名
public UserDao userDao(){
UserDao userDao = new UserDao(); // 方法内部,还是new关键词的那些代码
return userDao;
}
}
新建应用入口类SpringApplication.java
public class SpringApplication {
public static void main(String[] args) {
// 基于Java Config来配置ioC容器的初始化
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
String[] ids = context.getBeanDefinitionNames();
for (String id : ids) {
System.out.println(id + ":" + context.getBean(id));
}
}
}
结果为:
成功显示两个实例化的bean对象:
config:com.imooc.spring.ioc.Config$$EnhancerBySpringCGLIB$$9ddf0940@49070868 // 用于配置的Java类Config的实例化对象
userDao:com.imooc.spring.ioc.dao.UserDao@6385cb26 // 实例化的对象beanId=方法名
在独立的Java类Config.java
中,来配置其他对象:
@Configuration // 表明当前类是一个配置类,用于完全替代 applicationContext.xml
public class Config {
@Bean // 通过定义一些方法,来创建对象,将方法返回的对象放入IoC容器。实例化的对象beanId=方法名
public UserDao userDao(){
UserDao userDao = new UserDao();
return userDao;
}
@Bean
public UserService userService(){
UserService userService = new UserService();
return userService;
}
@Bean // 这个过程,相当于XML中<bean id="xxx" class="xxx">的Java表现形式
public UserController userController(){
UserController userController = new UserController();
return userController;
}
}
结果为:
按照方法定义的先后顺序,依次进行了实例化,并以方法名作为beanId进行了管理:
config:com.imooc.spring.ioc.Config$$EnhancerBySpringCGLIB$$dd8fc29a@4d49af10
userDao:com.imooc.spring.ioc.dao.UserDao@279ad2e3
userService:com.imooc.spring.ioc.service.UserService@58134517
userController:com.imooc.spring.ioc.controller.UserController@4450d156
综上所述,是基于Java Config来实例化对象的演示。
5.4 示例 :基于Java Config来对象依赖注入
在当前的配置类中,如何实现对象间的关联,即实现service依赖dao,controller依赖service呢?
依托set方法,但是set的对象却来自于当前的IoC容器。因此,应该设置bean对应的set方法的参数。
@Configuration
public class Config {
@Bean
public UserDao userDao(){
UserDao userDao = new UserDao();
System.out.println("已创建" + userDao);
return userDao;
}
@Bean
public UserService userService(UserDao userDao) {
UserService userService = new UserService();
System.out.println("已创建" + userService);
userService.setUserDao(userDao); // 调用set方法,完成UserService中,属性userDao的赋值
System.out.println("调用setUserDao:" + userDao);
return userService;
}
@Bean
public UserController userController(UserService userService) {
UserController userController = new UserController();
System.out.println("已创建" + userController);
userController.setUserService(userService); // 调用set方法,完成属性赋值
System.out.println("调用setUserService:" + userService);
return userController;
}
}
结果为:
已完成属性的注入
已创建com.imooc.spring.ioc.dao.UserDao@1dd02175
已创建com.imooc.spring.ioc.service.UserService@16267862
调用setUserDao:com.imooc.spring.ioc.dao.UserDao@1dd02175 // 属性的注入
已创建com.imooc.spring.ioc.controller.UserController@6166e06f
调用setUserService:com.imooc.spring.ioc.service.UserService@16267862 // 属性的注入
=========================================
既然对象是运行时注入的,那么注入的过程是按照名称name注入,还是按照类型注入呢?
先按name尝试注入,name不存在则按照类型注入。
5.5 Java Config兼容注解形式
1.
其实,Java Config可以与注解形式不冲突:
比如@Primary
不仅可以用在注解类中,还可以用在Java Config配置文件中。
2.
比如:
在该工程中,除此之外,李四要开发员工mapper层的类EmployeeDao
,他习惯用注解的形式:
@Repository
public class EmployeeDao {
}
将原本注解配置IoC容器中,XML的最后利用价值也放在java类中:
标签 context:component-scan basePackages = "xxx"
,变为注解 @ComponentScan(basePackages = "xxx")
表明:在IoC容器启动时,不但会加载读取当前Config.java
类对象,还会去指定路径下扫描头上是组件类的注解的类,来实例化对象
@Configuration
@ComponentScan(basePackages = "com.imooc") // 注解形式,开启组件扫描
public class Config {
@Bean
public UserDao userDao(){
UserDao userDao = new UserDao();
System.out.println("已创建" + userDao);
return userDao;
}
@Bean
public UserService userService(UserDao userDao) {
UserService userService = new UserService();
System.out.println("已创建" + userService);
userService.setUserDao(userDao);
System.out.println("调用setUserDao:" + userDao);
return userService;
}
@Bean
public UserController userController(UserService userService) {
UserController userController = new UserController();
System.out.println("已创建" + userController);
userController.setUserService(userService);
System.out.println("调用setUserService:" + userService);
return userController;
}
}
结果为:
在IoC容器初始化时,他人李四用注解配置的bean对象,也能成功创建:
config:com.imooc.spring.ioc.Config$$EnhancerBySpringCGLIB$$40d69d8b@161b062a
employeeDao:com.imooc.spring.ioc.dao.EmployeeDao@17c1bced // 他人李四用注解配置的bean对象,也能成功创建:
userDao:com.imooc.spring.ioc.dao.UserDao@51931956
userService:com.imooc.spring.ioc.service.UserService@2357d90a
userController:com.imooc.spring.ioc.controller.UserController@15bb6bea
3.
上述创建完对象后,还可以对象的注入:
在视为配置文件的独立的Java类Config.java
中:
调用set方法,完成属性赋值
六、Spring与JUnit4整合
6.1 Spring Test:测试模块
Spring Test模块是Spring中专用于测试的模块。
最常用的功能:与JUnit4单元测试框架,进行良好整合。即通过Spring Test模块,可以在JUnit单元测试时,自动初始化IoC容器。
原理:基于注解。
6.2 Spring与JUnit4的整合过程:三步
分三步:
- 注解
@Runwith
---------------------- 将JUnit4 的运行过程交给Spring来完成,让Spring接管JUnit4 的控制权,以便完成IoC的初始化工作; - 注解
@ContextConfiguration
---用于说明,在初始化IoC容器过程中,到底要加载哪个配置文件呢?
即:共三步:
(1)在pom.xml
中,引入依赖spring-context
、junit4
(2)在新建的测试用例类中,增加两个注解,完成IoC容器的初始化工作
(3)在测试用例类中,用@Resource
,注入我们需要的属性。并在测试用例的的方法中,验证代码执行是否正确。
6.3 示例
1.
新建Maven工程s09:
在工程的配置文件pom.xml
中,引入依赖spring-context
、阿里云镜像仓库,以及新的依赖spring-test
:
新建applicationContext.xml
配置文件,增加官方的格式头schema:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
</beans>
2.
新建测试类:
在包com.imooc.spring.ioc.dao
中,新建mapper层的类UserDao.java
public class UserDao {
public void insert(){
System.out.println("新增用户数据");
}
}
新建service层的类UserService.java
public class UserService {
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void createUser(){
System.out.println("调用创建用户的业务代码");
userDao.insert();
}
}
在applicationContext.xml
配置文件中,进行配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="userDao" class="com.imooc.spring.ioc.dao.UserDao">
</bean>
<bean id="userService" class="com.imooc.spring.ioc.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
</beans>
3.
对上述代码,进行测试:
以前:创建一个应用入口类SpringApplication.java
现在:复杂场景下,需要多个测试用例,此时 JUnit就排上用场了
在工程的配置文件pom.xml
中,再引入依赖junit
:
在包test|java
中,新建测试类SpringTestor
// 将JUnit4的执行权交由Spring,在测试用例执行前,自动的初始化IoC容器
@RunWith(SpringJUnit4ClassRunner.class) // SpringJUnit4ClassRunner是引入依赖spring-test中最核心的类
@ContextConfiguration(locations = {"classpath:applicationContext.xml"}) // 通知IoC容器,要加载读取哪个配置文件
public class SpringTestor {
// 如何使用?就假设这个测试类在运行时,IoC容器已初始化完毕、已经提前准备好了:即根据上述配置文件,创建对象,对象依赖注入都已完成。
@Resource
private UserService userService;
@Test // 在测试用例中,直接调用业务方法即可
public void testUserService(){
userService.createUser();
}
}
结果为:
调用创建用户的业务代码
新增用户数据
上述测试用例,其实是在IoC容器内部运行的。
在测试类SpringTestor
创建好以后,会自动的注入userService
对象。当然,userService
对象在IoC容器初始化过程中,就已经准备好了。
在测试用例中,直接调用业务方法即可。
综上所述,Spring Test:测试模块的使用,为承上启下。后续仍会频繁使用。
Comments | NOTHING