首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

Spring的IOC(统制反转Inversion of Control)

2012-11-06 
Spring的IOC(控制反转Inversion of Control)所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对

Spring的IOC(控制反转Inversion of Control)

所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。

依赖注入(Dependency Injection)

所谓依赖注入就是指:在运行期,由外部容器动态地将依赖对象注入到组件中

spring的配置文件模版

<?xml version="1.0" encoding="UTF-8"?><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.0.xsd">  <bean id="userId"class="biz.impl.UserBizImpl"/></beans>

实例化spring容器

ApplicationContextapp=new ClassPathXmlApplicationContext("bean.xml");

从spring容器中得到bean

当spring容器启动后,因为spring容器可以管理bean对象的创建,销毁等生命周期,所以我们只需从容器直接获取Bean对象就行,而不用编写一句代码来创建bean对象。从容器获取bean对象的代码如下:

ApplicationContextapp=new ClassPathXmlApplicationContext("bean.xml");

UserBizuserBiz=app.getBean("userId",UserBiz.class);

Bean的作用域

.singleton

 在每个SpringIoC容器中一个bean定义只有一个对象实例。默认情况下会在容器启动时初始化bean,但我们可以指定Bean节点的lazy-init=“true”来延迟初始化bean,这时候,只有第一次获取bean会才初始化bean。如:

 <bean id="xxx"class="cn.itcast.OrderServiceBean" lazy-init="true"/>

如果想对所有bean都应用延迟初始化,可以在根节点beans设置default-lazy-init=“true“,如下:

<beans default-lazy-init="true“...>

.prototype

 每次从容器获取bean都是新的对象。<bean id=“” class=“”  scope=“prototype”/>

 每次从容器获取bean都是新的对象。

 根据经验,对有状态的bean应该使用prototype作用域,

 而对无状态的bean则应该使用singleton作用域

.request

 表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTPrequest内有效

.session

  表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTPsession内有效

.globalSession

 不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全Session

 的概念,它被所有构成某个portletweb应用的各种不同的portlet所共享。

以上3种均基于web的SpringApplicationContext情形下有效

延迟初始化bean

默认情况下会在容器启动时初始化bean,但我们可以指定Bean节点的lazy-init=“true”来延迟初始化bean,这时候,只有第一次获取bean时才初始化bean。如:

<bean id="xxx"class="cn.itcast.OrderServiceBean"                                                          lazy-init="true"/>

如果想对所有bean都应用延迟初始化,可以在根节点beans设置default-lazy-init=“true“,如下:

    <beans default-lazy-init="true“...>

Bean的初始化方法和销毁方法

<bean id="xxx"class=“biz.OrderServiceBean" init-method="init" destroy-method="close"/>//init-method初始化方法   destroy-method销毁方法  public void init() {      System.out.println(“已经初始化了”);  }  public void close() {      System.out.println(“被销毁了”);  }  //ApplicationContext不具有close()方法来调用销毁函数,需要使用ApplicationContext 才可以调用close()  AbstractApplicationContext ctx = newClassPathXmlApplicationContext("beans.xml");  PersonService person =(PersonService)ctx.getBean("personServiceBean");  ctx.close();

注入依赖对象

