Spring4 IOC详解

Spring4 IOC详解

上一章对Spring做一个快速入门的教程,其中只是简单的提到了IOC的特性。本章便对Spring的IOC进行一个详解。主要从三个方面开始:基于xml文件的Bean配置,基于注解的Bean配置和IOC容器Bean的生命周期。


基于xml文件的Bean配置

首先是applicationContext.xml文件,这可是核心文件。
配置一个bean,需要一个id去唯一标识它,用class指定Bean对象的路径,作用域默认是单例。
通过prototype进行属性赋值,name是属性名,value是值,也可以用ref引用对象,用list,map设置集合。
用SpEL表达式语言赋值,用p命名空间简化赋值,用继承和依赖简化代码。

<?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:util="http://www.springframework.org/schema/util"  
    xmlns:p="http://www.springframework.org/schema/p"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">  
      
    <!-- 配置一个 bean   
        bean中有一个id,且id是唯一的。若不指名则为该类的类名并首字母小写。  
        property 中有一个name,其name就是生产了setter方法的属性,value便是其值。  
    -->  
    <!-- Bean 的作用域  
        singleton:单例,默认值,容器初始化创建bean实例,在整个生命周期内只创建一个bean。  
        prototype:原型,容器初始化不创建bean实例,每次请求的时候会创建一个新的bean  
     -->  
    <bean id="entity" class="com.itdragon.spring.my.Entity" scope="prototype">  
        <!-- 属性赋值   
            属性注入使用 <property> 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 <value> 子节点指定属性值   
        -->  
        <property name="intValue" value="1"></property>  
        <!-- 引用bean  
            细节:  
            1. 用ref 是引用外部bean  
            2. 也可以直接写在当前bean里面,这就是内部bean, 内部bean是不能被外部引用  
        -->  
        <property name="spELEntity"  ref="spELEntity"></property>  
        <!-- 构造器注入  
            构造器注入在 <constructor-arg> 元素里声明属性, <constructor-arg> 中没有 name 属性,按照构造器参数顺序赋值  
            细节:  
            1. 也可以用index(按索引匹配入参),和type(按类型匹配入参)去指定赋值。实际上是没有必要的  
            2. 使用构造器注入的前提是 entity 被初始化。  
            3. 特殊字符,需要用 <![CDATA[内容]]> 这属于xml语法  
         -->  
         <constructor-arg value="1.1" />  
         <constructor-arg >  
            <value><![CDATA[<ITDragon>]]></value>  
         </constructor-arg>  
         <property name="listValue">  
            <list>  
                <value>欢迎阅读</value>  
                <value>ITDragon</value>  
                <value>的博客!</value>  
            </list>  
         </property>  
         <property name="mapValue">  
            <map>  
                <entry key="one" value="1"></entry>  
                <entry key="two" value="2"></entry>  
            </map>  
         </property>  
    </bean>  
      
    <!-- SpEL 表达式语言, #{…} 作为定界符, 操作和java相似-->  
    <bean id="spELEntity" class="com.itdragon.spring.my.SpELEntity">  
        <property name="intSpel" value="#{1}"></property>  
        <property name="floatSpel" value="#{entity.intValue + 0.2}"></property>  
        <property name="stringSpel" value="#{'Spring4基础教程'}"></property>  
        <property name="bSpel" value="#{2 >= 1}"></property>  
    </bean>  
      
    <!-- 使用 p 命名空间    
        给Entity 对象 的intValue 字段设置 为2 ,根据名称匹配SpEL对象  
        自动装配 autowire (不常用)  
        byName(根据名称自动装配): 必须将目标 Bean 的名称和属性名设置的完全相同.反之不能  
        byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean. 在这种情况下, 不能执行自动装配.  
    -->  
    <bean id="entity2" class="com.itdragon.spring.my.Entity"   
        p:intValue="2"  autowire="byName" />  
          
    <!-- 继承 依赖   
        如果 被继承的bean 不想被继承,则要加上 abstract="true"  
        依赖:如果被依赖的bean,没有实例化,则会报错。如果有多个依赖需用","分开  
    -->  
    <bean id="entity3" class="com.itdragon.spring.my.Entity"   
        parent="entity" depends-on="spELEntity" />  
          
    <!-- 使用外部属性文件 在Spring操作数据库的时候再讲 -->  
