首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

Spring学习小结(一)

2013-09-17 
Spring学习总结(一)SpringSpring基本功能详解:Spring的控制反转:把对象的创建、初始化、销毁等工作交给sprin

Spring学习总结(一)
Spring
    Spring基本功能详解:
        Spring的控制反转:把对象的创建、初始化、销毁等工作交给spring容器来做。
        由spring容器控制对象的生命周期。    
    
        步骤:
            启动spring容器
            在类路径下寻找配置文件来实例化容器
                         ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});可以在整个类路径中寻找xml文件
                      * 通过这种方式加载。需要将spring的配置文件放到当前项目的classpath路径下
                    
                      *  classpath路径指的是当前项目的src目录,该目录是java源文件的存放位置。

            在文件系统路径下寻找配置文件来实例化容器

            ApplicationContext ctx = new FileSystemXmlApplicationContext(new String[]{“d:\\beans.xml“});Spring的配置文件可以指定多个,可以通过String数组传入。
                     注:经常用第一种方法启动容器
            从spring容器中提取对象。

    
    别名:
        <beans>
            <alias name="person" alias="p"/>
            <bean name="person" class="cn.itcast.aliasspring.Person"/>
        </beans>

        通过这样的配置可以达到在一个地方命名,在多个不同的地方使用不同的名字的效果。



Spring创建对象的方式:
    1.无参构造函数
        <bean id="personService" class="cn.itheima.bean.PersonServiceImpl"/>
    
    2.静态工厂:
        <bean id="personService" class ="cn.itcast.factory.PersonServiceFactory"
                     factory-method="createPersonService"/>

      在类中提供createPersonService方法即可。

    3.实例工厂:



关于对象的scope:
    1.singleton(默认值)
         在每个Spring IoC容器中一个bean定义只有一个对象实例(共享)(单例)。
        
         默认情况下会在容器启动时初始化bean,但我们可以指定Bean节点的lazy-init=“true”来延迟初始化bean,
         这时候,只有第一次获取bean会才初始化bean。
         如:
        
         <bean id="xxx" class="cn.itcast.OrderServiceBean" lazy-init="true"/>
         如果想对所有bean都应用延迟初始化,可以在根节点beans设置default-lazy-init=“true“,
        
         如下:
         <beans default-lazy-init="true“ ...>


    2.prototype
           允许bean可以被多次实例化(使用一次就创建一个实例) . Spring不能对一个prototype bean的整个生命周期负责.
           这就意味着清楚prototype作用域的对象并释放任何prototype bean所持有的昂贵资源都是客户端的责任。

    3.Request
        在一次HTTP请求中,一个bean定义对应一个实例:即每次HTTP请求将会有各自bean实例,他们依据某个bean定义创建而成。
        该作用域仅在基于Web的Spring applicationContext情形下有效。

    
    4.session
        在一次HTTPsession中,一个bean定义对应一个实例:即每次HTTP请求将会有各自bean实例,他们依据某个bean定义创建而成。
        该作用域仅在基于Web的Spring applicationContext情形下有效。

    5.Global session
        在一个全局HTTP session中,一个bean定义对应一个实例:即每次HTTP请求将会有各自bean实例,他们依据某个bean定义创建而成。
        该作用域仅在基于Web的Spring applicationContext情形下有效。





spring初始化bean的时机:
        
    Spring默认在启动时将所有singleton bean提前进行实例化。提前实例化意味着作为初始化的一部分,ApplicationContext会自动创建并配置所有的singleton bean.通常情况下这是件好事。因为这样在配置中有任何错误能立即发现。
        Lazy-init=”true or  false”
        Lazy-init 为false,spring容器将在启动的时候报错(比较好的一种方式)
        Lazy-init 为true,spring容器将在调用该类的时候出错。


bean的init、destroy(初始化和销毁)
          Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法。
          <bean id=“foo” class=“...Foo”
                init-method=“setup”
                destory-method=“teardown”/>
         当foo被载入到Spring容器中时调用init-method方法。当foo从容器中删除时调用destory-method(scope = singleton有效)。