public class UserBizImpl implements UserBiz {   private UserDao userDao;   //需要注入的对象}方式一    <bean id="userDaoId "class="cn.itcast.service.OrderDaoBean"/>    <bean id="orderService"class="biz.impl.UserBizImpl">          <propertyname="userDao " ref="userDaoId "/></bean>//这里使用id定义的userDaoId可以被其他bean使用方式二(使用内部bean,但该bean不能被其他bean引用)    <bean id="orderService"class=" biz.impl.UserBizImpl">       <property name="userDao ">    <!--没有id(name)属性,所以不能被其它引用-->              <bean class=“dao.impl.userDaoImpl”/>       </property>    </bean>方法三  也可以通过构造函数注入和set方法注入<bean id="userDaoId "class="cn.itcast.service.OrderDaoBean"/> <bean id="orderService"class="cn.itcast.service.OrderServiceBean">       <constructor-arg index=“0”  ref=”userDaoId”/>//构造器注入    (构造函数注入,则构造函数的为这个对象赋值,index表示参数的索引,可以省略的)       <property name=“userDao”  ref=” userDaoId”/>//属性setter方法注入     (使用set方法注入当然得为对象设置set方法) </bean>

集合类型的装配

<bean id="order"class="cn.itcast.service.OrderServiceBean">   <property name="lists">         <list>       <value>pkbest</value>        </list>     </property>            <property name="sets">        <set>           <value>pkbest</value>       </set>     </property>           <property name="maps">       <map>           <entry key=“pkbest" value="28"/>      </map>    </property>            <property name="properties">       <props>       <propkey=“pk">best</prop>      </props>      </property></bean>

依赖注入--手工装配

第一种方法:同上面依赖注入对象的第三种是一样的

第二种方法:

在java代码中使用@Autowired或@Resource注解方式进行装配。但我们需要在xml配置文件中配置以下信息:

<beansxmlns="http://www.springframework.org/schema/beans"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:context="http://www.springframework.org/schema/context"      xsi:schemaLocation="http://www.springframework.org/schema/beans          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd           http://www.springframework.org/schema/context      http://www.springframework.org/schema/context/spring-context-3.0.xsd">          <context:annotation-config/>    </beans>

这个配置隐式注册了多个对注释进行解析处理的处理器:AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor

注: @Resource注解在spring安装目录的lib\j2ee\common-annotations.jar

在java代码中使用@Autowired或@Resource注解方式进行装配,这两个注解的区别是:@Autowired 默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。

    @Autowired

    private PersonDao  personDao;//用于字段上

    @Autowired

    public void setOrderDao(OrderDao orderDao){//用于setter方法上

        this.orderDao = orderDao;

    }

@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:

    @Autowired  @Qualifier("personDaoBean")

    private PersonDao  personDao;

@Resource注解和@Autowired一样,也可以标注在字段或setter方法上,但它默认按名称装配。名称可以通过@Resource的name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在setter方法上,即默认取bean名称寻找依赖对象。

    @Resource(name=“personDaoBean”)

private PersonDao personDao;//用于字段上

注意:如果没有指定name属性,并且按照默认的名称找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。

通过在classpath自动扫描

前面的例子我们都是使用XML的bean定义来配置组件。在一个稍大的项目中,通常会有上百个组件,如果这些这组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便。spring为我们引入了组件自动扫描机制,他可以在类路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理。它的作用和在xml文件中使用bean节点配置组件是一样的。要使用自动扫描机制,我们需要打开以下配置信息:

<beansxmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:context="http://www.springframework.org/schema/context"      xsi:schemaLocation="http://www.springframework.org/schema/beans          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scanbase-package="cn.itcast"/>  // base-package指定需要扫描的路径</beans>

其中base-package为需要扫描的包(含子包)。

@Service用于标注业务层组件、 @Controller用于标注控制层组件(如struts中的action)、@Repository用于标注数据访问组件,即DAO组件。而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

@Scope用于指定scope作用域的(用在类上)  @PostConstruct用于指定初始化方法(用在方法上)

@PreDestory用于指定销毁方法(用在方法上)

使用自动扫描以后在beam.xml中的beans中不需要再定义bean了,要使用时路径下的bean对象时只需要通过类名首字母小写获取即可,比如要获取UserBizImpl的对象

UserBiz biz = app.getBean("userBizImpl", UserBiz.class);

如果依赖的注入对象的接口有多个实现类的情况下需要,在@Resource中的name的值也类名首字母小写,如果只有一个实现类的话可以不需要指明@Resource的name属性

@Resource(name=“userDaoImpl”)

热点排行