Spring中三个重要概念 IOC AOP BOP

首先讲解一下Spring框架,以及为什么要使用Spring 框架?

Spring 是一个很好的容器框架, 是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,一般在传统的java开发中具有高度的耦合性,一个项目中或者一个逻辑功能的实现时,往往一个对象需要依赖很多的对象来完成自己的操作,这样就造成了两个类的依赖关系太强,改一个地方,往往牵扯很多类牵扯大量的代码。 
此时Spring就被开发出来, 它可以管理对象和对象之间的依赖关系,我们不需要自己建立对象,把这部分工作全部转交给容器完成,具有低耦合,对代码没有侵略性,对服务器没有依赖性特点的框架 
一个简单的例子说明使用和不使用框架的区别:

不使用Spring框架

public classUserService{  
   private UserDao userdao;
   public void insert(User user){  
       userdao = new UserDao();  // 需要自己new一个UserDao类型的对象
       userdao.insert(user);  
   }  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用了框架

public classUserService{  
   private UserDao userdao;  
   // 设置 set和get函数,在运行时,Spring会将UserDao对象会自动注入到该类中
   public UserDao getUserdao() {  
      return userdao;  
   }  
   public void setUserdao(UserDao userdao) {  
      this.userdao= userdao;  
   }  

   public void insert(User user){  
      userdao.insert(user); // 不需要自己new对象了 
   }  
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

IOC DI

在Spring之中,始终最为重要的两个思想就是 控制反转IOC, 和依赖注入DI 有人认为 DI(依赖注入)是实现IoC的一种方法,也有人认为DI 只是IoC的另一种说法。没有IoC的程序中我们使用面向对象编程对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

java程序中的每个业务逻辑至少需要两个或以上的对象来协作完成,通常,每个对象在使用他的合作对象时,自己均要使用像new object() 这样的语法来完成合作对象的申请工作。你会发现:对象间的耦合度高了。而IOC的思想是:Spring容器来实现这些相互依赖对象的创建、协调工作。对象只需要关系业务逻辑本身就可以了。从这方面来说,对象如何得到他的协作对象的责任被反转了(IOC、DI)

引用一个网上比较火的例子, 
那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。 
那么DI是如何实现的呢? 反射实现(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的

在上面的例子中,使用框架之后在classUserService类中不需要new一个UserDao对象了,取而代之的是 生成set和get方法,这样在程序运行的时候Spring就可以自己从容器中生成一个UserDao对象,利用反射的方式注入到 该类中。 
Spring IOC 实现的一个小例子, 该例子转载自博客: 
http://blog.csdn.net/frightingforambition/article/details/47974775

spring IOC容器的关键点: 
必须将被管理的对象定义到spring配置文件中 
必须定义构造函数或setter方法,让spring将对象注入过来

Spring IOC具体如何实现?

上文中的婚介所就是ioc管理对象的容器,实际上是一个xml文件,将对象配置在xml里面,通过spring的工厂类进行解析,以“反射”的方式创建对象。 

我们可以通过下面这里例子理解spring ioc的实现。本例使用spring 3.2 
1.配置applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    <bean id="userDao4MySqlImpl" class="com.bjsxt.spring.dao.UserDao4MySqlImpl"/>
    <bean id="userDao4OracleImpl" class="com.bjsxt.spring.dao.UserDao4OracleImpl"/>
    <bean id="userManager" class="com.bjsxt.spring.manager.UserManagerImpl">
        <!-- 构造方法注入 
        <constructor-arg ref="userDao4OracleImpl"/>
         -->
         <!-- setter方法注入 而且指定注入的对象为userDao4OracleImpl类型对象-->
         <property name="userDao" ref="userDao4OracleImpl"/>
    </bean>
</beans>

2.注入的类:

package com.bjsxt.spring.dao;

public interface UserDao {

    public void save(String username, String password);
}

package com.bjsxt.spring.dao;

public class UserDao4MySqlImpl implements UserDao {

    public void save(String username, String password) {
        System.out.println("--------UserDao4MySqlImpl.save()-------");
    }
}

package com.bjsxt.spring.dao;

public class UserDao4OracleImpl implements UserDao {

    public void save(String username, String password) {
        System.out.println("--------UserDao4OracleImpl.save()-------");
    }
}

3.被注入的类:

package com.bjsxt.spring.manager;

public interface UserManager {
    public void save(String username, String password);
}

package com.bjsxt.spring.manager;

import com.bjsxt.spring.dao.UserDao;

public class UserManagerImpl implements UserManager {
    /**
     * 两种方式:如果这个类中需要注入对象,先建立对象属性,
     *      在写构造方法或者set方法。
     * 
     */
    private UserDao userDao;

/* 构造方法实现
 public UserManagerImpl(UserDao userDao) {
        this.userDao = userDao;
    } */

    public void save(String username, String password) {
        this.userDao.save(username, password);
    }
// set方式实现
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

4.测试类:

package com.bjsxt.spring.client;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bjsxt.spring.manager.UserManager;

public class Client {

    public static void main(String[] args) {
/*  传统的通过new对象建立类之间的关系
 * UserManager userManager = new UserManagerImpl(new UserDao4OracleImpl());
        UserManager userManager = new UserManagerImpl(new UserDao4MySqlImpl());
        userManager.save("张三", "123");*/
/**
 * IOC思想     通过工厂类解析xml文件,以“反射”的方式创建对象:
 */
        BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserManager userManager = (UserManager)factory.getBean("userManager");
        userManager.save("张三", "123");
/**
 * IOC思想   实际的执行过程,这也是为什么需要setter方法或构造方法的原因:        
 */
//      UserManagerImpl userManager = new UserManagerImpl();
//      userManager.setUserDao(new UserDao4OracleImpl());  根据配置文件可知,这里set的对象是UserDao4OracleImpl对象
//      userManager.save("张三", "123");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113

面向Bean

Spring 是面向 Bean 的编程(Bean Oriented Programming, BOP),Bean 在 Spring 中才是真正的主角。Bean 在 Spring 中作用就像 Object 对 OOP 的意义一样,Spring 中没有 Bean 也就没有 Spring 存在的意义。Spring 提供了 IoC容器通过配置文件或者注解的方式来管理对象之间的依赖关系。 
Spring 设计的核心 org.springframework.beans 包(架构核心是org.springframework.core包),它的设计目标是与 JavaBean 组件一起使用。这个包通常不是由用户直接使用,而是由服务器将其用作其他多数功能的底层中介。下一个最高级抽象是 BeanFactory 接口,它是工厂设计模式的实现,允许通过名称创建和检索对象。BeanFactory 也可以管理对象之间的关系。

    BeanFactory 支持两个对象模型。

        1,单例:模型提供了具有特定名称的对象的共享实例,可以在查询时对其进行检索。Singleton 是默认的,也是最常用的对象模型。对于无状态服务对象很理想。

        2,原型:模型确保每次检索都会创建单独的对象。在每个用户都需要自己的对象时,原型模型最适合。

bean 工厂的概念是 Spring 作为 IoC容器的基础。IoC则将处理事情的责任从应用程序代码转移到框架。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

AOP 面向切面编程 Aspect Oriented Programming

Aop,是一种编程技术,它允许程序员对横切关注点或横切典型的职责分界线的行为(例如日志和事务管理)进行模块化。Aop的核心构造是方面,它将那些影响多个类的行为封装到可重用的模块中。Aop的功能完全集成到了 Spring 事务管理、日志和其他各种特性的上下文中。 
举个例子说明一下吧,比如——————银行会有这样的两个流程, 取款和显示余额, 然而在这两个流程中有着同样的一个操作:用户验证,那么可不可以把用户验证封装成一个模块取出来呢? 然后在需要的时候注入到这两个流程中? 
这里写图片描述 
这就是AOP的作用了,有了AOP,你写代码时不要把这个验证用户步骤写进去,即完全不考虑验证用户,你写完之后,在另我一个地方,写好验证用户的代码,然后告诉Spring你要把这段代码加到哪几个地方,Spring就会帮你加过去,而不要你自己Copy过去,这样的好处是当流程变的越来越多时,只需要写一遍用户验证程序,可以节省写代码的时间,不过最主要的是你写代码的时候,事先只需考虑主流程,而不用考虑那些不重要的流程,在事后就使用AOP就可以给所有流程一次性加入验证代码,而你只需要写一次验证代码 

所以 AOP的本质是在一系列纵向的控制流程中,把那些相同的子流程提取成一个横向的面,面向这些横向的面进行操作。


IOC和AOP是Spring中的两个核心的概念,下面谈谈对这两个概念的理解。

1. IOC(Inverse of Control):控制反转,也可以称为依赖倒置。

        所谓依赖,从程序的角度看,就是比如A要调用B的方法,那么A就依赖于B,反正A要用到B,则A依赖于B。所谓倒置,你必须理解如果不倒置,会怎么着,因为A必须要有B,才可以调用B,如果不倒置,意思就是A主动获取B的实例:B b = new B(),这就是最简单的获取B实例的方法(当然还有各种设计模式可以帮助你去获得B的实例,比如工厂、Locator等等),然后你就可以调用b对象了。所以,不倒置,意味着A要主动获取B,才能使用B;到了这里,就应该明白了倒置的意思了。倒置就是A要调用B的话,A并不需要主动获取B,而是由其它人自动将B送上门来。
        形象的举例就是:
        通常情况下,假如你有一天在家里口渴了,要喝水,那么你可以到你小区的小卖部去,告诉他们,你需要一瓶水,然后小卖部给你一瓶水!这本来没有太大问题,关键是如果小卖部很远,那么你必须知道:从你家如何到小卖部;小卖部里是否有你需要的水;你还要考虑是否开着车去;等等等等,也许有太多的问题要考虑了。也就是说,为了一瓶水,你还可能需要依赖于车等等这些交通工具或别的工具,问题是不是变得复杂了?那么如何解决这个问题呢?
        解决这个问题的方法很简单:小卖部提供送货上门服务,凡是小卖部的会员,你只要告知小卖部你需要什么,小卖部将主动把货物给你送上门来!这样一来,你只需要做两件事情,你就可以活得更加轻松自在:
        第一:向小卖部注册为会员。
        第二:告诉小卖部你需要什么。

        这和Spring的做法很类似!Spring就是小卖部,你就是A对象,水就是B对象
        第一:在Spring中声明一个类:A
        第二:告诉Spring,A需要B

        假设A是UserAction类,而B是UserService类

[html]  view plain  copy
  1. <bean id="userService" class="org.leadfar.service.UserService"/>  
  2. <bean id="documentService" class="org.leadfar.service.DocumentService"/>  
  3. <bean id="orgService" class="org.leadfar.service.OrgService"/>  
  4.   
  5. <bean id="userAction" class="org.leadfar.web.UserAction">  
  6.      <property name="userService" ref="userService"/>  
  7. </bean>  

        在Spring这个商店(工厂)中,有很多对象/服务:userService,documentService,orgService,也有很多会员:userAction等等,声明userAction需要userService即可,Spring将通过你给它提供的通道主动把userService送上门来,因此UserAction的代码示例类似如下所示:

[java]  view plain  copy
  1. package org.leadfar.web;  
  2. public class UserAction{  
  3.      private UserService userService;  
  4.      public String login(){  
  5.           userService.valifyUser(xxx);  
  6.      }  
  7.      public void setUserService(UserService userService){  
  8.           this.userService = userService;  
  9.      }  
  10. }  

         在这段代码里面,你无需自己创建UserService对象(Spring作为背后无形的手,把UserService对象通过你定义的setUserService()方法把它主动送给了你,这就叫依赖注入!),当然咯,我们也可以使用注解来注入。Spring依赖注入的实现技术是:动态代理

2. AOP:即面向切面编程

        面向切面编程的目标就是分离关注点。什么是关注点呢?就是你要做的事,就是关注点。假如你是个公子哥,没啥人生目标,天天就是衣来伸手,饭来张口,整天只知道玩一件事!那么,每天你一睁眼,就光想着吃完饭就去玩(你必须要做的事),但是在玩之前,你还需要穿衣服、穿鞋子、叠好被子、做饭等等等等事情,这些事情就是你的关注点,但是你只想吃饭然后玩,那么怎么办呢?这些事情通通交给别人去干。在你走到饭桌之前,有一个专门的仆人A帮你穿衣服,仆人B帮你穿鞋子,仆人C帮你叠好被子,仆人C帮你做饭,然后你就开始吃饭、去玩(这就是你一天的正事),你干完你的正事之后,回来,然后一系列仆人又开始帮你干这个干那个,然后一天就结束了!

        AOP的好处就是你只需要干你的正事,其它事情别人帮你干。也许有一天,你想裸奔,不想穿衣服,那么你把仆人A解雇就是了!也许有一天,出门之前你还想带点钱,那么你再雇一个仆人D专门帮你干取钱的活!这就是AOP。每个人各司其职,灵活组合,达到一种可配置的、可插拔的程序结构。

        从Spring的角度看,AOP最大的用途就在于提供了事务管理的能力。事务管理就是一个关注点,你的正事就是去访问数据库,而你不想管事务(太烦),所以,Spring在你访问数据库之前,自动帮你开启事务,当你访问数据库结束之后,自动帮你提交/回滚事务!


猜你喜欢

转载自blog.csdn.net/suchahaerkang/article/details/80171134