Spring概述

  Spring框架可以说是java世界最为成功的框架,在实际企业应用中,绝大部分企业架构都基于Spring框架。它的成功来自于理念,它最核心的理念是IoC(控制反转)和AOP(面向切面编程),其中IoC是Spring的基础,而AOP则是其重要的功能,最为典型的当属数据库事务的使用。可以说Spring框架已经融入到java EE开发的各个领域。

Spring历史

   Rod Johnson在2002年编著的《Expert one on one J2EE design and development》一书中,对Java EE 系统框架臃肿、低效、脱离现实的种种现状提出了质疑,并积极寻求探索革新之道。以此书为指导思想,他编写了interface21框架,这是一个力图冲破J2EE传统开发的困境,从实际需求出发,着眼于轻便、灵巧,易于开发、测试和部署的轻量级开发框架。Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。同年他又推出了一部堪称经典的力作《Expert one-on-one J2EE Development without EJB》,该书在Java世界掀起了轩然大波,不断改变着Java开发者程序设计和开发的思考方式。在该书中,作者根据自己多年丰富的实践经验,对EJB的各种笨重臃肿的结构进行了逐一的分析和否定,并分别以简洁实用的方式替换之。至此一战功成,Rod Johnson成为一个改变Java世界的大师级人物。

  传统J2EE应用的开发效率低,应用服务器厂商对各种技术的支持并没有真正统一,导致J2EE的应用没有真正实现Write Once及Run Anywhere的承诺。Spring作为开源的中间件,独立于各种应用服务器,甚至无须应用服务器的支持,也能提供应用服务器的功能,如声明式事务、事务处理等。

  Spring致力于J2EE应用的各层的解决方案,而不是仅仅专注于某一层的方案。可以说Spring是企业应用开发的“一站式”选择,并贯穿表现层、业务层及持久层。然而,Spring并不想取代那些已有的框架,而是与它们无缝地整合。

Spring特点(策略)

  轻量——对于POJO的潜力开发,提供轻量级和低侵入的编程,可以通过配置(xml、注解等)来扩展POJO的功能,通过依赖注入的理念去扩展功能;通过接口编程,强调OOD的开发模式理念,降低系统的耦合度,提高系统的可读性和可扩展性

  面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。使得开发人员把精力更加集中于业务开发而非技术本身,也避免了try-catch-finally的滥用。

  Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了模板类来整合各种优秀框架。

Spring IoC概述

  2004年,Martin Fowler探讨了同一个问题,既然IoC是控制反转,那么到底是“哪些方面的控制被反转了呢?经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。他的这个答案,实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中

  所以,依赖注入(DI)和控制反转(IoC)是从不同的角度的描述的同一件事情,就是指通过引入IoC容器,利用依赖关系注入的方式,实现对象之间的解耦。

  在Spring中,实现控制反转的是IoC容器,其实现方法是依赖注入。Spring会提供IoC容器来管理对应的资源。

  控制反转是一个比较抽象的概念,对于初学者不好理解,我们举例说明。

案例:使用Spring组装电脑

  每台电脑由内存、主板、CPU三个基本的电脑元件组成,内存及CPU需要插在主板上才能工作。我们假定有各式各样的主板、内存及CPU可供选择,因此可通过Java接口来抽象各配件的定义。

//PCComponent接口
public interface PCComponent {
    String getName();//名称 
    double getPrice();//价格
    String getCompany();//厂家    
}
//CPU
public interface CPU extends PCComponent{    
    int getSpeed();//处理器速度
    void doInstr(); //做指令运算
    void outResult();//输出结果 
}
//Ram
public interface Ram extends PCComponent{
    int getSize();//内存大小
    void inData();//读数据
    void outData();//取数据
}
//主板
public interface Mainboard extends PCComponent {
    void setCpu(CPU cpu);//安装cpu
    CPU getCpu();//得到主板上的CPU
    void setRam(Ram ram);//安装内存
    Ram getRam();//得到主板上的内存
    boolean havePower();//是否有电源
    void startPower();//开电源
    void shutdownPower();//关电源
}

Computer类的设计及实现

  每台Computer需要一个主板,每个主板上需要插上CPU及内存条,电脑才能正常工作。