</beans>   

实体类Entity和SpELEntity

import java.util.List;  
import java.util.Map;  
public class Entity {  
      
    private int intValue;  
    private float floatValue;  
    private String stringValue;  
    private SpELEntity spELEntity;  
    private Map<String, Object> mapValue;  
    private List<Object> listValue;  
      
    public Entity() {  
    }  
    public Entity(float floatValue, String stringValue) {  
        this.floatValue = floatValue;  
        this.stringValue = stringValue;  
    }  
    public int getIntValue() {  
        return intValue;  
    }  
    public void setIntValue(int intValue) {  
        this.intValue = intValue;  
    }  
    public float getFloatValue() {  
        return floatValue;  
    }  
    public void setFloatValue(float floatValue) {  
        this.floatValue = floatValue;  
    }  
    public String getStringValue() {  
        return stringValue;  
    }  
    public void setStringValue(String stringValue) {  
        this.stringValue = stringValue;  
    }  
    public SpELEntity getSpELEntity() {  
        return spELEntity;  
    }  
    public void setSpELEntity(SpELEntity spELEntity) {  
        this.spELEntity = spELEntity;  
    }  
    public Map<String, Object> getMapValue() {  
        return mapValue;  
    }  
    public void setMapValue(Map<String, Object> mapValue) {  
        this.mapValue = mapValue;  
    }  
    public List<Object> getListValue() {  
        return listValue;  
    }  
    public void setListValue(List<Object> listValue) {  
        this.listValue = listValue;  
    }  
    @Override  
    public String toString() {  
        return "Entity [intValue=" + intValue + ", floatValue=" + floatValue  
                + ", stringValue=" + stringValue + ", spELEntity=" + spELEntity  
                + ", mapValue=" + mapValue + ", listValue=" + listValue + "]";  
    }  
}  
public class SpELEntity {  
      
    private int intSpel;  
    private float floatSpel;  
    private boolean bSpel;  
    private String stringSpel;  
    public int getIntSpel() {  
        return intSpel;  
    }  
    public void setIntSpel(int intSpel) {  
        this.intSpel = intSpel;  
    }  
    public float getFloatSpel() {  
        return floatSpel;  
    }  
    public void setFloatSpel(float floatSpel) {  
        this.floatSpel = floatSpel;  
    }  
    public boolean isbSpel() {  
        return bSpel;  
    }  
    public void setbSpel(boolean bSpel) {  
        this.bSpel = bSpel;  
    }  
    public String getStringSpel() {  
        return stringSpel;  
    }  
    public void setStringSpel(String stringSpel) {  
        this.stringSpel = stringSpel;  
    }  
    @Override  
    public String toString() {  
        return "SpELEntity [intSpel=" + intSpel + ", floatSpel=" + floatSpel  
                + ", bSpel=" + bSpel + ", stringSpel=" + stringSpel + "]";  
    }  
  
}  

测试Main方法。首先要创建一个容器,然后通过bean的id获取到实例,这样就可以开始相关的操作。其中entity,entity2,entity3对应三块不同的知识点。

import org.springframework.context.support.ClassPathXmlApplicationContext;  
public class Main {  
  
    public static void main(String[] args) {  
        /** 
         * ClassPathXmlApplicationContext:从 类路径下加载配置文件,建议用该方法 
         * FileSystemXmlApplicationContext: 从文件系统中加载配置文件 
         */  
        // 1. 创建 Spring 的 IOC 容器  
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");  
          
        /** 
         * entity 属性注入,构造器注入,对象引用,集合,SpEL,(重点) 
         * entity2 自动装配和P命名空间 
         * entity3 继承和依赖,作用域 
         */  
        // 2. 从 IOC 容器中获取 bean 的实例  
        Entity entity = (Entity) ctx.getBean("entity");  
          
        // 3. 使用 bean  
        System.out.println(entity.toString());  
//      System.out.println(ctx.getBean("entity") == ctx.getBean("entity")); 使用 prototype 打印的是false  
          
        ctx.close();  
    }  
      
} 
Entity [intValue=1, floatValue=1.1, stringValue=<ITDragon>, spELEntity=SpELEntity [intSpel=1, floatSpel=1.2, bSpel=true, stringSpel=Spring4基础教程], mapValue={one=1, two=2}, listValue=[欢迎阅读, ITDragon, 的博客!]]  