Spring的DI(依赖注入)
    xml形式:
        使用构造器注入:
        
        使用xml的注入方式:
            通过参数的顺序
            <constructor-arg index="0">
                  <value>张三</value>
            </constructor-arg>
            <constructor-arg index="1">
                   <value>56</value>
             </constructor-arg>
            
            通过参数的类型
            <constructor-arg type="java.lang.Integer">
                      <value>56</value>
                   </constructor-arg>
                   <constructor-arg type="java.lang.String">
                      <value>张三</value>
                   </constructor-arg>

    使用属性setting方法进行注入:
        使用xml的注入方式:
            简单Bean的注入
            简单Bean包括两种类型:包装类型和String
            
            <bean id="personService"   class="com.itcast.bean.impl.PersonServiceImpl">
                <!-- 基本类型,string类型 -->
                <property name="age" value="20"></property>
                <property name="name" value="张无忌"></property>                   
            </bean>
            
            引用其他Bean
            <bean id="person" class="com.itcast.bean.Person" />
            
             <bean id="personService"  class="com.itcast.bean.impl.PersonServiceImpl">
                <property name="person" ref="person" />
            </bean>

        装配list集合
            <property name="lists">
                <list>
                    <value>list1</value>
                    <value>list2</value>
                    <ref bean="person"/>
                <list>
            </property>


        装配set集合
            <property name="sets">
                <set>
                    <value>set1</value>
                    <value>set2</value>
                    <ref bean="person"/>
                <set>
            </property>

        装配map
            <property name="maps">
                 <map>
                  <entry key="01">
                      <value>map01</value>
                  </entry>
                  <entry key="02">
                      <value>map02</value>
                  </entry>    
                 </map>
            </property>

        map中的<entry>的数值和<list>以及<set>的一样,可以使任何有效的属性元素,需要注意的是key值必须是String的。

    
    装配Properties:
        <property name="props">
           <props>
             <prop key="01">prop1</prop>
             <prop key="02">prop2</prop>
           </props>
        </property>  



注解形式:
    步骤:
        在配置文件中,引入context命名空间
              <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"
                xsi:schemaLocation="http://www.springframework.org/schema/beans
                                http://www.springframework.org/schema/beans/spring- beans-2.5.xsd
                                http://www.springframework.org/schema/context
                             http://www.springframework.org/schema/context/spring-context-2.5.xsd">
                在配置文件中加入context:annotation-config标签
                       
                <context:annotation-config/>
                
                 这个配置隐式注册了多个对注释进行解析处理的处理器

                    AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,
                    PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor
                 注: @Resource注解在spring安装目录的lib\j2ee\common-annotations.jar

    
    1、 这两个注解的区别是:
        @Autowired 默认按类型装配。

            @Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,
            可以设置它required属性为false。
            例: @Autowired(required=false)

                 如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。
            如下:

            例: @Autowired@Qualifier("personDao")
        
        @Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
            1. @Resource 注解和 @Autowired一样,也可以标注在字段或属性的setter方法上.

            2. @Resource 注解默认按名称装配。

            3. 名称可以通过 @Resource的name属性指定,如果没有指定name属性:
                1)当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象.

                2)当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。
        
        注意:如果没有指定name属性,并且按照默认的名称找不到依赖对象时, @Resource注解会回退到按类型装配。
              但一旦指定了name属性,就只能按名称装配了。

    


    @PostConstruct :指定Bean的初始化方法.

    @PreDestroy  :     指定Bean的销毁方法.






扫描机制:
    前面的例子我们都是使用XML的bean定义来配置组件。在一个稍大的项目中,通常会有上百个组件,
    如果这些组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便。
    spring2.5为我们引入了组件自动扫描机制,它可以在类路径底下寻找标注了:
        @Component 、 @Service 、 @Controller、 @Repository注解的类,并把这些类纳入进spring容器中管理。
        
    它的作用和在xml文件中使用bean节点配置组件是一样的。要使用自动扫描机制,我们需要打开以下配置信息:

    <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"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context-2.5.xsd">
            
        <context:component-scan base-package="cn.itcast"/>
    
    </beans>



       在配置文件中添加context:component-scan标签。
    
          <context:component-scan base-package="cn.itcast"/>
             其中base-package为需要扫描的包(含含其下所有子包)。

    


  注:
       1、在使用组件扫描元素时,AutowiredAnnotationBeanPostProcessor和
        CommonAnnotationBeanPostProcessor会隐式地被包括进来。 也就是说,连个组件都会被自动检测并织入
        - 所有这一切都不需要在XML中提供任何bean配置元数据。

       2、功能介绍
           @Service用于标注业务层组件、
           @Controller用于标注控制层组件(如struts中的action)、
           @Repository用于标注数据访问组件,即DAO组件。
           而 @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
    



