zoukankan      html  css  js  c++  java
  • Spring总结

    1.Spring作用和优点

    a.  Spring框架是解决方案级的框架或者说整合框架,是各种组件、技术的使用平台,可以在这个平台上使用Struts,Hibernate,JDBC技术并且可以可以实现各种开发技术的组合。     Spring提供了IoC和AOP机制的实现,可以改善程序结构,提高系统的灵活性,便于维护和扩展。

         Spring主要作用

      让组件之间实现低耦合(方便解耦),让程序结构更加灵活,方便日后的维护和扩展 。

      低耦合:组件与组件之间的关联度较低, Spring相当于主机中的主板,而struts、Hibernate、jsp相当于主板上的cpu、内存、显卡之类的组件(主板特点:可插拔 ) 

    b.  在SSH使用中,Spring提供了一个容器,该容器具有IOC和AOP机制,利用这个容器IOC机制管理程序中的DAO,Service等组件,采用AOP机制实现事务,异常日志记录等共通处理。

    2.Spring容器简介

       1)Spring容器是Spring框架的基础和核心。该容器具有以下功能:

        a.可以创建和初始化一个Bean组件对象( 在spring里,任何java对象和java组件都被当成bean处理 )。

        b.可以管理Bean对象的生命周期

        c.可以利用IoC机制建立Bean对象之间的关系

        d.可以利用扩展的AOP机制将共通组件和某一批目标组件对象建立关联。

          (需要引入AOP扩展jar包)

     

        2)Spring容器类型可以使用BeanFactory或者ApplicationContext.

         --Spring容器实例化

          ApplicationContext ac =new ClasspathXmlApplicationContext(xml配置);

         --从Spring容器获取Bean对象

          接口类型 变量 =  (接口类型)ac.getBean("id属性");

         --销毁Spring容器

           使用AbstractApplicationContext类型的close();

           一般情况下,销毁容器对象由Spring管理完成,无需手动销毁。如果要

           手动销毁需要使用AbstractApplicationContext容器,调用

           AbstractApplicationContext容器的close()方法。

       3)Spring容器的使用方法

          --引入spring核心包

         --在src下添加spring配置文件

         --在spring配置文件定义Bean组件

        <bean id="标识符" class="包名.实现类名">

        </bean>

    eg:

    applicationContext.xml:

     <!-- 定义Bean组件 -->

    <bean id="costDao" class="com.tarena.dao.JdbcCostDAO"></bean>

         --实例化spring容器,通过容器的getBean("标识符")方法获取

     

    eg:

    public static void main(String[] args) {

      // CostDAO costDao = new JdbcCostDAO();

      // costDao.save();

      // costDao.update();

      // 获取Spring容器中的CostDAO

      // 第一步实例化Spring容器

      String conf = "applicationContext.xml";

      // 用于加载src下的xml配置文件

      AbstractApplicationContext ac = new 

           ClassPathXmlApplicationContext(conf);

      // AbstractApplicationContext ac = new FileSystemXmlApplicationContext(); 用于加载磁盘路径的xml配置

      // 获取容器中的DAO

      CostDAO costDao = (CostDAO) ac.getBean("costDao");

      costDao.save();

      costDao.update();

      // ac.close();//销毁Spring容器

    }

    3.Spring容器对Bean组件的管理

     *1)创建Bean对象的方式

         Spring可以采用单例模式和非单例模式创建Bean对象。

         默认情况下,采用单例模式创建Bean对象。

         在<bean scope="">中利用scope属性控制创建模式。

         scope="singleton"采用单例模式,

         scope="prototype"采用原型(非单例)模式

         (在JavaWeb环境中,scope属性值还可以指定request,session等范围)

       如果scope="singleton",Spring容器实例化时,会自动创建Bean组件对象。

         如果scope="prototype",Spring容器会在调用getBean方法时创建Bean对象。

    scope属性的取值介绍:

    在web(仅限于web项目)环境中,还可以设置所创建的bean对象的生命周期和request、session。

    a.request 表示bean对象生命周期和request生命周期相同

    b.session 表示bean对象生命周期和session生命周期相同

    c.global session 相当于application

    d.singleton 单例模式

    e.prototype 原型模式

       2)Bean对象的创建时机

         默认是随着容器创建,可以使用lazy-init=true设置(在调用getBean()创建) 延迟创建

       3)Bean对象的初始化和销毁

         使用<bean init-method="" destroy-method="">

         可以指定Bean对象创建和销毁时触发的方法。

         destroy-method只适用于scope="singleton"模式.

        当调用applicationcontext.close()时,容器会自动销毁所有单例对象,此时会  

        触发指定destory-method方法。

         init-method指定的初始化方法可以在构造方法执行后自动执行。

     4.如何使用Spring容器的IoC机制

      Spring提供的IoC主要是用于建立两个对象(组件、Bean)之间的关系,好处是低耦合方式。

       1)DI(依赖注入技术)

         Dependency Injection 称为依赖注入。意思是采用注入技术建立两个组件

         的依赖关系。

          Spring通过DI技术实现了IoC思想。DI技术可以分成以下几类:

          --setter方式注入(依靠属性的set方法注入)

    <property....></property>对应的注入方式只能是setter注入

     applicationContext.xml配置:

    <!-- 定义Bean组件 -->

    <bean id="costDao" scope="singleton" init-method="myinit"

    destroy-method="mydestroy" class="com.tarena.dao.JdbcCostDAO">

    </bean>

    <bean id="hibernateCostDao

         class="com.tarena.dao.HibernateCostDAO">

    </bean>

    <!-- setter方式注入示例 -->

    <bean id="costAction" scope="prototype" 

          class="com.tarena.action.CostAction">

    <!-- 将ref指定的id属性Bean对象给costDao属性注入 -->

    <property name="costDao" ref="hibernateCostDao"></property>

    </bean>

    其中,name=”costDao”中的costDao为要注入的属性,即public void 

    setCostDao ....方法中的setCostDao()方法名中的除”set”之后的部分

      /** setter方式注入示例*/

    public class CostAction {

    private CostDAO costDao1;

    // spring自动调用该方法,注入一个CostDAO对象

    public void setCostDao(CostDAO costDao) {

    this.costDao1 = costDao;

    }

    public String add() {

    System.out.println("执行资费添加操作");

    costDao1.save();

    return "success";

    }

    }

    --构造方式注入(依靠构造方法注入)

      applicationContext.xml配置:

    <!-- 定义Bean组件 -->

    <bean id="costDao" scope="singleton" init-method="myinit"

    destroy-method="mydestroy" class="com.tarena.dao.JdbcCostDAO">

    </bean>

    <bean id="hibernateCostDao" class="com.tarena.dao.HibernateCostDAO">

    </bean>

    <!-- 构造方式注入示例 -->

    <bean id="costAction1" scope="prototype" 

         class="com.tarena.action.CostAction1">

      <!-- “0”为构造参数索引;"costDao"为要注入的Bean对象的id -->

      <constructor-arg index="0" ref="costDao">

      </constructor-arg>

    </bean>

    其中,<constructor-arg index="构造参数索引"

                ref="要注入的Bean对象的id">

          </constructor-arg>

     

    /**构造方式注入示例*/

    public class CostAction1 {

    private CostDAO costDao1;

    // spring自动调用该方法,注入一个CostDAO对象

    public CostAction1(CostDAO costDao) {

    this.costDao1 = costDao;

    }

    public String add() {

    System.out.println("执行资费添加操作");

    costDao1.save();

    return "success";

    }

             }

    --接口方式注入(了解名称,可以参考spring文档)

       2)IoC思想

          Inverse of Controller 称为反向控制或控制反转,确切讲被称为控制转移,

          意思就是转交控制权。

         所谓控制及控制权:指的是负责对象的创建、初始化以及销毁等工作。

         两个组件,当A调用B时,原有方式需要在A里面编写控制权逻辑代码,

         当需要替换B组件时,需要修改控制权逻辑,因此A和B组件的耦合度比

         较高。

         采用IoC思想后,就是将A中的控制权逻辑转移给第三方容器或框架,有

         第三方框架负责A,B对象的创建,释放,初始化和关系指定等工作。

     

        *3)Action--->DAO采用Spring的IoC方式

           --在Action中定义一个DAO接口类型的变量

           --在Action中定义一个setter方法,主要作用是接收spring注入进

             来DAO对象。

           --将Action和DAO都交给Spring容器,Action配置如下:

            <bean id="action标识符" class="action实现类">

                <!--setter方式注入配置-->

                <property name="属性名" 

                   ref="dao定义时的Bean组件Id值">

                </property>

            </bean>

            参见上例“setter方式注入”

         4)采用构造方式注入重构3示例

              --定义带参数构造方法替代setter方法

              --定义Action的<bean>时,采用

            <constructor-arg>替代<property>配置

           <constructor-arg index="构造参数索引"

               ref="要注入的Bean对象的id">

           </constructor-arg>

    参见上例“构造方式注入”

     

    5.各种类型数据的注入

      1)基本数据注入

         利用value属性指定,可以注入字符串,数值等简单数据。

      2)Bean对象注入

         利用ref属性指定,可以注入一个Bean组件对象

    <bean id="hibernateCostDao" class="com.tarena.dao.HibernateCostDAO">

    </bean>

    <!-- setter方式注入示例 -->

    <bean id="costAction" scope="prototype" 

           class="com.tarena.action.CostAction">

    <!-- 将ref指定的id属性Bean对象给costDao属性注入 -->

    <property name="costDao" ref="hibernateCostDao">

    </property>

        </bean>

      3)集合数据注入

      eg:

    applicationContext.xml配置如下:

    <bean id="msgBean" scope="singleton" class="com.tarena.service.MessageBean">

      <!-- 基本数据注入 -->

      <property name="name" value="露丝">

      </property>

      <!-- 

        其中,value值的类型全部为String型,对于age属性来说,其类型为Int

        型,在属性注入时Spring会自动进行类型转换(String—>int)

       -->

      <property name="age" value="18">

      </property>

      <!-- List集合注入 -->

      <property name="friends">

        <list>

          <value>TOM</value>

          <value>JACK</value>

          <value>张三丰</value>

        </list>

      </property>

      <!-- Set集合注入 -->

      <property name="cities">

        <set>

          <value>北京</value>

          <value>上海</value>

          <value>深圳</value>

        </set>

      </property>

      <property name="includeTypes" value="jpeg,gif,jpg">

      </property>

      <!-- Map集合注入 -->

      <property name="books">

        <map>

          <entry key="1001" value="Core Java基础"></entry>

          <entry key="1002" value="Struts框架详解"></entry>

          <entry key="1003" value="编程之美"></entry>

        </map>

      </property>

      <!-- Properties(本质是Map)属性注入 -->

      <property name="dbParams">

        <props>

          <prop key="username">root</prop>

          <prop key="password">1234</prop>

        </props>

      </property>

    </bean>

    测试类代码:

    public class MessageBean {

      private String name;

      private int age;

      private List<String> friends;

      private Set<String> cities;

      private Set<String> types;

      private Map<Integer, String> books;

      private Properties dbParams;

     

    public void setDbParams(Properties dbParams) {

      this.dbParams = dbParams;

    }

    public void setIncludeTypes(String str) {

      String[] arr = str.split(",");

      types = new HashSet<String>();

      for (String type : arr) {

        types.add(type);

      }

    }

     

    public void setCities(Set<String> cities) {

      this.cities = cities;

    }

     

    public void setFriends(List<String> friends) {

      this.friends = friends;

    }

     

    public void show() {

      /**基本数据注入测试*/

      System.out.println("姓名:" + name);

      System.out.println("年龄:" + age);

      /**List注入测试*/

      System.out.println("---她的朋友---");

      for (String s : friends) {

        System.out.println(s);

      }

      /**Set集合注入测试*/

      System.out.println("---他们所在城市---");

      for (String s : cities) {

        System.out.println(s);

      }

      System.out.println("---允许上传的图片类型---");

      for (String s : types) {

        System.out.println(s);

      }

      /**Map集合注入测试*/

      System.out.println("-----图书信息-----");

      Set<Integer> keys = books.keySet();

      for (Integer key : keys) {

        System.out.println("编号:" + key + " 名字:" + books.get(key));

      }

      /**Properties注入测试*/

      System.out.println("----连接参数-----");

      Set<Object> dbKeys = dbParams.keySet();

      for (Object key : dbKeys) {

        System.out.println(key + ":" + dbParams.getProperty(key.toString()));

      }

    }

    public void setAge(int age) {

    this.age = age;

    }

    public void setName(String name) {

    this.name = name;

    }

    public void setBooks(Map<Integer, String> books) {

    this.books = books;

    }

    }

    *6.什么是AOP,解决什么问题

         Aspect Oriented Programming 面向方面编程也叫面向切面编程

    面向方面编程是以(OOP)面向对象编程为基础,这两种编程思想侧重点不同。OOP侧重于对象,根据需求提炼出对象结构。AOP侧重于方面对象,方面(共同处理组件)关注的是共通处理部分,例如事务管理,权限控制,日志记录等。可以通过配置将其作用到某一个或多个目标对象上。

    好处:实现组件重复利用,改善程序结构,提高灵活性。将共同处理组件与目标对象解耦。

       AOP主要是解决一对多调用问题,一个共通组件被多个目标组件调用,降低组件关联。

    *7.Spring容器AOP的基本使用

     1)引入spring-aop开发包

     2)编写方面组件,封装共通的处理逻辑

     3)在spring配置文件中,定义方面组件,利用aop配置,将方面组件方

        法和目标组件方法作用在一起。

    8. AOP相关概念

        *1)方面(Aspect)

            方面(组件)指的是共同业务处理,可以切入到(即作用到)多个目标

            对象,可以多次使用。

        *2)切入点(Pointcut)

            切入点是连接点(Pintcut)的集合,采用表达式指定,用于指定哪些

            组件和方法作为方面组件的切入目标。

    *(1)方法限定表达式

       可以规定哪些方法被切入方面组件,哪些不被切入,也就是

       定义目标对象,格式如下:

    execution(修饰符? 返回类型 方法名(参数) throws异常? )

       示例1:匹配容器中Bean对象的find开始的方法

               execution(* find*(..))

    第一个“*”表示返回类型不限,"find*"表示以“find

    ”开头的所有方法,".."表示一个或多个参数(也即参

    数不限)

       示例2:匹配CostServiceImpl类中所有方法

          execution(* tarena.service.CostServiceImpl.*(..))

       示例3:匹配tarena.service包下所有类的所有方法

        execution(* tarena.service.*.*(..))

       示例4:匹配tarena.service包及其子包下所有类所有方法

        execution(* tarena.service..*.*(..))

       示例5:匹配容器Bean对象中的find开始的方法,并且是 public void 修饰的

         execution(public void find*(..))

       *(2).类型限定表达式

         可以规定哪个类中的所有方法被切入方面组件

        格式:within(包名.类型名)

        示例1:匹配CostServiceImpl类中所有方法

         within(tarena.service.CostServiceImpl)

        示例2:匹配tarena.service包下所有类所有方法

           within(tarena.service.*)

        示例3:匹配tarena.service包及其子包中所有类所有方法

           within(tarena.service..*)

       (3).Bean的Id或Name名称限定

         可以按<bean>定义时,id或name属性值匹配  

          bean(beanIdOrName)

          示例1:匹配容器中id=costService的Bean对象

          bean(costService)

        示例2:匹配容器中id值以Service结尾的对象

            bean(*Service)

       (4).参数类型限定

         args(参数类型列表)

         示例1:匹配有且只有一个参数,参数类型符合Serializable类型的方法

           args(java.io.Serializable)

       *注意:上述切入点表达式可以联合使用,采用&&,||连接

         3)连接点(JoinPoint)

           // 连接点的集合组成切入点,连接点指的是切面组件在目标对象上

      // 作用的位置,例如:在方法调用前、方法调用后、或者发生异常。

           切入点是连接点的集合。代表方面组件和某一个目标方法的关联点。

        *4)通知(Advice)

            用于指定方面组件作用于目标对象中的目标方法的时机。例如前置

            通知,意思是先执行方面组件,再执行目标方法。

       Spring提供了5种类型的通知。用于指定方面组件在目标方法哪个位置切入。

       a.前置通知 <aop:before>

          先执行方面组件,再执行目标组件方法

       b.后置通知 <aop:after-returning>

          先执行目标组件方法,没有异常再执行方面组件。

          如果发生异常,不会执行方面组件

       c.异常通知 <aop:after-throwing>

          当目标方法抛出异常之后,执行方面组件。

       d.最终通知 <aop:after>

          先执行目标方法,无论有没有异常都执行方面组件

       e.环绕通知 <aop:around>

          相当于前置+后置通知。在目标方法前和后都执行方面组件

       内部实现原理:

    try{

         //前置通知切入

      //环绕前置通知切入

         //目标组件方法

      //环绕后置通知切入

         //后置通知切入

       }catch(){

        //异常通知切入

       }finally{

         //最终通知切入

       }

         5)目标对象(Target)

            方面组件作用的对象,即与切入点表达式匹配的对象。

         6)动态代理(AutoProxy)

           Spring采用了动态代理技术实现了AOP控制。

           如果Spring采用了AOP配置后,容器getBean方法返回的组件对象

           是代理对象(一个动态生成类型,即动态代理类),用户在使用时,由

           代理对象调用切面组件和目标对象的功能。

         Spring采用的动态代理技术有以下两种:

          a.目标对象没有接口(使用cglib.jar工具包)

          适用于目标组件没有接口实现的情况。

     public class $Service$$Enhancer$CGLIB extends  原目标组件类型{

        //重写目标对象的方法,在重写的方法中调用目标对象和方面组件对象功能

     }

      b.目标对象有接口(采用JDK Proxy API)

          适用于目标组件有接口实现的情况。

          public class $Proxy4 implements 原目标组件接口{

             //重写目标接口方法,在重写的方法中调用目标对象和方面组件对 

               象功能

           }

        public void testDelete() {

        String[] confs = { "applicationContext.xml" };

        ApplicationContext ac = new ClassPathXmlApplicationContext(confs);

        CostService service = (CostService) ac.getBean("costService");

        System.out.println("类名:"+service.getClass().getName());

        //获得代理类中的所有public方法

                 Method[] ms =service.getClass().getMethods();

        for(Method m : ms){

          System.out.println(m);

        }

      service.deleteCost();

    }

          程序运行结果如下:

    类名:$Proxy4

    public final void $Proxy4.addCost()

    public final void $Proxy4.deleteCost()

    public final void $Proxy4.findById()

    public final boolean $Proxy4.isFrozen()

    public final org.springframework.aop.TargetSource 

          $Proxy4.getTargetSource()

    public final void 

          $Proxy4.addAdvisor(int,org.springframework.aop.Advisor) 

     

      从以上结果可以看出,动态代理类中重写了原实现类中的

             addCost()、deleteCost()、findById()方法并加入了方面(共同

             处理的方法),这样就可以实现对目标对象实现方面切入。

     

  • 相关阅读:
    【FZYZOJ】细菌 题解(最短路)
    oracle 开发 第02章 查询
    oracle 开发 第01章 简介
    rhel配置163、epel、rpmforge的yum源
    linux 手动清除缓存
    查看linux内核版本和发行版本
    linux下安装rlwrap
    linux下安装vncserver
    Nagios 安装
    linux mutt发送报表
  • 原文地址:https://www.cnblogs.com/qq739178184/p/5083462.html
Copyright © 2011-2022 走看看