Spring核心概念

一、Spring框架概述
    1、轻量级的Java EE开源框架,它是由Rod Johnson为了解决企业应用程序开发的复杂性而创建,
        Spring框架提供了一个开发平台,用于整合其他技术,例如Struts,Hibernate,Mybatis等。
        例子:
            把Spring比作一台电脑的主板,它为各种硬件设施(CPU,内存,硬盘)提供了接口,
            这样做的好处是,在改善系统的结构方面,更利于系统的扩展和升级。

    2、包含的内容:
        IoC容器(控制反转IoC,依赖注入DI)
        AOP实现(面向切面编程)
        数据访问支持
           简化JDBC/ORM框架    ORM( Hibernate(Nhibernate),iBATIS,mybatis,EclipseLink,JFinal)
            声明式事务
        Web集成

    3、作用:
        a、实现一个全方位的整合框架,实现“一站式”的企业应用开发
        b、提供了整合其他技术的API
        c、提供了创建对象的功能,这样Spring就编程了一个大的工厂,所以spring是一个具有工厂功能的框架
        d、spring提供了两种非常重要的机制IOC和AOP,这样的好处是降低了组件对象之间的耦合度,实现了对象之间的解耦。

    4、Spring优点
        低侵入式设计
        独立于各种应用服务器
        依赖注入特性将组件关系透明化,降低了耦合度
        面向切面编程特性允许将通用任务进行集中式处理
        与第三方框架的良好整合