Spring中的继承:
    类的继承关系在spring中的配置文件中要声明出来,否则是不行的
    范例:
        <bean id="student" class="cn.itcast.spring.extend.Student" parent="person" />

    配置文件中,parent为student在容器中继承person.如果去掉person是不行的。





IOC和DI的意义:
    核心:面向切面编程。

    1.代理模式:
        代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,
        就是一个人或者一个机构代表另一个人或者另一个机构采取行动。
        在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.

    抽象主题角色
        声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以是使用代理主题
    
    代理主题(Proxy)角色:
        代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象;
        代理主题角色提供一个与真实主题角色相同的接口,以便可以在任何时候都可以替代真实主题控制对真实主题的引用,
        负责在需要的时候创建真实主题对象(和删除真实主题对象);代理角色通常在将客户端调用传递给真实的主题之前或之后,
        都要执行某个操作,而不是单纯地将调用传递给真实主题对象。
    
    真实主题角色
        定义了代理角色所代表地真实对象.





 JDK的动态代理必须具备四个条件:
       1.. 目标接口
           2.. 目标类
           3.. 拦截器
           4.. 代理类


  总结:1、因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有。
     2、生成的代理类的所有的方法都拦截了目标类的所有的方法。
         而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体。
        3、利用JDKProxy方式必须有接口的存在。
        4、invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型。




   CGLIB做代理:
    1.CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
    2.用CGlib生成代理类是目标类的子类。
    3.用CGlib生成 代理类不需要接口
    4.用CGLib生成的代理类重写了父类的各个方法。
    5.拦截器中的intercept方法内容正好就是代理类中的方法体



spring有两种代理方式:
    1.若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
          优点:因为有接口,所以使系统更加松耦合
          缺点:为每一个目标类创建接口
    2.若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
          优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
          缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。



AOP编程:
    Aspect(切面)
          比如说事务、权限等,与业务逻辑没有关系的部分
    
    joinpoint(连接点)
             目标类的目标方法。(由客户端在调用的时候决定)
    
    Pointcut(切入点)
        所谓切入点是指我们要对那些拦截的方法的定义.
              被纳入spring aop中的目标类的方法。
    
    Advice(通知)
        所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,
        环绕通知(切面要完成的功能)
    
    Target(目标对象):
               代理的目标对象
    
    Weaving(织入)
        是指把切面应用到目标对象来创建新的代理对象的过程.切面在指定的连接点织入到目标对象 。


1、概念
    面向切面编程
2、意义
    场景
        在编程的过程中,会遇到这样的情况:
            在一个类中,有很多方法,这些方法有一个共性,就是在进行数据库操作的时候,需要开启事务和提交事务,
            这样每个方法中都得写开启事务和事务提交的代码,我们能不能把这些代码只写一次呢?
    实现
        切面:
            我们可以把上述的这种场景的事务的开启和提交提取出来,写在一个类中,这样的类为切面
        通知:
            把该类中的两个方法:事务的开启和提交为通知
        目标类:
            我们可以把在方法中对业务逻辑(数据库中数据的操作)的操作所在的类为目标类
        目标方法:
            实现业务逻辑的方法为目标方法,例如:在student表中插入一行数据
        AOP代理:
            利用动态代理模式生成的代理对象
        代理对象的方法
            代理对象的方法把通知与目标方法结合在了一起
        连接点:
            代理对象调用的方法为连接点,需要说明的是代理对象的机制有两种
                1、代理对象和目标对象实现了共同的接口
                2、代理对象是目标对象的子类
            所以连接点也可以说是目标类中的一个方法
    通知
        前置通知
            1、在目标方法执行之前执行
            2、方法中可以有一个参数:PointJoint,从这个参数中可以获取目标方法的信息
            3、前置通知的应用场合:
                1、可以执行日志
                2、如果目标方法涉及到数据库的操作,前置通知可以做开启事务的操作
                3、如果要统计一个方法被访问的次数,可以通过前置通知设计计数器来实现
        后置通知
            1、在目标方法执行之后执行
            2、可以获取目标方法的返回值
            3、如果目标方法遇到异常,后置通知将不再执行
            4、应用场合:
                1、可以在后置通知中提交事务
                2、在完成业务逻辑操作以后,可以执行一些额外的操作:发email等
        最终通知
            1、在目标方法执行之后执行
            2、无论目标方法是否遇到异常,都执行
            3、相当于代码中的finally
        异常通知
            1、可以获取目标方法抛出的异常
            2、应用场合:
                在mvc结构中,如果把service层的所有的类当做目标类,该通知可以成为异常处理的统一接口
        环绕通知
            1、可以控制目标方法的执行

