Spring-IOC案例及单元测试
Spring-IOC案例的两种配置,xml 配置,和注解配置
一:使用 xml 配置链接数据库
<!--配置Service -->
<bean id="userService" class="huarangmeng.service.impl.UserServiceImpl">
<!--注入Dao对象 -->
<property name="userDao" ref="userDao"></property>
</bean>
<!--配置Dao -->
<bean id="userDao" class="huarangmeng.dao.impl.UserDaoImpl">
<!--注入QueryRunner -->
<property name="runner" ref="runner"></property>
</bean>
<!--配置QueryRunner -->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源 -->
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!--配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--链接数据库的必备信息 -->
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="test"></property>
<property name="password" value="a123456789"></property>
</bean>
二:通过注解配置
QueryRunner为jar包中的字节码,无法直接通过注解配置
数据源同样
因而需要一个注解类来解决
/**
* 该类是一个配置类,它的作用和bean.xml是一样的
* spring中的新注解
* @Configuration
* 作用:指定当前类是一个配置类
* 细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写
* @ComponentScan
* 作用:用于通过注解指定spring在创建容器时要扫描的包
* 属性:
* value:他和basePackages的作用时一样的,都是用于指定创建容器时要扫描的包
* 我们使用此注解就等同于在xml中配置了
* <context:component-scan base-package="huarangmeng"></context:component-scan>
* @Bean
* 作用:用于把当前方法的返回值作为bean对象存入spring的IOC容器中
* 属性:
* name:用于指定 bean 的 id。默认值为 当前方法的名称.
* 细节:当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找是否有可用的bean对象
* 查找的方式与 @Autowired注解的作用相同
* @Import
* 作用:用于导入其他的配置类
* 属性:value:用于指定其他配置类的字节码。
* 当我们使用 @Import注解后,有@Import注解的类就是父类配置,而导入的就是子配置类
*
* @PropertySource
* 作用:用于指定properties文件的位置
* 属性:
* value:指定文件的名称和路径
* 关键字:classpath:表示类路径
*/
@Configuration
//@ComponentScan(basePackages = {"huarangmeng"}) 两种都可以
@ComponentScan("huarangmeng")
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbc.properties")
public class SpringConfiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 用于创建一个QueryRunner对象
* @param dataSource
* @return
*/
@Bean(name = "runner")
@Scope("prototype")
public QueryRunner creteQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
/**
* 创建数据源对象
* @return
*/
@Bean(name = "dataSource")
public DataSource creteDataSource(){
try{
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
举例说明 @Configuration 和 @ComponentScan,引入@Import 注解
- 当配置类作为 AnnotationConfigApplicationContext 对象创建的参数时,@Configuration注解可以不写
倘若有两个配置类,分别为 SpringConfiguration.class 和 JdbcConfig.class,直接作为参数,可不使用@Configuration注解,两个类可当作兄弟关系
//1.获取容器
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class,JdbcConfig.class);
//2.得到业务层对象
IUserService us = ac.getBean("userService", IUserService.class);
// JdbcConfig注解类
public class JdbcConfig {
}
// SpringConfiguration注解类
public class SpringConfiguration {
}
-
希望 SpringConfiguration.class 和 JdbcConfig.class 作为父子关系时
//1.获取容器 ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class); //2.得到业务层对象 IUserService us = ac.getBean("userService", IUserService.class); // 第一种做法,给JdbcConfig类添加 @Configuration注解 //给SpringConfiguration中添加扫描JdbcConfig的注解 @Configuration public class JdbcConfig { } // SpringConfiguration注解类 @ComponentScan("huarangmeng") public class SpringConfiguration { } //第二种做法,给SpringConfiguration中添加@Import注解 public class JdbcConfig { } // SpringConfiguration注解类 @Import(JdbcConfig.class) public class SpringConfiguration { }
三:Spring中的单元测试
直接使用JUnit进行单元测试,存在问题,以下第一步和第二步,每个测试方法都要写,且要求测试同学有学过spring才会写出相应的代码
@Test public void testFindAll(){ //1.获取容器 // ApplicationContext ac = new ClassPathXmlApplicationContext("dao.xml"); ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class); //2.得到业务层对象 IUserService us = ac.getBean("userService", IUserService.class); //3.执行方法 List<User> users = us.findAllUser(); for (User user: users) { System.out.println(user); } }
解决每个测试方法都要写前两步的问题
private ApplicationContext ac; private IUserService us; @Before public void init(){ // 1.获取容器 // ApplicationContext ac = new ClassPathXmlApplicationContext("dao.xml"); ac = new AnnotationConfigApplicationContext(SpringConfiguration.class); // 2.得到业务层对象 us = ac.getBean("userService", IUserService.class); } @Test public void testFindAll(){ //3.执行方法 List<User> users = us.findAllUser(); for (User user: users) { System.out.println(user); } }
仍然存在相应的代码需要写,则使用spring-test包解决问题
为什么不能直接使用注解注入 IUserService,原因是 JUnit 下没有spring的IOC容器
/** * 使用JUnit单元测试,测试我们的配置 * spring整合junit配置 * 1.导入spring整合junit的jar包 * 2.使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的 * @RunWith * 3.告知spring 的运行期,spring的IOC容器创建时基于 xml 还是注解的,并说明位置 * @ContextConfiguration * location:指定xml文件的位置,加上classpath关键字,表示在类路径下 * classes:指定注解类所在的位置 * 当我们使用spring 5.X版本时,要求Junit的jar版本必须是4.12及以上 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfiguration.class) public class UserServiceTest { @Autowired private IUserService us; @Test public void testFindAll(){ //3.执行方法 List<User> users = us.findAllUser(); for (User user: users) { System.out.println(user); } } }