//电脑类
public class Computer {    
    private Mainboard mainboard;//主板
    //电脑的显示器、鼠标键等其它属性省略
    public void setMainboard(Mainboard mainboard) {
    this.mainboard = mainboard;
    }
    public void doWork(){
        System.out.println("开始工作...");
        for(int i=0;i<100;i++)
        System.out.print(i+"  ");
        System.out.println("结束工作!");
    }
    public void start(){
      mainboard.startPower();
    }
    public void shutdown(){
      mainboard.shutdownPower();
    }
    public double getPrice(){
      return mainboard.getPrice()+mainboard.getCpu().getPrice()+mainboard.getRam().getPrice();
    }
    public String getSetting(){//读取电脑配置信息以及价格总额
      String ret;
      ret="电脑组成如下!主板:"+mainboard.getName()+",CPU:"+mainboard.getCpu().getName()+",内存:"+mainboard.getRam().getName()+"\n";
      ret+="这个配置的价格为:"+getPrice();
      return ret;
    }
} 

主板MainBoard的设计及实现

  在现实中,有很多种类型的主板,只要这些主板符合我们的标准,就能接到我们的电脑中来用。本例提供了AUSUBoard及IntelBoard两种类别的主板。

// 主板 公共特性AbstractMainboard
public abstract class AbstractMainboard implements Mainboard {
    private CPU cpu;
    private Ram ram;    
    private boolean power;
    public void setCpu(CPU cpu) {
        this.cpu=cpu;
    }
    public CPU getCpu() {    
        return cpu;
    }
    public void setRam(Ram ram) {
        this.ram=ram;
    }
    public Ram getRam() {    
        return ram;
    }
    public boolean havePower() {
            return power;
    }
    public void startPower() {
        power=true;
    }
    public void shutdownPower() {
            power=false;
    }
}
// AUSUBoard
public class AUSUBoard extends AbstractMainboard {
    public String getName() {
        return "AUSU主板";
    }
    public double getPrice() {
        return 3000.00;
    }
    public String getCompany() {
        return "SUSU公司";
    }    
}

//IntelBoard
public class IntelBoard extends AbstractMainboard {
    public String getName() {
        return "Intel主板";
    }
    public double getPrice() {
        return 3500.00;
    }
    public String getCompany() {
        return "Intel公司";
    }    
}             

CPU的设计及实现

  在现实中,有很多种类型的CPU可供使用,只要这些CPU符合我们的标准,就能接到我们的电脑中来用。本例提供了AMDCpu及IntelCPU两种类别的主板。

// IntelCPU
public class IntelCPU implements CPU {
    public int getSpeed() {
        return 1700;
    }
    public void doInstr() {
    System.out.println("做指令运算");        
    }
    public void outResult() {    
    }
    public String getName() {    
        return "IntelCPU";
    }
    public double getPrice() {
        return 2500;
    }
    public String getCompany() {    
        return "Intel公司";
    }
}

// AMDCpu
public class AMDCpu implements CPU {
    public int getSpeed() {
        return 1500;
    }
    public void doInstr() {
    System.out.println("做指令运算");        
    }
    public void outResult() {        
    }
    public String getName() {    
        return "AMD CPU";
    }
    public double getPrice() {
        return 1800;
    }
    public String getCompany() {    
        return "AMD公司";
    }
}

内存的设计及实现

  本例我们也只提供两款可供选择的内存。分别是Kingmax的内存,以及Kingstone的内存。

// KingmaxRam 
public class KingmaxRam implements Ram {
    public int getSize() {        
        return 512;
    }
    public void inData() {
    //读入数据
    }
    public void outData() {
    //输出数据
    }
    public String getName() {
        return "Kingmax内存";
    }
    public double getPrice() {    
        return 300;
    }
    public String getCompany() {    
        return "Kingmax公司";
    }
}

// KingstoneRam
public class KingstoneRam implements Ram {
    public int getSize() {        
        return 512;
    }
    public void inData() {
        //读入数据
    }
    public void outData() {
        //输出数据
    }
        public String getName() {
            return "Kingstone内存";
    }
    public double getPrice() {    
        return 200;
    }
    public String getCompany() {    
        return "Kingstone公司";
    }
}

传统的组装电脑方法

  传统的情况下,要组装一台电脑,需要在代码中分别new出每一个电脑组件的实例,再把他们组装到电脑上面,再运行程序。代码如下:

