• 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_19558705/article/details/49994191

  • 相关阅读:
    [译]理解 iOS 异常类型 <🌟>
    LeetCode 24. 两两交换链表中的节点
    解决The operation couldn’t be completed. Unable to log in with account
    <Typora> 常用操作快捷键
    LeetCode 23. 合并K个升序链表
    CSS盒子模型
    CCS属性
    CSS
    form表单
    html
  • 原文地址:https://www.cnblogs.com/itdragon/p/7717924.html
Copyright © 2020-2023  润新知