二、Spring框架基本应用
    1、对象创建功能
        使用配置文件:
           a.添加spring-ioc开发jar包到工程
           b.在src下添加applicationContext.xml配置文件
           c.将bean组件在配置文件中定义(bean组件也就是程序中需要使用spring创建的对象),
           d.实例化spring容器对象,调用getBean("标示符")获取Bean对象。

        使用Spring IoC解耦合步骤:           
            创建工程并添加Spring的jar包
            创建业务层和数据访问层接口
            编写业务层和数据访问层实现类
            在业务实现类中添加DAO接口引用和相关访问器,注意JavaBean命名规范
            编写Spring配置文件,完成业务层和数据访问层装配

    2、IOC机制
        A、概念:
            控制反转,可以理解为组件之间的调用,将组件对象的创建和关系的建立由第三方框架或容器负责。

        B、IOC实现原理----依赖注入(DI)
            当两个组件存在使用关系时,也就是存在依赖关系时。
            依赖关系建立可以通过以下几种注入途径:
            a、setter方式注入,通过set方法将DAO传入
                在Action中定义属性变量和set方法
                在定义配置时,指定注入

            b、构造方式注入
                通过构造器将DAO传入
                在Action中定义属性变量和带参数的构造方法
                在定义配置时,指定注入

        C、实现思想
            将组件对象的控制权从代码本身转移到外部容器
            组件化的思想:分离关注点,接口和实现分离
            依赖的注入:将组件的构建和使用分开(运行时注入)
            目的:解耦合。实现每个组件时只关注组件内部的事情
            要点:明确定义组件间的接口

        D、Spring Bean封装机制
            Spring以Bean的方式管理所有的组件,Java EE的全部组件都被视为Bean管理
            Bean在Spring的容器中运行,Spring负责创建Bean的实例,并管理其生命周期

        E、Bean的作用域
            singleton            在Spring容器中仅存在一个共享的Bean实例
            prototype            每次从容器中都获取一个新的实例
            request                每次HTTP请求都会创建一个新的Bean实例
            session                同一个HTTP请求共享一个Bean实例
            global session        同一个全局Session共享一个Bean实例

            如何使用:
                唯一实例:(Bean的作用域默认情况就是为单例:scope="singleton")
                <bean id= "user" class= "entity.User " />或
                <bean id= "user" class= "entity.User" scope= "singleton" />

                创建新实例:
                <bean id= "user" class= "entity.User" scope= "prototype " />

        F、BeanFactory
            由org.springframework.beans.factory.BeanFactory接口定义
            方法:
                getBean(String name)
                containsBean(String name)
                getType(String name)
            它是工厂模式(Factory pattern)的实现,主要负责创建和管理bean

            子接口:ApplicationContext
                实现类    ClassPathXmlApplicationContext
                实现类    FileSystemXmlApplicationContext

            如何使用整合多个配置文件:
                ApplicationContext context = new ClassPathXmlApplicationContext(
                    new String[] {"conf/beans1.xml" , "conf/beans2.xml"} );

    3、AOP机制
        A、概念:
            AOP又被称为面向方面编程,其实就是在面向对象的基础上又进行了一次封装,由于面向对象是将共同的属性和方法封装起来,
            而面向切面编程则是面向共同的方面逻辑,如事务和异常,所有的对象都会产生这样一个共性的方面。
            它将复杂的需求分解出不同方面,将散布在系统中的公共功能集中解决 
            面向切面编程:
                是一种通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态添加功能的技术       

        B、为什么使用AOP?
            a、就是为了方便,把自己做的事情都让Spring容器去做了。用了AOP能让开发人员少写很多代码
            b、就是为了更清晰的逻辑,可以让我的业务逻辑去关注自己本身的业务,而不去想一些其他的事情。这些其他的事情包括:安全,事物,日志等等。

        B、OOP与AOP的区别:
            这两种设计思想在目标上有着本质的差异。具体如下:
            OOP:针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分
            AOP:针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或者阶段,
                 以获得逻辑过程中各部分之间低耦合的隔离效果。

        C、AOP编程概念(相关术语)
            a.切面(Aspect)
                封装共通处理部分的组件。方面组件可以被切入到其他目标组件方法上。
                切面由切点和增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP就是负责实施切面的框架,
                它将切面所定义的横切逻辑织入到切面所指定的连接点中。

            b.切入点(Pointcut)
                负责指定哪些组件方法调用方面(共通)处理,通过一个表达式指定。
                每个程序类都拥有多个连接点,如一个拥有两个方法的类,这两个方法都是连接点。AOP是通过“切点”定位特定的连接点。
                通过数据库查询的概念来理解切点和连接点的关系:连接点相当于数据库中的记录,而切点相当于查询条件。一个切点可以匹配多个连接点。
                如:<aop:pointcut id="servicePointcut" expression="execution(public * com.pb.service.*.*(..))" />
                    //切入点表达式,符合该表达式的方法可以被织入增强处理

                表达式匹配规则:
                    public * addUser(entity.User):                  "*"表示匹配所有类型的返回值
                    public void *(entity.User):                         "*"表示匹配所有方法名
                    public void addNewUser (..):                    ".. "表示匹配所有参数个数和类型
                    *com.service.*.*(..):               这个表达式匹配com.service 包下所有类的所有方法
                    *com.service..*(..):                这个表达式匹配com.service 包及其子包下所有类的所有方法

            c.连接点(JoinPoint)
                程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。这些代码中的特定点,称为“连接点”。
                Spring仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用前后这些程序执行点织入增强。
                切入点是连接点的集合。连接点包含了切面和目标方法关联的信息。
                如:当前作用的目标组件类型和作用的方法名等信息。

            d.通知或者增强处理(Advice)
                就是你想要的功能,像安全、事务、日志等。给先定义好,然后再想用的地方用一下。包含Aspect的一段处理代码
                负责指定方面处理和目标组件方法之间的作用关系。
                例如先执行方面处理再执行目标处理;先执行目标处理再执行方面处理等
                增强是织入到目标类连接点上的一段程序代码。
                增强既包含了用于添加到目标连接点上的一段执行逻辑,又包含了用于定位连接点的方为信息,
                所以Spring所提供的增强接口都是带方位名的:
                    BeforeAdvice(方法调用前的位置)、AfterReturningAdvice(访问返回后的位置)、ThrowsAdvice等。

            e.目标对象(Target)
                启用方面处理的组件,即切入点指定的组件,增强逻辑的织入目标类。

            f、织入
                织入是将增强添加到目标类具体连接点上的过程。AOP有三种织入方式
                1)编译期织入,这要求使用特殊的Java编译器;
                2)类装载期织入,这要求使用特殊的类装载器;
                3)动态代理织入,在运行期为目标类添加增强生成子类的方式。
                Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

        D、AOP的实现方法:
            AOP是通过使用动态代理(设计模式)技术实现的,
            要点:
                通过代理对象来调用原对象的方法
                代理对象方法前后都可以插入代码,这些代码就是增强处理

            当采用AOP切入之后,Spring容器返回的目标对象是采用动态代理技术生成的一个类型。
            该类型会重写原目标的方法,内部会调用原目标的方法和方面处理。

        E、Spring AOP的主要工作
            通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前、方法后、方法两端等等)
            Spring AOP 通过Pointcut(切点)指定在哪些类的哪些方法上织入横切逻辑
            Spring通过切面将Pointcut和Advice两者结合起来
            Spring利用JDK动态代理技术或GCLib为目标Bean创建织入切面的代理对象

        F、Spring AOP代理机制
            一种是基于JDK的动态代理,另一种是基于CGLib的动态代理。
            之所以需要两种代理机制,很大程度上是因为JDK本身只提供接口的代理,而不支持类的代理。

            a、JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。

            b、CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。

            研究表明
                CGLib所创建的动态代理对象的性能比JDK的所创建的代理对象的性能高了不少。
                但CGLib在创建代理对象时所花费的时间却比JDK动态代理多,
                所以对于singleton的代理对象或者具有实例池的代理,因为无须频繁创建代理对象,所以比较适合用CGLib动态代理技术,
                反之则适合用JDK动态代理技术。 
                另外,
                    CGLib不能对目标类中的final方法进行代理。

