疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Spring实现的两个核心技术


 

        1) Spring简介

  Spring是一个全方位的应用程序开发框架(framework),是潜在的一站式解决方案,它定位于与典型应用相关的大部分基础结构。自从2003年发布以来,Spring Framework已经对Java企业应用体系产生了前所未有的冲击,尽管历史不长,但它拥有深厚的历史根基。如今Spring已风靡全球,甚至有取代EJB的趋势,最新的EJB3.0规范也吸取了Spring的设计理念,如今这陈风也刮到了华为公司,越来越多的项目正在使用或准备使用Spring架构开发,所以有关Spring架构下的单元测试如何做是我们必须面对的问题。简单说来,Spring有以下特性:

  u 轻量级

  相对于一些重量级的EJB容器,Spring的核心包在文件容量上只有不到1MB的大小,而使用Spring核心包所需要的资源负担也是很小的。

  u 非侵入性

  就是说你的开发对Spring的依赖很小,只需要较少的Spring API调用,甚至你的对象完全感知不到Spring容器的存在,提高了对象在不同容器环境下移植的可能性。

  u 完全开放性

  Spring并不排斥已有的软件结构,如Struts、EJB、Hibernate等,能够将已有系统很好地集成进Spring。

  2) Spring实现的两个核心技术

  u IoC—Inversion of Control

  中文翻译为控制反转,在Spring里的实现是Dependency Injection(依赖注入),就是说对象之间的依赖关系在后期通过配置文件(典型为XML文件)生成, Spring里实现了两种注入方式:构造函数注入、Setter方法注入。我们可以这样理解这种技术带来的好处,前期我们只需要关注单个对象(组件)的功能实现,具体的业务实现是通过后期配置出来的,不同的配置可以产生不同的业务功能。

  u AOP—Aspect-oriented programming

  面向方面的编程,但我觉得翻译为面向切面的编程更容易理解一些。AOP大大降低了对象之间的耦合程度,与IoC一样,能够通过后期的配置动态为对象增加新的特性,甚至能够为对象动态增加方法。在Spring下,AOP的实现不需要借助专门的AOP定义语言,只需要普通的Java对象和XML配置文件即可。

  3) Spring提供的单元测试支持

  首先要说明的是,在Spring里将单元测试的对象理解为一个孤立的单元,单元依赖的对象用桩取代。但考虑到业软的开发现状,如果对象功能逻辑简单,我们将多个对象的组合作为一个被测单元(在Spring里理解为集成测试),典型的情况如对访问数据库代码的测试。

  Spring架构带来的直接好处是对象之间的松耦合,减少了对象之间的依赖,这为我们做单元测试提供了便利,另外Spring基于JUnit提供了单元测试支持,实现包为spring-mock.jar。Spring基于Junit的TestCase类实现了两个子类:AbstractDependencyInjectionSpringContextTests、AbstractTransactionalSpringContextTests。下面我们分别讲解这两个类的使用。

  u AbstractDependencyInjectionSpringContextTests

  AbstractDependencyInjectionSpringContextTests 继承自JUnit的TestCase,所以写测试用例的方法与以前相同。Spring下的对象之间的关系是通过XML配置文件生成的,在运行时根据XML中的配置生成对象及对象之间的关系,形成Spring上下文件环境(Application Context),做单元测试时也一样,我们基于类AbstractDependencyInjectionSpringContextTests生成测试用例时需要实现方法getConfigLocations,告诉Spring你的XML配置文件在哪儿,如下所示:

  @Override

  protected String[] getConfigLocations()

  {

  returnnew String[]{"file:D:/workspace321/example/beans-config.xml"};

  }

  在每个用例运行前都生成一次Spring上下文势必会影响性能,Spring在不同的用例执行间提供Spring上下文缓存功能。另外基类提供protected的applicationContext对象,方便你访问上下文环境,如get一个Bean等。

  另外,对于被测的对象可以通过依赖注入,不需要你在测试代码中显式创建,如下例所示:

  publicclass UserDaoTest2 extends AbstractDependencyInjectionSpringContextTests

  {

  // 这个实例将被(自动的)依赖注入

  private UserDao userDao;

  // 依赖注入的Setter方法

  publicvoid setUserDao(UserDao userDao)

  {

  this.userDao = userDao;

  }

  publicvoid testInsert()

  {

  User user = new User();

  user.setId(1);

  user.setName("tzs");

  user.setAge(32);

  userDao.insert(user);

  }

  @Override

  protected String[] getConfigLocations()

  {

  returnnew String[] { "file:D:/workspace321/example/beans-config.xml" };

  }

  }

  在beans-config.xml文件中需要定义你的被测对象:

  Spring根据类型匹配原则(类型是UserDao)自动将userDao对象注入到测试用例对象中。

  u AbstractTransactionalSpringContextTests

  AbstractTransactionalSpringContextTests继承自AbstractDependencyInjectionSpringContextTests,提供事务支持功能,主要用于我们针对访问数据库代码的测试,它的最大特点是在每一个用例执行前开始一下事务,在用例执行结束后对事务回滚,也就是说用例执行期间对数据库的操作在执行结束后回退到最初的状态,用例之间的数据库环境互不影响。前面的代码基类换成AbstractTransactionalSpringContextTests,其它什么都不变,即可实现事务支持。

  4) Spring如何与DBUnit结合

  由于Java不可以同时继承自两个基类,所以我们的用例类不可能同时继承自DBTestCase和AbstractTransactionalSpringContextTests,但我们在“DBUnit数据库测试工具”一节最后提到也可以不需要继承自DBTestCase也能完成数据库的测试,所以为使用DBUnit功能,我们在Spring中也采用此种方式。但要注意的是为了能将DBUnit对数据库的操作纳入Spring的事务支持,不能直接从dataSource获得connection,而要通过DataSourceUtils提供的静态方法间接地获取,最后要记得将connection释放。请参见以下的例子:

  publicclass UserDaoTest3 extends AbstractTransactionalSpringContextTests

  {

  private UserDao userDao;

  publicvoid setUserDao(UserDao userDao)

  {

  this.userDao = userDao;

  }

  publicvoid testInsert() throws Exception

  {

  Connection jdbcConnection = null;

  DataSource dataSource = (DataSource)applicationContext.getBean("dataSource");

  //获得connection对象

  jdbcConnection = DataSourceUtils.getConnection(dataSource);

  IDatabaseConnection connection = new DatabaseConnection(jdbcConnection,"TZS21911");

  //以下代码用于执行前的数据库初始化

  IDataSet dataSet = new FlatXmlDataSet(new FileInputStream(

  "dataset.xml"));

  DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);

  //以下代码执行具体的测试

  User user = new User();

  user.setId(5);

  user.setName("tzs");

  user.setAge(35);

  userDao.insert(user);

  //以下代码用于执行后的数据库验证

  IDataSet databaseDataSet = connection.createDataSet();

  ITable actualTable = databaseDataSet.getTable("users");

  IDataSet expectedDataSet = new FlatXmlDataSet(new File(

  "expectedDatasetInsert.xml"));

  ITable expectedTable = expectedDataSet.getTable("USERS");

  Assertion.assertEquals(expectedTable, actualTable);

  //记得要释放connection

  DataSourceUtils.releaseConnection(jdbcConnection, dataSource);

  }

  @Override

  protected String[] getConfigLocations()

  {

  returnnewString[] { "file:D:/workspace321/example/beans-config.xml" };

  }

  }

  通过以上将Spring与DBUnit的结合,我们既能实现用例执行前的数据库初始化以及执行后的数据库验证,也能避免用例执行中对数据库环境的影响,做到用例间数据库环境互不影响。

  疯狂java培训机构专注java培训,打造一流的java培训机构,一流的技术人才,疯狂java拥有强大的教师队伍,部分疯狂java老师还是疯狂java系列图书的作者,如此知识技术沉淀深厚的老师,带领你走进编程,激发你对编程的热爱,大量全真的企业项目训练,全面提高你的动手实践能力,同时掌握8-10万的代码量,达到经理级的代码量,成为社会最急需的技术人才,给自己做一个最明智的选择,参加疯狂java培训,通过短短的几个月的培训,华丽转身高级java工程师,还等什么?梦想在向你招手,赶快行动吧!想了解更多,欢迎登陆疯狂java官网http://www.fkjava.org抢座热线:020-28309358 020-28309378咨询QQ:707552864 , 544627560,我们都将为你一一回答。