• Spring第一天——入门与IOC


      大致内容

        spring基本概念

        IOC入门

    【17.6.9更新】,如何学习spring?

      掌握用法

      深入理解

      不断实践

      反复总结

      再次深入理解与实践

    一、Spring相关概念

       1.概述:    

        Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的容器(container)

          无论从大小和开销还是来说,都足以称得上是轻量级的框架
        由Rod Johnson创建。
        简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架

        可以说,spring带来了复杂JavaEE开发的春天!

      【更新】spring是一个解决方案级别的整合框架,主要是用来作解耦

      2.核心有两部分:

        IOC:控制反转
          对象创建不是通过new,而是通过配置交给Spring管理
        AOP:面向切面编程
          所以AOP的本质是在一系列纵向的控制流程中,把那些相同的子流程提取成一个横向的面

        是一种容器,它会管理由他创建的对象,包括生命周期的管理等。

      3.一站式框架
        在JavaEE三层架构中,每一层都提供了不同的解决方案
        web层:SpringMVC
        service层:IOC
        dao层:jdbcTemplate

        对应JavaWeb阶段的三层架构:

        

      

      4.使用的版本
        Spring4.x的版本

      5.Spring包的下载方式
        http://www.open-open.com/news/view/1eb1613

        将文章大致内容提取出来就是:

           找到 spring framework

         找到All avaible features and modules are described in  the Modules section of the reference documentation .

            Their  maven/gradle coordinates are also described there 

         这个就是各个spring版本的下载地址:  http://repo.spring.io/release/org/springframework/spring 而且很清楚的告诉你下载哪个文件。
         (等待maven依赖管理的更新)

     二、IOC(Inverse of Control)控制反转

      【更新】:面向接口编程 每一层只向外提供接口,各层之间只依赖接口而不依赖具体的实现,用于隐藏具体实现并实现多态的组件

        什么被反转了?获得依赖对象的过程被反转了

      IOC主要的观点就是借助第三方(也就是IOC容器)实现依赖关系的对象之间的解耦

      更多详细的IOC与DI的阐述,请参见http://www.cnblogs.com/xdp-gacl/p/3707631.html

      1.对象创建交给Spring管理

        【更新】:应用程序本身并不负责依赖对象的创建和维护,由IOC容器负责创建和维护

          (IOC容器初始化的时候会创建一系列的bean,并存在spring的上下文中,ApplicationContext)

      

       2.Ioc管理分为两部分:

      【更新,初始化IOC容器的方法(WEB应用中) listen可以通过context-param】 主要是指定 contextConfigLocation

        1)Ioc配置文件
        2)Ioc注解 

      (1)==Ioc的底层原理:
          主要用到的技术
            xml配置文件
            dom4j解析配置文件
            工厂设计模式
            反射

    之前代码:
                一个User类:
                    public class User{
                        public void add(){
                            ...
                        }
                    }  
    View Code

      想调用add方法,需要构建类的对象,再调用:
        User user = new User();user.add();
      如果想在servlet中使用,需要将上述代码写在servlet中,但如果原来的类名、方法名发生了修改
      则servlet也要同步修改,耦合度太高,不方便!

        针对这种情况,提出第一阶段的解决方案:
          工厂模式,使用此模式进行解耦操作

    public class UserService{
                    public void add(){
                        ...
                    }
                }
                做法是建立一个工厂类:
                    public class UserFactory{
                        //提供静态方法返回
                        public static UserService getService(){
                            return new UserService();
                        }
                    }
                在servlet中调用可以使用工厂:
                    UserFactory.getService().add();
                    这样就相对降低了和类的耦合度
                    但缺陷是和工厂类又有耦合度(高内聚,低耦合)
    View Code

         IOC的解决的大概过程:
          要在servlet得到UserService类的实例
        步骤:
          第一步:创建xml配置文件,配置需要创建的对象的类;
              <bean id="userService" class="cn.UserService">
          第二步:创建工厂类,使用dom4j解析配置文件+反射
              解析xml得到指定id值得class属性值:类路径
              采用反射创建类的对象
              得到类对象过程还是通过工厂:Factory.getUserService();
              此时类名称发生变化时,只需要变更xml配置文件即可

      (2)IOC入门案例:
        第一步:
          导包:jar包里每个都有三个jar包,分别是jar包、doc、源码
              spring核心组件有四个(如图)


    分别是:beans core context spEL(表达式的,导expression的包)
    再导入支持日志输出的jar包(spring本身并不提供日志jar包)【log4j的使用在后面作补充】
      log4j logging 两个jar包

      也就是如图六个jar包

      第二步:
        创建类和方法
        例如创建User类和add()方法

    package cn.ioc;
    
    public class User {
    
        public void add(){
            System.out.println("spring_ioc_add");
        }
    }
    View Code

      第三步:
        创建spring配置文件,配置创建的类
        前面两个框架的名称和位置固定,而spring不是,但一般都建议放在src下,【更新】:一般放在与src同级的 source folder 下。
        建议名字为 applicationContext.xml
        自定义命名请参考:http://huihai.iteye.com/blog/1019281
        但完全可以自定义名字(位置建议src!)

          在web.xml中指定spring路径:

    <context-param>  
         <param-name>contextConfigLocation</param-name>  
         <param-value>/WEB-INF/beans.xml</param-value>  
    </context-param> 

        比如这里创建一个 bean1.xml
        创建完xml文件,首先是引入约束(这里是schema约束!)
        进入包里的docs->spring framework reference->html->找最后一个文件 (见图!)

        【更新】:现在由 springIDE来做这件事

               

        引入schema约束:

    <?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-4.0.xsd">
    
        <!--ioc入门-->
        <bean id="user" class="cn.ioc.User"></bean>
    </beans>
    View Code

      注意:id建议与类同名,首字母改为小写(这也是spring的默认命名策略)

      第四步:
        简单测试
          步骤:
            加载核心配置文件
            得到对象
            具体不再赘述,见testIoC

    package cn.ioc;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestIoC {
    
        //只是测试这样写,实际开发并不这样操作
        @Test
        public void test(){
            //加载spring核心配置文件
            ApplicationContext context = 
                    new ClassPathXmlApplicationContext("bean1.xml");
            //得到配置创建的对象
            User user =(User)context.getBean("user");
            user.add();
        }
    }
    View Code

      //配置文件没有提示的问题(无法上网,类比之前dtd引入,但稍有区别)此处不再赘述,全部在另外一篇同分类引入约束的博客介绍

      (3)spring的bean管理基于配置文件,day02注解方式
        ==bean实例化的三种方式:(常用一种方式)
          1)使用类的无参构造器(常用)
            上面的入门案例
            <bean id="user01" class="cn.ioc.User"></bean>
            会自动找无参的构造器
          2)使用静态工厂创建
            在类里使用静态方法返回实例对象
            <bean id="user02" class="cn.factory.BeanFactory" factory-method="getBean"></bean>
            依旧使用context.getBean()方法得到bean
          3)使用实例工厂创建
            创建一个不是静态的方法返回类的对象,使用此方式先要创建工厂的对象
            <bean id="bean3Factory" class="cn.factory.Bean3Factory"></bean>
            <bean id="user03" factory-bean="bean3Factory" factory-method="getBean"></bean>
          2、3仅作了解,实际开发用的一般是方式1   

      ==bean标签常用属性的介绍:
        id : 表示起的名称(一般不要包含特殊符号) ,可以根据id值得到配置的对象
        class : 要创建对象所在类的全路径
        name : (一般已经不用了) 功能和id类似,也可以得到bean对象(id值不能得到特殊符号),
            属于遗留问题,为了整合原来的struts1的
        scope : bean的作用范围:一般掌握两个值:
            singleton:单例 (默认)
            prototype:多例(应用于struts2的多实例的action)
          可以分别拿到两个对象比较对象地址

      (4)属性注入:创建对象的时候,也可以向类的属性设置值
        属性注入的方式:支持级联属性的注入(但是必须初始化(不会像struts2一样自动创建,当然,很多时候我们都用不着))
          原始方式:
          有参构造注入
          set()方法注入【用的最多】
          接口注入(用的少)

      spring只支持前两种方式的注入:
        spring有参构造注入:
        建立类

    package cn.propertiry;
    
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    
    public class PropertiryDemo01 {
    
        private String username;
    
        public PropertiryDemo01(String username) {
            this.username = username;
        }
        public void print(){
            System.out.println("有参构造属性构造:"+username);
        }
        
    }

      配置文件修改:

     <!-- 使用有参构造器属性注入 -->
      <bean id="prop01" class="cn.propertiry.PropertiryDemo01">
        <constructor-arg name="username" value="jiangbei"></constructor-arg>
      </bean>

      (不出现name属性时,把约束后面的spring-beans-4.0补上)

    <!-- 有参构造注入 -->
        <bean id="id" class="class">
            <!-- name必须和构造器的参数名一致,ref为需要注入的引用 -->
            <constructor-arg name="" ref=""/>
        </bean>

      spring的set方式注入【最常用】:
        依旧是:创建类 配置文件配置 简单测试

    package cn.propertiry;
    
    public class Book {
    
        private String BookName;//属性
        //set()方法
        public void setBookName(String bookName) {
            BookName = bookName;
        }
        
        public void print(){
            System.out.println("set属性注入:"+BookName);
        }
    }

      修改配置文件

    <!-- set()方法属性注入 -->
    <bean id="book" class="cn.propertiry.Book">
      <property name="BookName" value="从入门到放弃"></property>
    </bean>

    【实用】真正开发中不止是注入字符串,更多的是对象的注入等!
      例如service中依赖dao,需要dao的属性,可以进行属性注入(只是注入的是对象!)
      将new的过程交给spring实现!
      先建立两个类 Service Dao

    package cn.propertiry;
    
    public class Service {
    
        //定义dao成员变量
        private Dao dao;
        public void setDao(Dao dao) {
            this.dao = dao;
        }
    
        public void add(){
            //service中要调用dao的add()方法需要得到其对象
            dao.add();
        }
    }

      

    package cn.propertiry;
    
    public class Dao {
    
        public void add(){
            System.out.println("dao.add");
        }
    }

      在Service中依赖dao对象,定义变量,生成set()方法
      进行配置(ref):

     <!-- 属性注入,注入对象 -->
      <bean id="dao" class="cn.propertiry.Dao"></bean>
      <!-- 注入dao对象 -->
      <bean id="service" class="cn.propertiry.Service">
        <!-- name为成员变量名,ref为dao的bean的id -->
        <property name="dao" ref="dao"></property>
      </bean>

      当然是可以通过多行注入多个属性的。

      名称空间注入:(也可以实现属性注入)只引出概念,不作演示赘述(用的太少)

      ===spring注入复杂数据(会用)
        例如注入list 注入数组 注入map 注入propertites
        都在案例:Prop类里
        定义成员
        生成set

    package cn.propertiry;
    
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    
    public class Prop {
    
        //注入复杂数据类型
            private String[] strs;
            private List<String> list;
            private Map<String,String> map;
            private Properties props;
    
            
            public void setStrs(String[] strs) {
                this.strs = strs;
            }
            public void setList(List<String> list) {
                this.list = list;
            }
            public void setMap(Map<String, String> map) {
                this.map = map;
            }
            public void setProps(Properties props) {
                this.props = props;
            }
            
            public void print2(){
                System.out.println("array:"+strs);
                System.out.println("list:"+list);
                System.out.println("map:"+map);
                System.out.println("props:"+props);
            }
    }

        配置注入(所有的注入都必须先有对象(相关数据)生成)

          如果是配置引用,可以使用 value-ref等(按alt /即可见名知意)

          也可以配置独立的bean(导入util的命名空间),以供多出引用

    <!-- 注入复杂属性 -->
        <bean id="p" class="cn.propertiry.Prop">
            <!-- 进行属性注入 -->
            <!-- 数组 -->
            <property name="strs">
                <list>
                    <value>sx</value>
                    <value>sy</value>
                    <value>sz</value>
                </list>
            </property>
            <!-- list -->
            <property name="list">
                <list>
                    <value>lx</value>
                    <value>ly</value>
                    <value>lz</value>
                </list>
            </property>
            <!-- map -->
            <property name="map">
                <map>
                    <entry key="mx" value="mvx"></entry>
                    <entry key="my" value="mvy"></entry>
                    <entry key="mz" value="mvz"></entry>
                </map>
            </property>
            <!-- props -->
            <property name="props">
                <props>
                    <!-- props的value值写在标签里 -->
                    <prop key="px">pvx</prop>
                    <prop key="py">pvy</prop>
                    <prop key="pz">pvz</prop>
                </props>
            </property>
        </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"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    
        <!-- bean definitions here ioc入门-->
        <bean id="user" class="cn.ioc.User"></bean>
        
        <!-- 使用有参构造器属性注入 -->
        <bean id="prop01" class="cn.propertiry.PropertiryDemo01">
            <constructor-arg name="username" value="jiangbei"></constructor-arg>
        </bean>
        
        <!-- set()方法属性注入 -->
        <bean id="book" class="cn.propertiry.Book">
            <property name="BookName" value="从入门到放弃"></property>
        </bean>
        <!-- 属性注入,注入对象 -->
        <bean id="dao" class="cn.propertiry.Dao"></bean>
        <!-- 注入dao对象 -->
        <bean id="service" class="cn.propertiry.Service">
            <!-- name为成员变量名,ref为dao的bean的id -->
            <property name="dao" ref="dao"></property>
        </bean>
        
        <!-- 注入复杂属性 -->
        <bean id="p" class="cn.propertiry.Prop">
            <!-- 进行属性注入 -->
            <!-- 数组 -->
            <property name="strs">
                <list>
                    <value>sx</value>
                    <value>sy</value>
                    <value>sz</value>
                </list>
            </property>
            <!-- list -->
            <property name="list">
                <list>
                    <value>lx</value>
                    <value>ly</value>
                    <value>lz</value>
                </list>
            </property>
            <!-- map -->
            <property name="map">
                <map>
                    <entry key="mx" value="mvx"></entry>
                    <entry key="my" value="mvy"></entry>
                    <entry key="mz" value="mvz"></entry>
                </map>
            </property>
            <!-- props -->
            <property name="props">
                <props>
                    <!-- props的value值写在标签里 -->
                    <prop key="px">pvx</prop>
                    <prop key="py">pvy</prop>
                    <prop key="pz">pvz</prop>
                </props>
            </property>
        </bean>
    </beans>

      【更新】:使用外部属性配置文件(场景就是读取数据源等信息)

         之前可以使用此种形式:缺点很明显,如果需要修改数据库的配置信息,将比较复杂,需要拿出spring的配置文件

    <!-- 数据库连接池 (此时使用的是dbcp,效率不高,仅作演示使用)-->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
            destroy-method="close">
            <property name="driverClassName" value="${jdbc.driver}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
            <property name="maxActive" value="10" />
            <property name="maxIdle" value="5" />
        </bean>

        我们将这些属性抽取到db.properties:(一般而言,我们都是给Key这里起类似 jdbc.username这样的以.分割的形式,因为有时候直接写username非常容易和其他的(如系统的用户名)相冲突)

    jdbc.user=root
    jdbc.password=1230
    jdbc.driverClass=com.mysql.jdbc.Driver
    jdbc.jdbcUrl=jdbc:mysql:///test
    
    jdbc.initPoolSize=5
    jdbc.maxPoolSize=10

        我们加入context的命名空间(使用springIDE,更简单,更强大!),在配置文件中进行属性文件位置的配置:

    <!-- 导入属性文件 -->
        <context:property-placeholder location="classpath:db.properties"/>

        如何在配置文件中取值我们之前已经提过,使用类似EL的形式:${val}

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

      //当然,这些配置都可以通过编码方式来代替,实现真正的全注解无配置开发

      【更新】 spring的SpEL:为配置文件动态赋值提供了可能

        使用#{...},可以动态引用其它对象,动态引用其它对象的属性值(字面值这里不做阐述)

         value="#{car.price}",注解形式:

               @Value("#{testConstant.STR}")  

              private String str;  

          并且还支持一些基本的运算,以及三目判断运算符等其他的待补充

      【更新】 spring容器的生命周期方法:init-method 和 destroy-method

      重要概念:
        IoC和DI的区别:
      IoC:控制反转,将对象的创建交给spring管理
      DI:依赖注入,向类的属性中设置值
      DI需要在IoC的基础上进行操作(需要在对象创建的基础上进行)

      【更新】:DI是IOC的一种更简单的诠释,也就是说:通过引入IOC容器,利用依赖注入的方式,实现对象之间的解耦

       【更新】bean的作用域(与struts2整合时使用到)

          prototype(每次请求都创建新的实例,使用hashCode判断) singleton request session

          bean的生命周期

          定义  

          初始化

            (比较简便的配置是bean中配置init-method destroy-method的配置)

            当然不使用配置的时候可以通过bean实现 initlizaingBean disposiableBean两个接口,覆盖方法

              当然,也可以配置全局的初始化和销毁方法(就近原则 全局的最后执行)

          使用

          销毁

    第一天的最后引出整合的一些基本概述(后面day会做补充)

    ===spring整合web项目
      Hibernate时有一个遗留问题:sessionFactory的创建会比较慢,可以交给服务器来创建
      还有上面的bean1.xml每次都要加载spring核心配置文件,会影响性能
      以上的类似问题,解决的实现思想都是:
        把加载配置文件和创建对象在服务器启动时就创建,把压力给服务器
      spring中封装了相关的处理类,这里简单介绍原理:

      web阶段中有一个与天地同寿的对象 ServletContext
      它的创建可以由监听器进行监听
      在服务器启动的时候,服务器会为每个项目创建一个独一无二的对象:ServletContext
      可以使用监听器对ServletContext进行监听,可以知道对象的创建时间
      于是可以在监听器监听到ServletContext创建后
      加载spring配置文件,把配置文件中配置的对象进行创建
      对象创建后将创建的对象放在ServletContext中(它也是一个域对象)
      域对象的存取数据直接使用get/setAttribute()即可

  • 相关阅读:
    GNU binutils工具使用(转)
    wget下载整个网站
    Qt中使用第三方的数据库(Sqlite)存储并读取文件本体
    thinkpad T400不能hibernate解决方案,ubuntu 10.10
    android 2.3 StrictMode 使用
    N900 Dual boot(meego& maemo)
    maemo环境安装问题和解决方案(ubuntu 10.04)
    shell中判断一个参数是否为整型
    linux中的块设备和字符设备(转)
    对聊天室调试总结
  • 原文地址:https://www.cnblogs.com/jiangbei/p/6790251.html
Copyright © 2020-2023  润新知