SpingMVC流程图

Struts的请求流程

 

springmvc的流程

0.struts2       MVC框架  Controller
  Hibernate     持久化框架   Model
  spring        项目管理框架   为javaEE开发提供更好的解决方案
======================================================================================
1.spring:工厂,容器
        :创建项目中的所有模块(组件),并持有管理所有的组件.
        :spring的所有功能实现,都架设在工厂(容器)的支持下.
======================================================================================
2.spring工厂搭建:
  2.1 导包:
  2.2 配置文件:告知spring需要生产的组件.
       *位置:任意
       *名称:任意   applicationContext.xml    beans.xml
        <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-3.2.xsd">
            
            <!-- 告知spring生产如下的组件 -->
            <bean id="ud47" class="com.c47.dao.UserDAOImpl"></bean>
            <bean id="us47" class="com.c47.serivce.UserServiceImpl"></bean>
        </beans>
  2.3 api:启动工厂:
        ApplicationContext
        ClassPathXmlApplicationContext
        //启动工厂:指定配置文件位置
        ApplicationContext context=new ClassPathXmlApplicationContext("com/c47/config/applicationContext.xml");
        //从工厂中获取bean
        UserDAO ud=(UserDAO)context.getBean("ud47");
        UserService us=(UserService)context.getBean("us47");
=====================================================================================
3.IOC Inverse Of Controll  控制反转
  :将属性的赋值权有静态代码中 反转 到配置文件中
  :将具有依赖关系的双方的耦合打散.提高项目的可维护性.
  :在配置文件中为属性赋值:DI  Dependency Injection  依赖注入
=====================================================================================
4.set注入:通过set方法,将属性值存入.
    <!-- jdk8中基本类型+String -->
    <property name="id" value="1"></property>
    <property name="name" value="c47"></property>
    <property name="gender" value="true"></property>
    <!-- List/数组 -->
    <property name="list47">
        <list>
            <value>1</value>
            <value>c47</value>
            <value>true</value>
            <ref bean="us47"/>
        </list>
    </property>
    <!-- Map -->
    <property name="map47">
        <map>
            <entry key="name" value="lichangpu"></entry>
            <entry key="age" value="18"></entry>
            <entry key="gender" value="true"></entry>
            <entry key="us47" value-ref="us47"></entry>
        </map>
    </property>
    <!-- properties -->
    <property name="props">
        <props>
            <prop key="url">jdbc:oracle:xxx</prop>
            <prop key="username">hr</prop>
        </props>
    </property>
=====================================================================================
5.构造注入:通过构造方法,为属性赋值
    <!-- 第一个参数,类型为Integer -->
    <constructor-arg index="0" type="java.lang.Integer" value="47"></constructor-arg>
    <constructor-arg index="1" type="java.lang.String" value="c47"></constructor-arg>
    <constructor-arg index="2" type="java.lang.Boolean" value="true"></constructor-arg>
    弊端:不够灵活
        :用于构造不提供空参构造的组件.
=====================================================================================
6.自动注入
    <!--
        autowire:自动装载
        byType:将工厂中与目标组件的属性同类型的bean,赋值给对应属性
        byName:将工厂中与目标组件的属性同名的bean,赋值给对应属性
     -->
    <bean id="ioc49" class="com.c47.IOC.test.TestIOC3" autowire="byName"></bean>
=====================================================================================
7.spring对于bean的生产原理:
    反射+空参构造:
    String path="com.c47.dao.UserDAOImpl";
    Class claz=Class.forName(path);
    Object obj=claz.newInstance();//调用空参构造
    例外:当使用了构造注入时,就不会选取空参构造,而是调用配置中指定的构造方法.
=====================================================================================
8.bean的生命周期:
  *bean的构建时刻:spring工厂启动时,所有的单例的bean随之创建
  *bean的销毁时刻:spring工厂关闭时,所有bean随之销毁.
  *细节:bean的生命历程(了解)
    构造-->set-->init-->destroy
