Spring IOC
IOC(Inversion of Control),译作反转控制,其功能是将类之间的依赖转移到外部的配置文件中, 避免在调用类中硬编码实现类,因此也被称作依赖注入(Dependency Injection)。在以往的开发中, 通常利用工厂模式(Factory)来解决此类问题,其实不管是工厂模式还是依赖注入,调用类与实现类不可 能没有任何依赖,工厂模式中工厂类通常根据参数来判断该实例化哪个实现类,Spring IOC将需要实例的 类在配置文件文件中配置。使用Spring IOC能得到工厂模式同样的效果,而且编码更加简洁。看段代码比较 一下:
一、用工厂模式来实现
例 1.1. Product.java
public interface Product { public void execute();} 例 1.2. ConcreteProductA.java
public class ConcreteProductA implements Product{ public void execute() { ... }} 例 1.3. ConcreteProductB.java
public class ConcreteProductB implements Product{ public void execute() { ... }} 例1.4. Factory.java
public class Factory{ public Product CreateProduct(object param) { return ConstructObjects(param); } private Product ConstructObjects(object param) { ... }} 例 1.5. Client.java(调用类)
public class Client{ public Client() { //实例化ConcreteProductA Product product = Factory.CreateProduct(paramA); //实例化ConcreteProductB Product product = Factory.CreateProduct(paramB); ... }} 在ConstructObjects方法中设定实例化实现类的逻辑,这样对于调用类来说,不直接实例化实现类,纵然实现类发生变化, 调用代码仍然可以不作修改,给维护与扩展带来便利。
二、Spring IOC实现
例 1.6. SpringConfig.xml
<bean id="productA" class="ConcreteProductA" /><bean id="productB" class="ConcreteProductB" /> 例 1.7. Client.java(调用类)
public class Client{ public Client() { //实例化ConcreteProductA Product product = (Product)InitSpring.getObject("productA"); //实例化ConcreteProductB Product product = (Product)InitSpring.getObject("productB"); ... }} 调用代码中没有硬编码实现类,比较工厂模式,少了Factory类。
Spring为依赖注入提供三种实现方式:接口注入、设值注入、构造注入。利用这些可以灵活的解决 类之间的依赖关系,让你为所欲为的组装代码。与其说Spring IOC是一个工具,还不如说搭建了一 个思想的舞台。继续看代码:
来实现一个操作多个数据源的切换
例 1.8. DataSource.java
public class DataSource{ private String driverClassName; private String url; private String username; private String password; public String getDriverClassName() { return this.driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getUrl() { return this.url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return this.Username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return this.password; } public void setPassword(String password) { this.password = password; }} 例 1.9. DataAccessor.java
public class DataAccessor{ private DataSource dataSource; public void setDriver(DataSource dataSource) { this.dataSource = dataSource; } public void save(String sql) { Statement s = getStatement(); try { s.getConnection().setAutoCommit(false); int rows = s.executeUpdate(sql); s.getConnection().commit(); } catch(Exception e) { s.getConnection().rollback(); ... } finally { ... } } private Statement getStatement() { Statement s; try { Class.forName(dataSource.getDriverClassName()).newInstance(); java.sql.Connection conn = java.sql.DriverManager.getConnection(dataSource.getUrl(),dataSource.getUser(),dataSource.getPassword()); try { s = c.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); } } catch(Exception e) { ... } return s; }} 例 1.10. BussinessA.java
public class BussinessA{ private DataAccessor dao; public void setDao(DataAccessor dao) { this.dao = dao; } public void execute() { dao.save("insert into tb1 ..."); }} 例 1.11 BussinessB.java
public class BussinessB{ private DataAccessor dao; public void setDao(DataAccessor dao) { this.dao = dao; } public void execute() { dao.save("insert into tb2 ..."); }} 全部代码就这样了,执行BussinessA.java、BussinessB.java代码即可完成数据插入操作,从代码中看, 这两个类具体操作的是什么数据库?什么样的操作细节?让你失望了,代码中找不到这样的关联,看配置文件吧:
例 1.12. SpringConfig.xml
<bean id="dataSourceA" class="DataSource" destroy-method="close"> <property name="driverClassName"><value>org.gjt.mm.mysql.Driver</value></property> <property name="url"> <value>jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=GBK</value> </property> <property name="username"><value>root</value></property> <property name="password"><value></value></property> </bean> <bean id="dataSourceB" class="DataSource" destroy-method="close"> <property name="driverClassName"><value>org.gjt.mm.mysql.Driver</value></property> <property name="url"> <value>jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=GBK</value> </property> <property name="username"><value>root</value></property> <property name="password"><value></value></property> </bean><bean id="daoA" class="DataAccessor"> <property name="dataSource"> <ref local="dataSourceA"/> </property></bean><bean id="daoB" class="DataAccessor"> <property name="dataSource"> <ref local="dataSourceB"/> </property></bean><bean id="bussinessA" class="BussinessA"> <property name="dao"> <ref local="daoA"/> </property></bean><bean id="bussinessB" class="BussinessB"> <property name="dao"> <ref local="daoB"/> </property></bean> 看完配置文件应该明白了,这里承担了所有的依赖关系。
首先,我们通过设值注入方法设置数据源相关参数
然后,我们将数据源实例注入给数据访问类
最后,我们为每个具体业务类注入相应访问器
是不是感觉想玩积木似的,在组装你的代码?
例 1.13. DaoTest.java
public void testSave(){ BussinessA bussinessA = (BussinessA)InitSpring.getObject("bussinessA"); bussinessA.execute(); bussinessB bussinessB = (BussinessB)InitSpring.getObject("bussinessB"); bussinessB.execute();} 执行这段测试代码,数据库Test1、Test2中tb1、tb2表将分别插入对应的数据,从实现代码来看操作多个数据库和 操作一个数据库完全一样,即使当数据源,数据访问类不断变化,应用代码也可以做到不用任何修改。
希望看完本章节的内容能让读者与我共鸣,Spring IOC是一种优雅的思想,借助它发挥你无穷的想象吧。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lip8654/archive/2007/04/30/1592637.aspx