三、IoC和AOP使用扩展
    1、属性的注入的多种方法:
        1.设置注入(set注入)
        2.构造注入(使用构造方法注入)
        3.使用内部bean注入(实际上是set注入)
        4.使用p命名空间注入(实际上是set注入)
        5.自动装配(相当于自动注入)

    2、设置注入,需要在被注入的类中有注入类的对象属性,并且设置了set的方法,而且set方法需要符合命名规范
        <property name="被注入属性名">
            <ref bean="注入的属性命"/>
        </property>

        <ref> 中的bean属性 可以和 local属性换着使用,但是他们两个属性的查找范围是不一样的
        注意:
            bean的查找范围是所有配置文件
            local的查找范围是当前配置文件

    3.构造注入
        a、需要创建一个带有注入参数的构造方法
        b、然后在配置文件中使用<constructor-arg>标签代替<property>标签
        c、有多少个输入注入的参数就添加多少个<constructor-arg>标签,参数的位置使用index属性
            <constructor-arg index="参数位置">
                <ref bean="注入的属性名"/>
            </constructor-arg>

    4.使用内部bean注入
        <property name="被注入属性名">
            <bean class="需要注入的类的全路径"></bean>
        </property>

    5.使用p命名空间注入
        a.使用前需要导入新的命名空间
            xmlns:p="http://www.springframework.org/schema/p"
        b.对需要注入属性的<bean>添加属性p:属性名-ref="被注入的属性对象"

    6.自动装配
        a.全局设置自动装配
        b.局部设置自动装配

        有4中自动注入的标准
            1.no
            2.byName        根据配置文件中bean的名字和注入类中属性名字对应
            3.byType        根据配置文件中bean的类型和注入类中属性的类型
            4.constructor        和bytype一样,只是一个以构造方法注入,一个是set注入

    7、注意事项:
        根据属性注入的时候,要求对应的bean类型对象是唯一的,如果有多个相同属性
        自动装配会抛出异常,没有匹配的就啥都不错

        a.设置全局自动装配
            <beans>标签中加入属性: default-autowire="注入标准"

        b.设置局部自动装配
            <bean>标签中加入属性: autowire="注入标准"

四、SSH框架整合
    1、系统程序架构的整合思路:
        逆依赖方向而行,由Spring提供对象管理和服务