=====================================================================================
9.bean的创建模式
  *singleton:单例    全局唯一  (默认)
  *prototype:非单例  全局不唯一
  <bean id="c47" class="xx"/> 单例
  <bean id="userAction47" class="xxxx" scope="singleton"> 单例
  <bean id="userAction47" class="xxxx" scope="prototype"> 非单例
  *单例:无论使用(getBean()/用于注入)多少次,都只有一个对象
  *非单例:每使用一次,都要创建一个新的对象.
  *细节:
       在工厂启动时,非单例的bean不会随之创建.而是在被使用时才创建.
=====================================================================================
1.复杂对象:创建过程复杂.不能直接new.
          :FactoryBean==构建复杂对象
=====================================================================================
2.FactoryBean 工厂bean使用流程:
  2.1 定制FactoryBean
        implements FactoryBean<SessionFactory>{
            /**
             * 主体逻辑:定制复杂对象的创建流程
             */
            public SessionFactory getObject() throws Exception {
                ....
            }
            /**
             * 返回复杂对象的类对象
             */
            public Class getObjectType() {
                return SessionFactory.class;
            }
            /**
             * 定制复杂对象的创建模式:
             * return true;单例
             * return false;非单例
             */
            public boolean isSingleton() {
                return true;
            }
        }
  2.2 配置
        <!-- 声明工厂Bean -->
        <bean id="sessionFactory47" class="com.c47.factory_bean.MySessionFactory"></bean>
  2.3 使用:
        *当从工厂中获取bean时,如果此bean是FactoryBean,则返回给用户的并不是bean本身
         的对象.而是去回调此bean中的getObject(),返回此bean中getObject()方法的返回值.
====================================================================================
3.spring 初步的整合hibernate
  *将sessionfactory纳入工厂
  *将DAO,Service 纳入工厂
  *并通过IOC满足DAO和Service的依赖