3、说明
    1、在spring容器中,spring容器会自动根据目标类是否实现接口,选择采用哪种动态代理实现代理对象
        1、目标类实现了接口,则采用jdk动态代理
            代理对象和目标对象实现了相同的接口
        2、目标类没有实现接口,则采用cglib动态代理
            代理类是目标类的子类
    
    2、我们可以利用springAOP很好的把hibernate中的重复性代码抽取出来
        1、写一个事务类     切面
            两个方法:
                开启事务  前置通知
                提交事务  后置通知
        
        2、目标类
        
        3、代理类
            生成的代理类的方法:
                1、开启事务
                2、执行数据库的操作
                3、事务的提交
    
    3、我们可以利用springAOP的特点,给目标类创建异常处理切面
    
    4、在目标类的上下文可以建立很多个切面,这些切面可以处理:事务、日志、计数器、缓存等

4、扩展
    AOP在企业中做到了:
        日志可以由专门的人处理,因为现在日志的数量和种类越来越多了
        事务由专门的人处理,现在的系统,事务变得很复杂
        缓存由专门的人处理:有些人估计更擅长于缓存的操作
        业务逻辑由专门的人处理:有些人估计对需要把握特别准确
        在客户端生成的代理对象的方法把这些内容全部整合在了一起,但是上面的各个内容是送耦合的








    JDKProxy代理                SpringAop

    目标对象                目标对象
    拦截器类                切面
    拦截器类中的方法            通知
    被拦截到的目标类中方法的集合        切入点
    在客户端调用的方法(目标类目标方法)    连接点
    代理类                    AOP代理
    代理类的代理方法生成的过程        织入
        
    通知根据拦截目标类中的目标方法的位置不一样可以分为:前置通知、后置通知、最终通知、环绕通知、异常通知。






AOP实现的两种模式:
    1.xml形式:
    2.注解形式:
    (待补全)



spring的事务管理:
    1、原理
        1、基于的原理是aop
        2、标题分析
            这个标题可以分解为这几个词:
                声明式    
                    程序员对目标方法进行声明
                事务处理
                    spring容器负责处理事务
        3、说明:
            1、目的
                这个技术的目的是让程序员不再关注事务,而只关注做自己的事情
            2、利用AOP可以达到这个目的
                1、程序员做数据库的操作
                2、让spring容器做事务
    2、步骤:
        1、写java类,dao层和service层
        2、写spring的配置文件
            1、引入sessionFactory
            2、引入事务管理器
            3、引入AOP的配置
            4、配置AOP
            5、配置事务通知
    3、spring中处理事务的框架
        1、顶级接口
            PlatformTransactionManager
                getTransaction
                commit
                rollback
        2、抽象类
            AbstractPlatformTransactionManager
                对commit、rollback方法进行了实现
        3、具体类
            DataSourceTransactionManager,HibernateTransactionManager等
        4、说明:
            在spring内部,都是面向接口编程(这点从HbiernateTemplate中可以体会),而接口的实现类是需要通过spring配置文件注入进去的,所以任何一个数据库
            操作框架只要知道spring的结构,很容易整合到spring容器中
    4、spring声明式事务处理的缺点
        从原理上可以看出,如果一个类的方法中有数据库的操作,如果该类的事务处理想交给spring容器来做,那么必须满足:
            1、把该类放入到spring容器中
            2、为该类生成代理对象
        如果存在这样的情况:
            例如在jbpm工作流中,有些类是由jbpm内部调用的,但是这些类的方法中如果需要事务呢?答案是用spring容器做事务做不到
    5、关于声明式事务处理的session
        由于必须保证数据库操作的session和事务的session是同一个session,所以session必须由当前线程产生

热点排行