?        依次实现Spring与Hibernate、Spring与Struts 2的集成

    2、在Spring中配置数据源和会话工厂
        1)配置数据源
            <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
                <property name="driverClassName" value="oracle.jdbc.OracleDriver"></property>
                <property name="url" value="jdbc:oracle:thin:@localhost:1521:jbit"></property>
                <property name="username" value="jbit"></property>
                <property name="password" value="jbit"></property>
                <property name="maxActive" value="100"></property><!-- 最大活动链接数 -->
                <property name="maxIdle" value="10"></property><!-- 最大空闲连接数 -->
                <property name="maxWait" value="10000"></property><!-- 最大等待链接时间 ,毫秒为单位  10s-->
            </bean>

        2)配置辅助参数及映射文件
            <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
                方法一:定义独立的Hibernate配置文件,由Spring导入并创建会话工厂Bean
                <!-- <property name="configLocation" value="classpath:hibernate.cfg.xml"></property> -->

                方法二:在Spring配置文件中进行集中配置
                <!-- 引入数据源 -->
                <property name="dataSource" ref="dataSource"></property>
                <!-- 以键值对形式配置辅助参数 -->
                <property name="hibernateProperties">
                    <props>
                        <prop key="dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                        <prop key="format_sql">true</prop>
                        <prop key="show_sql">true</prop>
                        <prop key="current_session_context_class">thread</prop>
                        <prop key="javax.persistence.validation.mode">none</prop>
                    </props>
                </property>

                <!-- 配置映射文件 -->
                a、持久化类的映射文件可以逐个配置
                <!-- <property name="mappingResources">
                    <list>
                        <value>com/ljw/ssh/entity/BizClaimVoucher.hbm.xml</value>
                        <value>com/ljw/ssh/entity/BizCheckResult.hbm.xml</value>
                        <value>com/ljw/ssh/entity/BizClaimVoucherDetail.hbm.xml</value>
                        <value>com/ljw/ssh/entity/SysEmployee.hbm.xml</value>
                        <value>com/ljw/ssh/entity/SysDepartment.hbm.xml</value>
                        <value>com/ljw/ssh/entity/SysPosition.hbm.xml</value>
                    </list>
                </property> -->

                <!-- 简化写法  也可按目录导入 -->
                <property name="mappingDirectoryLocations">
                    <list>
                        <value>classpath:com/ljw/ssh/entity/</value><!-- 也是以数组形式, -->
                    </list>
                </property>

    3、配置声明式事务
        A、好处:
            采用AOP的方式实现,简化了以前hibernate硬编码方式,使得代码逻辑清晰,不易破坏分层,代码也易于维护

        B、核心问题
            对哪些方法,采取什么样的事务策略

        C、配置步骤
            a、导入tx和aop命名空间
                xmlns:aop="http://www.springframework.org/schema/aop"
                xmlns:tx="http://www.springframework.org/schema/tx"

                xsi:schemaLocation="
                    http://www.springframework.org/schema/aop
                    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
                    http://www.springframework.org/schema/tx
                    http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

            b、配置事务管理器,注入会话工厂sessionFactory
                <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
                    p:sessionFactory-ref="sessionFactory"></bean>

            c、基于该事务管理器配置事务增强,指定事务规则
                <tx:advice id="txAdvice" transaction-manager="transactionManager" >
                    <tx:attributes>
                        <tx:method name="find*" propagation="SUPPORTS"/><!-- 不采用事务,前面开启了事务,也不影响 -->
                                    <!-- read-only=true,则不会自动清缓存 ,read-only默认为false,自动清理缓存,但是若和增删改合作,可能会影响到他们的操作-->
                        <tx:method name="get*" propagation="SUPPORTS"/>
                        <tx:method name="save*" isolation="DEFAULT" timeout="10"/><!-- Oracle默认是read-committed  默认-1,永不超时,这里允许事务运行的最长时间为只能等10s-->
                        <tx:method name="delete*" no-rollback-for="java.lang.RuntimeException"/><!-- 采用事务,会自动清理缓存  爆运行时异常不回滚 。默认是回滚的-->
                        <tx:method name="update*" rollback-for="java.lang.Exception"/><!-- 对受检查类型进行回滚 -->
                        <tx:method name="*"/>
                    </tx:attributes>
                </tx:advice>

            d、定义切入点,织入事务切面
                <aop:config>
                    <aop:pointcut expression="execution(public * com.ljw.ssh.biz..*(..))" id="bizMethod"/><!-- 定义所有业务方法为切入点 -->
                    <aop:advisor advice-ref="txAdvice" pointcut-ref="bizMethod"/>    <!-- 在业务方法织入事务增强 -->
                </aop:config>

        D、声明式事务属性
            1)propagation:事务传播机制
                REQUIRED(默认值)(推荐)
                MANDATORY
                REQUIRES_NEW
                NESTED

                SUPPORTS(推荐)
                NEVER
                NOT_SUPPORTED

            2)isolation:事务隔离等级
                DEFAULT(默认值)
                READ_UNCOMMITTED
                READ_COMMITTED
                REPEATABLE_READ
                SERIALIZABLE

            3)timeout:事务超时时间。允许事务运行的最长时间,以秒为单位。默认值为-1,表示不超时

            4)read-only:事务是否为只读。默认值为false

            5)rollback-for:设定能够触发回滚的异常类型
                ?Spring默认只在抛出runtime exception时才标识事务回滚
                ?可以通过全限定类名指定需要回滚事务的异常,多个类名用逗号隔开

            6)no-rollback-for:设定不触发回滚的异常类型
                ?Spring默认checked Exception不会触发事务回滚
                ?可以通过全限定类名指定不需回滚事务的异常,多个类名用英文逗号隔开

    4、Spring和Struts 2的无缝集成
        A、方式一
            实现步骤:
                添加struts2-spring-plugin-xxx.jar
                按照名称匹配的原则定义业务Bean和Action中的setter方法
                在struts.xml正常配置Action

        B、方式二
            a、在Spring配置文件中配置Action Bean,注意scope="prototype"属性
                <bean id="userAction" class="cn.bdqn.jboa.action.UserAction" scope="prototype">< !--省略其他配置--></bean>

            b、在sturts2中配置Action
                <package name="login" extends="struts-default">
                    <action name="login" class="userAction" method="login">
                        < !--省略其他配置-->
                    </action>
                </package>

            注意:
                class属性的值不再是Action类的全限定名,而是Spring配置文件中相应的Action Bean的名称

                1、采用此种配置方式时,Action的实例由Spring创建,Struts 2插件的工厂类只需根据Action Bean的id查找该组件使用即可
                2. 此种方式可以为Action进行更灵活的配置,但代价是在Spring配置文件中需要定义很多Action Bean,
                    增加了配置工作量,如非必需并非首选
                3. 采用此种配置方式,同样需要添加struts2-spring-plugin-xxx.jar文件

    5、web.xml文件的配置
        <!-- 如果applicationContext.xml在/WEB-INF/下,可以不配,否则需指定在那个路劲下-->
        <!-- spring配置文件的存放位置,读取上下文,告诉监听器 spring配置文件的位置在哪 -->
            <context-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:applicationContext.xml</param-value>
            </context-param>


        <!-- 启动tomcat时,负责读取spring配置文件,该监听器用于在web环境中启动Spring容器 -->
            <listener>
                <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
            </listener>


        <!-- spring提供的一个过滤器,实现一次请求,一次会话。简化了以前创建和关闭会话的代码,使过滤范围最大化 -->
        <!-- mapping在前的过滤器会先执行,另外在Spring上下文中找会话工厂sessionFactory -->
        该过滤器把一个Hibernate Session和一次完整的请求过程相绑定,解决了诸如延迟加载等问题,另外该过滤器要配置在struts2之前
            <filter>
                <filter-name>OpenSessionInViewFilter</filter-name>
                <filter-class>
                    org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
                </filter-class>
        <!-- 如果application配置文件里SessionFactory Bean的ID名字不是 sessionFactory 则需要为该过滤器配置sessionFactoryBeanName参数如下-->
                <!-- <init-param>
                    <param-name>sessionFactoryBeanName</param-name>
                    <param-value>sessionFactory</param-value><!--application配置文件里工厂的ID名字-->
                </init-param> -->
            </filter>
            <filter-mapping>
                <filter-name>OpenSessionInViewFilter</filter-name>
                <url-pattern>*.action</url-pattern>
            </filter-mapping>

    6、模板与回调机制的实现
        public List<BizClaimVoucher> findByPage(final int pageNo,
            final int pageSize, final String hql) {

            return this.getHibernateTemplate().execute(
                    new HibernateCallback<List<BizClaimVoucher>>() {
                        @SuppressWarnings("unchecked")
                        @Override
                        public List<BizClaimVoucher> doInHibernate(Session s)
                                throws HibernateException, SQLException {
                            return s.createQuery(hql)
                                    .setFirstResult((pageNo-1)*pageSize)
                                    .setMaxResults(pageSize)
                                    .list();
                        }
                    }
            );
        }

猜你喜欢

转载自blog.csdn.net/lif29103/article/details/80700831