什么是Spring
Spring是一个轻量级的,非注入式的框架。其目标是使应用程序对框架的依赖最小化,应用代码可以在没有Spring或者其他容器的情况下运行。
Spring的特点
①轻量级(Lightweight)
Spring 核心包容量不到1MBde 大小,可以在很多小型设备中使用Spring
②非侵入性(No intrusive)
增强应用程序组件的可重用性,减少对框架的依赖
③容器(Container)
根据配置文件自动生成对象及属性等,不用编写任何代码来产生对象
④Inversion of Control(IOC控制反转)与Dependency Injection(DI依赖注入)
IOC目的就是依赖于抽象;对象之间的关系由容器根据配置文件将依赖
注入指定的对象中
⑤AOP(Aspect-oriented programming)
基于代理及拦截器的机制,与Spring IOC 结合,采用运行时Weaving方式在
Spring框架的应用程序中使用各种声明式系统级服务。
⑥持久层(Persistent)
Spring提供DAO、编程事务与声明式事务,对于ORM工具(Hibernate、iBATIS)的整合及使用上简化。
Spring中两个重要的思想便是Inversion of Control(IOC控制反转)与Dependency Injection(DI依赖注入),下面谈谈对这两个思想的理解。
IOC控制反转的理解
如果一个类的合作对象的引用或依赖关系的管理由具体的对象来完成,会导致代码的耦合度和可测试性降低,这对面向对象系统的设计是非常不利的。控制反转就是,这些依赖关系通过把对象的依赖注入交给框架或者IOC来完成。
如有一个类FloppyWriter(底层模块)代表向软盘写入东西和一个类 Business(高层应用)要使用FloppyWriter的方法向软盘写入东西,那么
class FloppyWriter
{
void saveToFloppy()
{
……
}
}
public class Business{
private FloppyWriter writer=new FloppyWriter();
public void save()
{
writer.saveToFloppy();//依赖于底层模块
}
}
直接在高层的应用程序中调用底层模块的API,导致应用程序对底层模块产生的依赖…
那么有一个问题:如果使用USB作为存储介质,该应用程序无法直接重用,需要修改。导致由于
底层模块的变化,造成高层的应用程序跟着变化。
为了解决上面的问题。可以对类进行如下改造,
public interface IDeviceWriter //接口,向设备写入
{
public void saveToDevice();
}
public class FloppyWriter implement IDeviceWriter
{
public void saveToDevice()
{
//实际存储在软盘
}
}
public class Business{
private IDeviceWriter writer;
public void setDeviceWriter (IDeviceWriter writer)
{
this.writer=writer;
}
public void save()
{
writer.saveToDevice();
}
}
主程序:
Business bus=new Business();
bus.setDeviceWriter(new FloppyWriter());
bus.save();
//思考此时如果要向U盘写入文件怎么办,很简单建一个类USBWriter并实现save方法,并将主程序改为bus.setDeviceWriter(new FloppyWriter());
public class USBWriter implement IDeviceWriter{
public void saveToDevice(){
//实际存储在U盘
}
}
依赖关系的转移,高层模块不依赖于底层模块,必须依赖于抽象,实现必须依赖于抽象,而不是抽象依赖于实现。可以看到,无论底层的存储实现如何变动,对于Business类来说无须做任何修改。
DI依赖注入的理解
保留抽象接口,让组件依赖于抽象接口。当组件要与其他实际的对象发生依赖关系时,由抽象接口来注入依赖的实际对象。
有三种实现方式。
①Type 1 IoC:Interface injection(接口注入)
②Type 2 IoC: Setter injection(推荐使用)(setter方法注入)
③Type 3 IoC: Constructor injection(构造方法注入)
Type 1 IoC
public interface IDependency
{
//在接口中声明注入方法
public void saveToDevice(Map device);
}
public class Business implement IDependency
{
private Map device;
public void saveToDevice(Map device)
{
this.device=device;//实现Business关系依赖
}
}
使用该方式会要求实现接口,对象所在的容器也会使用这个接口,容器知道接口上的所有方法,所以可调用实现接口的对象完成依赖关系的注入!
依赖的接口越多,程序的侵入性越强,组件的重用性降低
Type 3 IoC
public class Business{
public IDeviceWriter writer;
public Business(IDeviceWriter writer)
{
this.writer=writer;
}
public void save()
{
writer.saveToDevice();
}
//主程序
Business bus=new Business(new FloppyWriter());
bus.save();
使用该方式注入,可以在构造对象的同时,一并建立依赖关系,但如果依赖关系很多需要构造的参数很多,使用Type 2 IoC较为方便。
Type 2 IoC(重点,Spring的IOC容器)
//先实现接口
public interface IDeviceWriter //接口,向设备写入
{
public void saveToDevice();
}
//实现各个存储设备的写入
public class FloppyWriter implement IDeviceWriter
{
public void saveToDevice()
{
//实际存储在软盘
}
}
public class USBWriter implement IDeviceWriter
{
public void saveToDevice(){
//实际存储在U盘
}
}
//实现business类
public class Business{
private IDeviceWriter writer;
public void setDeviceWriter (IDeviceWriter writer)
{
this.writer=writer;
}
public void save()
{
writer.saveToDevice();
}
}
//实现businessFactory工厂类获得business单例
public class businessFactory
{
private static businessFactory factory;
private Properties props;//通过属性文件读取包名
private Business bus;
private IDeviceWriter writer;
businessFatory()
{
//在此实现通过属性文件获得包名并实现依赖注入
bus=(Business)(Class.forName...);
writer=(IDecviceWriter)(Class.forName...);
bus.setWriter(writer);//完成注入
}
}
//实现主程序
public class BusinessExample
{
//主函数
main
{
BusinessFactort bus=new BusinessFactory();
}
}
如果使用了Type 2 IoC,需要改变写入的存储方式,如FloppyWriter 改为USBWriter,只需改变属性文件。但是Spring的为xml文件,原理是一样的。
如果有什么不懂欢迎评论。