public class ClientOldDemo {
    public static void main(String[] args) {        
    CPU cpu=new IntelCPU();
    Ram ram=new KingmaxRam();
    Mainboard myMainboard=new IntelBoard();
    myMainboard.setCpu(cpu);
    myMainboard.setRam(ram);
    Computer computer=new Computer();
    computer.setMainboard(myMainboard);
    //执行computer的doWork方法,使得commputer开始工作
    computer.doWork();
    //输出电脑的配置信息
    System.out.println(computer.getSetting());    
    }
}

用Spring组装电脑

  在Spring中,它会认为一切java类都是资源,而资源都是Bean,容纳这些Bean的是Spring所提供的IoC容器,所以Spring是一种基于Bean的编程。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
   <bean id="myMainboard" class="edu.uestc.avatar.bean.IntelBoard">
       <property name="ram" ><bean class="edu.uestc.avatar.bean.KingmaxRam"/>
    </property> <property name="cpu" ><bean class="edu.uestc.avatar.bean.IntelCPU"/></property>
  </bean>
  <bean id="myComputer" class="edu.uestc.avatar.Computer">
    <property name="mainboard" ref="myMainboard"/>
  </bean>
</beans>

  在配置文件中,通过<bean>标签来定义了一个id为myMainboard的主板,一个id为myComputer的电脑。通过<bean>标签下的<property>分别设置了主板上选择的具体的内存Ram及CPU,另外还通过myComputer的<property>标签设置了mainboard属性为myMainboard。

使用组装好的电脑

public class ClientDemo {
    public static void main(String[] args) {
        //定义Spring Bean工厂资源文件
        Resource res=new ClassPathResource("computer-beans.xml");
        //创建一个Bean工厂
        BeanFactory factory=new XmlBeanFactory(res);
        //从Bean工厂中取出一个名为myComputer的Computer对象
        Computer computer=(Computer)factory.getBean("myComputer");
        //执行computer的doWork方法,使得commputer开始工作
        computer.doWork();
        //输出电脑的配置信息
        System.out.println(computer.getSetting());
    }
}

发布电脑组装程序(让用户自己组装电脑==>修改xml文件即可)

  ClientDemo相当于电脑的最终使用者,一个不会组装电脑的用户,其甚至不知道电脑由哪些部件组成,他需要的仅仅是一个完整可以正常工作的电脑;而负责维护Spring配置文件者,相当于组装电脑的一般技术人员,他不需要很高深的技术,不需要知道怎么样生产一块主板、生产一块CPU,只需要知道什么是主板,什么是CPU,什么是Ram,并且知道CPU及Ram应该插放在什么位置,知道主板怎么安装即可。而实现CPU接口、Mainboard接口及Ram内存的类编写人员,如编写InterCPU这个类的人员,就相当CPU厂家的一线专业技术工程师,他们需要对微电子、数据电路等很多非常专业的技术,他们需要对CPU的工作原理等非常了解。

  基于上面的实例,可以基本上把控制反转定义为:控制反转是一种通过描述(在java中可以是xml或者注解)并通过第三方(spring容器)去产生或获取特定对象的方式。

  正如被动创建的电脑,是通过下面的xml代码描述所得到的:

<bean id="myComputer" class="edu.uestc.avatar.Computer"> 
  <property name="mainboard" ref="myMainboard"/> 
</bean>

  在spring中实现控制反转的是IoC容器,其实现方法是依赖注入。Spring会提供IoC容器来管理对应的资源,正如上面示例中的电脑和主板资源,他们形成依赖注入的关系。其中主板用到CPU和RAM两个资源。

为什么要使用Spring

  在项目中引入spring立即可以带来下面的好处

  • 降低组件之间的耦合度,实现软件各层之间的解耦,有利于测试。
  • 可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时,开发人员就不再需要手工控制事务.也不需处理复杂的事务传播。
  • 容器提供单例模式支持,开发人员不再需要自己编写实现代码。
  • 容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。
  • 容器提供的众多辅作类,使用这些类能够加快应用的开发,如: JdbcTemplate、 HibernateTemplate。
  • Spring对于主流的应用框架提供了集成支持,如:集成Hibernate、JPA、Struts等,这样更便于应用的开发。
  • Spring能通过接口而不是类促进好的编程习惯,降低开发难度。

 

 

posted @ 2022-01-12 15:32  Tiger-Adan  阅读(384)  评论(0编辑  收藏  举报