====================================================================================
4.类型转换器:注入过程,如果双方的类型不匹配,则需要类型转换.
            :String-->数字,布尔 自动完成
    4.1 定制转换器类:
        extends PropertyEditorSupport{
            /**
             * <bean>
             *       <property name="birth" value="2015-12-11">
             * </bean>
             * 转换器的主体逻辑:完成数据格式转换
             * param:text  要转换的值(2015-12-11)
             * 此方法,会在spring需要类型转换时被spring回调
             * setAsText("2015-12-11");
             * getValue();
             */
            @Override
            public void setAsText(String text) throws IllegalArgumentException {
                SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
                try {
                    Date date=format.parse(text);
                    //将转换好的数据,交还spring
                    //将转换好的数据,存入父类的成员变量中,spring会回调父类的getValue(),将值取走.
                    this.setValue(date);
                } catch (ParseException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    4.2 配置:
           *声明类型转换器:
            <bean id="dateEditor47" class="com.c47.property_editor.MyPropertyEditor"></bean>
           *注册:
            <!-- 告知spring
                 CustomEditorConfigurer:统一管理所有转换器的入口
             -->
            <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
                <!-- 注册自定义的类型转换器
                     告知spring此转换器可以完成string到Date的转换
                 -->
                <property name="customEditors">
                    <map>
                        <entry key="java.util.Date" value-ref="dateEditor47"></entry>
                    </map>
                </property>
            </bean>
           *使用:
            <!-- 转换器测试 -->
            <bean id="user47" class="com.c47.entity.User">
                <property name="birth" value="2015-12-11 11:51:47"></property>
            </bean>
    *细节:如果是日期数据的注入,可以不定制转换器,spring默认的日期格式:
         :yyyy/MM/dd HH:mm:ss
====================================================================================
*补充:spring对于hiberante更新的支持:
    //User{id,name,age,Set<order> orders}
    //user{id,name,age,null}
    //user2{id,name,age,orders}
    public void updateUser(User user) {
        Session session=factory.getCurrentSession();
        User user2=(User)session.get(User.class, user.getId());
        //将user的属性值,赋值给user2中的同名属性.
        //技巧:在set方法中添加判断,过滤null
        BeanUtils.copyProperties(user, user2);
        session.update(user2);
    }

0.业务层:冗余:在业务中有大量的重复的逻辑散布在大量的业务方法,导致极大的冗余.
             :对于项目的开发,和后期的维护,都是极大的隐患.
        :耦合:在业务中有两类逻辑[核心业务],[额外功能],耦合在一起,不利于项目的维护.
  public interface UserService{
    public void delete(Integer id);
    public void update(User user);
  }
  public class UserServiceImpl implements UserService{
    public void delete(Integer id){
        //核心业务处理:删除  UserDAO.delete();
    }
    public void update(User user){
        //核心业务处理:更新  UserDAO.update();
    }
  }

  //性能
  //事务
 
  静态代理类:组成:[target:核心业务]+[额外功能]
            :原则:代理(proxy)和目标(target)要有同样的方法实现(同样的接口实现)
      public class UserServiceProxy implements UserService{
        //原始的业务类
        private UserService us=new UserServiceImpl();
        public void delete(Integer id){
             //性能
             //事务
             us.delete(id);
             //事务
        }
        public void update(User user){
             //性能
             //事务
             us.update(id);
        }
      }
      new UserServiceProxy().update(user);
      new UserServiceProxy().delete(1);
  动态代理类搭建:
     1.准备原材料:target中的核心业务
                 :额外功能
     2.通过aop:编织,将原材料,动态的加载,称为一个代理类
     3.获取动态生成的代理类,完成相关业务.
======================================================================================
1.AOP :解决业务层中的问题
      :面向切面编程  代理模式   代理类
      :代理:target+Advice
      :切入点:切入了额外功能的 业务方法.
      :切面:切入点+额外功能
  OOP :面向对象编程  类 对象 接口  继承  封装  多态
=====================================================================================
2.动态代理搭建:*导入第三方的jar
  2.1 准备原材料
      *target
      *额外功能(Advice:建议)
             MethodBeforeAdvice       前置额外功能
         AfterReturningAdvice     后置额外功能
         MethodInterceptor        环绕额外功能
         ThrowsAdvice             异常时的额外功能(了解)
        implements MethodBeforeAdvice{
            /**
             * 主体逻辑:
             *   params:
             *      m:目标的方法对象
             *      params:目标方法的参数表,如果方法是空参,则params的长度为0.
             *      target:代理的目标
             */    
            public void before(Method m, Object[] params, Object target)
                    throws Throwable {
                //定制在目标的方法之前,执行的逻辑
                System.out.println("before: method:"+m.getName()+" params'length:"+params.length+" target:"+target);
            }
        }
  2.2 动态的编织代理类
      *声明原材料:target和advice
      *Weave:编织
        <!-- target -->
        <bean id="userService47" class="com.c47.serivce.UserServiceImpl"></bean>
        <!-- Advice -->
        <bean id="before47" class="com.c47.advice.MyBefore"></bean>
        <!-- 编织:基于aop schema完成编织 -->
        <aop:config>
            <!-- 1.目标,及其中需要附加额外功能的方法.
                 2.在目标中加入哪些额外功能
              -->
            <!--
                pointcut:切入点=目标中 附加了额外功能的方法
                execution()表达式:描述切入点
                       返回值   包  类  方法名  参数表
                * com.c47.service4.UserServiceImpl.*(..)
                * com.c47.service4.UserServiceImpl.deleteUser(..)
             -->
            <aop:pointcut id="pc47" expression="execution(* com.c47.service4.UserServiceImpl.*(..))"/>
            <!-- 在位置[pc47]上,附加额外功能[before47]  -->
            <aop:advisor advice-ref="before47" pointcut-ref="pc47"/>
        </aop:config>
  2.3 从工厂中获取动态代理对象:通过目标类的beanID即可,用接口类型引用接收.
===================================================================================  
3.额外功能:
  3.1 后置额外功能:AfterReturningAdvice
        implements AfterReturningAdvice{
            /**
             * 主体逻辑:
             *   params:
             *       ret:目标方法的返回值,如果方法是void,则ret为null
             *       m:目标方法对象
             *       paras:方法参数表
             *       target:目标对象
             */
            public void afterReturning(Object ret, Method m, Object[] params,
                    Object target) throws Throwable {
                System.out.println("after ret:"+ret+" method:"+m.getName()+" params'length:"+params.length+" target:"+target);
            }
        }
  3.2 环绕额外功能:
        implements MethodInterceptor{
            /**
             * 主体逻辑
             *   param:
             *      mi:
             */
            public Object invoke(MethodInvocation mi) throws Throwable {
                System.out.println("tx begin~~~");
                //调用目标的方法.
                Object ret=mi.proceed();
                System.out.println("tx commit~~~");
                //接收目标方法的返回值,并向上返回给用户.
                //注意:在环绕额外功能中,目标方法的返回值,务必要向上返回.
                return ret;
            }
        }
  3.3 异常时的额外功能:目标抛出异常时触发.(了解)
        implements ThrowsAdvice{
            /**
             * 主体逻辑:目标抛出异常时,执行
             * @param ex :抛出的异常对象
             */
            public void afterThrowing(Exception ex){
                System.out.println("my throws :"+ex.getMessage());
            }
        }
====================================================================================
4.execution表达式:描述切入点
  组成:返回值   包    类    方法名   参数表
  1>* com.c47.serivce.UserServiceImpl.deleteUser(..)
    返回值:任意
    包:com.c47.service
    类:UserServiceImpl
    方法:deleteUser
    参数表:任意
  2>* com.c47.serivce.UserServiceImpl.*(..)
    返回值:任意
    包:com.c47.service
    类:UserServiceImpl
    方法:任意
    参数表:任意
  3>* com.c47.serivce.*.*(..)
    返回值:任意
    包:com.c47.service
    类:任意
    方法:任意
    参数表:任意
  4>* *(..)
    返回值:任意
    包:任意
    类:任意
    方法:任意
    参数表:任意
  5>* login(..)
    返回值:任意
    包:任意
    类:任意
    方法:login
    参数表:任意
  6>技巧:* com.c47.serivce.UserServiceImpl.*User(..)
        返回值:任意
        包:com.c47.service
        类:UserServiceImpl
        方法:以User结尾的方法(便于批量的切入)
        参数表:任意
    建议:表达式,定义尽量精确.避免不必要的切入.
===================================================================================
*基于AOP,抽取事务管理:
  1>DAO,Service,SessionFactory,DataSource 纳入工厂
  2>IOC满足依赖
  3>Service不再依赖SessionFactory
  4>定制环绕额外功能:事务管理
  5>IOC满足事务管理器的依赖
  6>AOP将事务管理器切入需要事务的业务方法中.

1.原理:*动态代理类如何创建的.
          1>jdk代理  :通过和目标实现同一套接口,保证功能统一
          2>cglib代理:通过继承目标,保证功能统一.
          spring会动态的选择,如果目标有接口实现,则使用jdk代理,
          反之,则使用cglib.
       *为什么通过目标的BeanID===>Proxy
          1>BeanPostProcessor作用,再次加工.
======================================================================================
2.动态代理类如何创建(jdk代理):
        //1.目标 target
        final UserService us=new UserServiceImpl();
        //2.额外功能
        InvocationHandler ih=new InvocationHandler(){
            /**
             * method:方法对象
             * args:参数列表
             */
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                System.out.println("before~~~");
                //调用目标(us)的方法
                Object ret=method.invoke(us, args);
                System.out.println("after~~~");
                return ret;
            }
        };
        //3.编织  *类加载器   *目标的所有实现的接口   *额外功能
        UserService usProxy=(UserService)Proxy.newProxyInstance(TestAOPYL.class.getClassLoader()
                                                               ,us.getClass().getInterfaces()
                                                               ,ih);
====================================================================================
3.为什么通过目标的BeanID===>Proxy
  *BeanPostProcessor:后处理bean-->对工厂创建好的bean,进行再次的加工.
      被代理的Bean 生产过程:
      构造-->set-->
                postProcessBeforeInitialization-->
                init-->
                postProcessAfterInitialization-->
                用户
                
  *定制后处理bean:
            implements BeanPostProcessor{
                /**
                 * 在init之后执行
                 * param:bean=postProcessBeforeInitialization加工后的对象
                 */
                public Object postProcessAfterInitialization(final Object bean, String arg1)
                        throws BeansException {
                    
                }
                /**
                 * 在init之前执行
                 * param:bean=工厂供创建的目标的bean的对象
                 */
                public Object postProcessBeforeInitialization(Object bean, String arg1)
                        throws BeansException {
                    //加工
                    return bean;
                }
            }
   *<!-- 声明后处理bean
         则在获取当前配置中的任何一个bean时,后处理bean,就会进行再加工
     -->
    <bean class="com.c47.postprocessor.MyPostProcessor"></bean>
===================================================================================
4.spring事务管理:
  4.1 将 HibernateTransactionManager 纳入工厂,并IOC满足依赖:SessionFactory
        <!-- 并不是一个完整的事务管理器,其中,管理了事务控制的核心的逻辑
                     需要对其进一步的包装
        -->
        <bean id="tx47" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory47"></property>
        </bean>
  4.2 进一步包装,获取真正的事务管理器
        <!-- 基于schema tx 包装真正的事务管理器
             事务属性(attributes):
                *隔离级别:1>读未提交   事务之间可以读取到彼此未提交的数据,会导致[脏读],并发性极好.
                                [脏读]:一个事务中读取到了其他事务中未提交的数据
                       2>读提交    事务之间只可以读取到彼此已提交的数据,可防止[脏读].但不能防止[不可重复读],并发性较好
                                [不可重复读]:一个事务中,多次读取统一条数据,结果不一致
                       3>可重复读     一个事务内,多次读取统一条数据,结果一致.可防止[脏读,不可重复读],但不能防止[幻影读],并发性较差
                                [幻影读]:一个事务中,多次读取统一张表,数据行数不一致.
                       4>序列化读  多个事务是串行发生.可以防止一切不合法的读取,并发性极差.
                      oracle:1.读提交(默认)  2.序列化读
                *传播性: REQUIRED:如果当前没有事务环境,开启事务;如果已有事务环境,则融入事务.
                       SUPPORTS:如果当前没有事务环境,则在非事务环境下执行;如果已有事务环境,则融入事务.
                *读写性:read-only="true" 只读事务,事务中只能读.
                      read-only="false" 读写时序,事务中可读 可写.
                *回滚时刻:rollback-for="java.lang.Exception" 在出现所有异常时,要回滚.
                                           细节:如果出现了RuntimeException,则会自动回滚.
                                                     但是如果出现了Exception,默认不会回滚,依然提交事务.
            事务特性:ACID
                    原子性
                    一致性
                    持久性
                    隔离性
        
        -->
        <tx:advice transaction-manager="tx47" id="txManager">
            <tx:attributes>
                <tx:method name="queryUserByID" propagation="SUPPORTS"/>
                <!-- <tx:method name="*User"/> -->
                <!-- 其余方法 -->
                <tx:method name="*" isolation="READ_COMMITTED" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            </tx:attributes>
        </tx:advice>
        *事务管理器,定制完毕,AOP切入业务层中即可
===================================================================================
5.spring对于DAO操作支持:进一步简化DAO操作
  HibernateTemplate:模板类,作用在DAO,将session封装到底层,构建了封装后的方法,以完成并
                   :简化DAO操作.
                   :集成session几乎所有的方法:get(),save(),delete(),update()
                   :如何执行HQL:template.find("HQL",Object... param);
                   :execute();//通用方法.
                        //execute方法会回调HibernateCallback中的doInHibernate
                        //且doInHibernate方法的返回值,就是execute方法的返回值.
                        template.execute(new HibernateCallback<List<User>>(){
                                //param:session 即当前线程中使用的session
                                public List<User> doInHibernate(Session session)
                                        throws HibernateException, SQLException {
                                    String hql="from User u order by u.id";
                                    Query query=session.createQuery(hql);
                                    query.setMaxResults(5);
                                    query.setFirstResult((pageNum-1)*5);
                                    return query.list();
                                }
                            }
                        );
                   :其中将事务的自动提交置为true.   connection.setAutoCommit(true);
                     template.save(xx);
                     template.delete(xx);
                     利于测试DAO.
===================================================================================

*spring   struts2   hibernate
 spring   struts2   mybatis
 基于注解的ssh
 *OpenSessionInViewFilter

1.spring+struts整合
  1>搭建struts2
  2>将Action纳入工厂(注意:prototype)
  3>IOC满足Action依赖
  4>导入插件包:struts2-spring-plugin.jar
              :在struts.xml配置Action时,<action  class="Action_BeanID" ....
              :保证前端控制器从工厂中获取需要的Action实例
  5>启动工厂:定制监听器=org.springframework.web.context.ContextLoaderListener
                       =在项目启动时,启动工厂
            :定制context-param=contextConfigLocation
                              =指示spring配置文件位置
======================================================================================
2.spring+mybatis整合:
  1>构建连接池
  2>通过SqlSessionFactoryBean构建SqlSessionFactory
    *依赖点:
        *数据源
        *别名设置(可选)
        *映射文件位置
  3>通过MapperScannerConfigurer构建DAO接口的实现类
    *依赖点:
        *SqlSessionFactory
        *DAO接口所在位置
    *构建出的DAO接口实现类,会纳入工厂,且ID为对应接口名的首字母小写
  4>将构建好的DAO注入给Service
  5>搭建DataSourceTransactionManager(注入数据源)
    并通过<tx:advice 进一步包装出mybatis的事务管理器,切入service方法中
  6>整合struts2....
=====================================================================================
3.基于注解SSH整合:
  1>//将当前类纳入工厂,bean的ID默认为类名的首字母小写:userDAOImpl
    //也可以明确指定bean的ID
    @Component("userDAO") 作用在类上
  2> //指示当前bean是非单例/单例(默认)的.
     @Scope(value="prototype/singleton")  作用在类上
  3>//基于类型自动注入
    @Autowired   作用在属性
    //基于名称自动注入
    @Resource(name="userService")  作用在属性
  4>//作用在类上:缺省的为类中的所有方法指定事务属性.
    //作用在方法上:为方法单独的指定事务属性
    @Transactional(isolation=Isolation.READ_COMMITTED,propagation=Propagation.REQUIRED,readOnly=false,rollbackFor=Exception.class)
  *告知spring注解位置:
        <context:component-scan base-package="com.c47"></context:component-scan>
  *告知spring,事务注解切入的是什么事务:
        <bean id="tx47" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <tx:annotation-driven transaction-manager="tx47"/>
=====================================================================================
4.OpenSessionInViewFilter:
  :被此过滤器过滤的请求,Session有此过滤器管理:session在事务结束后依然是开启的,直到
   视图渲染完毕后,将session关闭,以解决延迟加载异常.
      <!-- 配置OpenSessionInViewFilter
                      注意:要在前端控制器之前定义
                      此过滤器依赖SessionFactory,且默认向工厂所要id为:"sessionFactory"的bean
                      如果工厂中的SessionFactory的beanID不是"sessionFactory",通过init-param指定
      -->
      <filter>
        <filter-name>osiv47</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        <init-param>
            <param-name>sessionFactoryBeanName</param-name>
            <param-value>sessionFactory47</param-value>
        </init-param>
      </filter>
      <filter-mapping>
        <filter-name>osiv47</filter-name>
        <!-- 需要在页面中使用延迟属性的请求 -->
        <url-pattern>/ssh/user_queryOneUser</url-pattern>
        <url-pattern>/user/a</url-pattern>
        <url-pattern>/user/b</url-pattern>
        <url-pattern>/user/c</url-pattern>
        <url-pattern>/user/d</url-pattern>
        <url-pattern>/a</url-pattern>
        <url-pattern>/b</url-pattern>
      </filter-mapping>
====================================================================================

原文地址:https://www.cnblogs.com/gyadmin/p/8458741.html