基于注解的Bean配置

相对于xml的配置,注解的方式显得异常简单。主要分两个步骤
第一步:在applicationContext.xml文件设置扫描包的范围

<?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:util="http://www.springframework.org/schema/util"  
    xmlns:p="http://www.springframework.org/schema/p"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xsi:schemaLocation="  
        http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans.xsd  
        http://www.springframework.org/schema/util   
        http://www.springframework.org/schema/util/spring-util-4.0.xsd  
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.0.xsd">  
      
    <!-- 配置自动扫描指定目录下的包   
        resource-pattern="xxx/*.class" 属性过滤特定的类   
    -->  
    <context:component-scan base-package="com.itdragon.spring.my" >  
        <!-- annotation 是针对指定的类 和 assignable 是针对所有继承或者扩展该类的类-->  
        <!-- context:exclude-filter 只排除expression里面的内容   
        <context:exclude-filter type="annotation" expression=""/>  
         -->  
        <!-- context:include-filter 只包含expression里面的内容   
            需配合 use-default-filters="false"(默认是true) 一起使用  
        <context:include-filter type="annotation" expression=""/>  
        -->  
    </context:component-scan>  
      
</beans>   

第二步:在对象上用注解。这四几个注解的作用一样,只是为了结构清晰,取的名字不同罢了。
使用方法很简单:直接在类上加注解即可。无参数的情况,bean的id默认是小写字母开头的类名。也可以指定参数@Commponent("指定参数"),那bean的id就是指定参数。
@Component: 基本注解, 标识了一个受 Spring 管理的组件
@Respository: 标识持久层组件
@Service: 标识服务层(业务层)组件
@Controller: 标识表现层组件

public interface AnnoRepository {  
      
    public void hello();  
  
}  
import org.springframework.stereotype.Repository;  
@Repository  
public class AnnoRepositoryImp implements AnnoRepository{  
  
    @Override  
    public void hello() {  
        System.out.println("AnnoRepository : hello!");  
    }  
  
}  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Service;  
@Service  
public class AnnoService {  
      
    @Autowired  
    private AnnoRepository annoRepository;  
      
    public void hello() {  
        System.out.println("AnnoService : hello!");  
        annoRepository.hello();  
    }  
  
}  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Controller;  
  
@Controller  
public class AnnoController {  
  
    @Autowired  
    private AnnoService annoService;  
      
    public void execut() {  
        System.out.println("AnnoController : hello !");  
        annoService.hello();  
    }  
      
}  

这里还有一个注解Autowired, <context:component-scan> 元素会自动组件装配被Autowired修饰的对象。
测试类:虽然applicationContext.xml中没有annoController的bean配置,但我们有注解!

import org.springframework.context.support.ClassPathXmlApplicationContext;  
public class Main {  
  
    public static void main(String[] args) {  
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");  
        AnnoController annoController = (AnnoController) ctx.getBean("annoController");  
        annoController.execut();  
        ctx.close();  
    }  
      
}  
AnnoController : hello !  
AnnoService : hello!  
AnnoRepository : hello! 

有没有觉得基于注解的bean配置比基于xml的bean配置简单很多。


IOC容器Bean的生命周期

step1 实例化,通过构造器创建 Bean 实例
step2 赋值,为 Bean 的属性设置值
step3 init-method,调用 Bean 的初始化方法(init-method)
step4 destroy-method,当容器关闭时, 调用 Bean 的销毁方法(destroy-method)

以上代码都是笔者亲测可用的,不要嫌麻烦,麻烦是学不好的,如果有什么问题和建议可以留言,我会及时处理。http://blog.csdn.net/qq_19558...

20170923190228262

阅读 2.1k

推荐阅读
JavaEE教程
用户专栏

这里主要有Spring,SpringMVC,SpringData,Hibernate,Mybatis,等java框架的系列教程。助你高效正确的...

55 人关注
50 篇文章
专栏主页