IoC容器

Posted 吴二喵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IoC容器相关的知识,希望对你有一定的参考价值。

一、什么是IoC容器?

Spring核心容器就是一个超级大工厂,所有的对象(包括数据源、Hibernate SessionFactory等基础性资源)都会被当成Spring核心容器管理的对象—Spring把容器中的一切对象统称为Bean。不管该java类是JDK提供的,还是第三方框架提供的,抑或是开发者自己实现的……只要是个java类,并将它配置在配置文件中,spring容器就可以管理它。

IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IoC容器进行组装。在Spring中BeanFactory是IoC容器的实际代表者。

二、什么是Bean?

Spring中的bean和java bean不同,java bean需要遵守一些特定的规范,而Spring对bean没有要求,只要是一个Java类就可以了。 所以,Bean就是由Spring容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。

那么Spring容器怎么知道如何管理哪些Bean?
答案是XML配置文件,Spring对XML配置文件的文件名没有任何要求,可以随意指定。当然还可以用注解,这里不做详细介绍。

三、使用Spring容器管理Bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xmlns:tx="http://www.springframework.org/schema/tx"
             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
                     http://www.springframework.org/schema/aop
                     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                     http://www.springframework.org/schema/tx
                     http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    <context:annotation-config/>
    <context:component-scan base-package="com.lixing.shop"/>

    <!--Jdbc Description -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations" value="classpath:jdbc.properties"/>
  </bean>

  <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
     <property name="driverClassName" value="$jdbc.driverClassName"/>
     <property name="url" value="$jdbc.url"/>
     <property name="username" value="$jdbc.username"/>
     <property name="password" value="$jdbc.password"/>
  </bean>

  <!--SessionFactory Description --> 
  <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
     <property name="dataSource" ref="dataSource" />
     <property name="packagesToScan">
        <list>
          <value>com.lixing.shop.model</value>        
        </list>
     </property>
     <property name="hibernateProperties">
         <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.mysqlDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
         </props>
     </property>
  </bean>

  <!--HinerbateTemplate Description -->
  <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
    <property name="sessionFactory" ref="sessionFactory"></property>
  </bean>

  <!--Transaction Description -->
  <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
     <property name="sessionFactory" ref="sessionFactory" />
  </bean>

  <!--Transaction Advice Desctiption -->  
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
         <tx:method name="is*" read-only="true"/>
            <tx:method name="list*" read-only="true"/>
             <tx:method name="find*" read-only="true"/>
            <tx:method name="get*" read-only="true"/>            
            <tx:method name="upda*"/>
        </tx:attributes>
     </tx:advice>

  <aop:config>
    <aop:pointcut    id="transactionPointcut" expression="execution(public * com.lixing.shop.service.*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointcut"/>
  </aop:config>  
</beans>

Spring框架通过反射根据<bean…/>元素的class属性指定的类名创建了一个java对象,并以<bean…/>元素的id属性的值为key,将该对象放入Spring容器中,这个Java对象就成为了Spring容器中的Bean。

下面是一个Spring底层用反射机制将java对象放入Spring容器的伪代码示例:

//解析<bean .../>元素的id属性得到该字符串值为“courseDao”  
String idStr = "courseDao";  
//解析<bean .../>元素的class属性得到该字符串值为“com.qcjy.learning.Dao.impl.CourseDaoImpl”  
String classStr = "com.qcjy.learning.Dao.impl.CourseDaoImpl";  
//利用反射知识,通过classStr获取Class类对象  
Class<?> cls = Class.forName(classStr);  
//实例化对象  
Object obj = cls.newInstance();  
//container表示Spring容器  
container.put(idStr, obj);  

在spring配置文件中配置Bean时,class属性的值必须是Bean实现类的完整类名(必须带包名),不能是接口,不能是抽象类(除非有特殊配置),否则spring无法使用反射创建该类的实例。

使用Spring框架后最大的改变之一就是:程序不再使用new调用构造器创建java对象,所有的java对象都是由Spring容器负责创建。

IoC容器的工作步骤:
1、准备配置文件:在配置文件中声明Bean定义也就是为Bean配置元数据。
2、由IoC容器进行解析元数据: IoC容器的Bean Reader读取并解析配置文件,根据定义生成BeanDefinition配置元数据对象,IoC容器根据BeanDefinition进行实例化、配置及组装Bean。
3、实例化IoC容器:由客户端实例化容器,获取需要的Bean。

使用IoC容器的三个基本要点:
1、应用程序的各个组件面向接口编程,将组件之间的耦合关系提升到接口层次,有利于项目后期的扩展
2、应用程序的各组件不再由程序主动创建,而是由Spring容器来负责产生并初始化
3、Spring采用配置文件或者注解来管理Bean的实现类、依赖关系,Spring容器则根据配置文件或注解,利用反射来创建实例,并为之注入依赖关系。

以上是关于IoC容器的主要内容,如果未能解决你的问题,请参考以下文章

IoC容器

spring在IoC容器中装配Bean详解

Spring IOC/DI

Spring Ioc底层实现

大话DI依赖注入+IOC控制反转 之 定义

同为容器,IoC和Docker有啥不同?