spring

spring的作用及优势


Spring的作用

Spring用于整合软件开发中的各种框架,提供组件之间松耦合的平台,目的就是将耦合度降至最低,即解耦。(开源,都是相通的。所有的框架都是基于反射实现的。)

1. spring用于整合各种框架,简化开发比如DAO层,只要使用spring的一个工具类即可

2. 解耦,松耦合让类与类之间的联系不大。降低依赖性,换了一个类,不影响整个项目。项目开发过程中,难点不是模块不好开发,功能能否实现,而是怎么整合各个程序员开发的程序代码。类比较多的时候不好管理,spring是将类与类之间的关联降至最低。

3. 我们在使用Spring框架时,主要是使用Spring容器的两个特性:IoC和AOP

spring的优势

1. spring是一个开源框架,开放源代码

2. spring 为JavaEE应用提供轻量级的解决方案;

3. spring提倡”最少侵入”;(降低耦合度,换了谁都可以)

4. spring是一个优秀的MVC框架   

5. 基于依赖注入的核心机制,基于AOP的声明式事务管理

spring容器


概念

spring框架的核心就是提供了一个容器。该容器类型是BeanFactory或者ApplicationContext(建议用这个类型,它是BeanFactory的子类,功能更多)

Spring的核心接口:BeanFactory

该容器具有以下功能:

a. 容器可以创建和销毁组件对象,等价于原来”工厂”类的作用。

b. 容器可以采用不同的模式创建对象,如单例模式创建对象

c. 容器具有IOC机制实现

d. 容器具有AOP机制实现

容器实例化

BeanFactory创建并负责管理Spring bean的上下文的生命周期。BeanFactory接口指明了spring到底干了什么事。

org.springframework.beans.factory.xml.XmlBeanFactory 是BeanFactory的实现类,在XMLBeanFactory中,以xml结构方式描述对象及对象之间的依赖关系。

创建BeanFactory实例时,必须提供Spring容器管理bean的详细配置信息,相应的XML文件作为参数传入。

BeanFactory  factory = new ClassPathXmlApplicationContext(“applicationContext.xml”);

BeanFactory  factory = new FileSystemXmlApplicationContext(“F:/applicationContext.xml”);

推荐使用ClassPathXmlApplicationContext方式

Bean对象

Bean指代的就是对象,BeanFactory是产生和管理bean的容器。

a. 产生bean

b. 控制Bean的产生数量

c. 控制Bean的产生时间

d. 控制Bean的生命周期

Spring通过BeanFactory管理和配置bean ,在Spring里,任何的java对象、java组件bean处理。

spring环境的搭建

1. 创建web工程

2. 导入jar  spring.jar commons-logging.jar     log4j-1.2.15.jar

3. 导入配置文件  log4j.properties        applicationContext.xml

实例化Bean对象方式

a. 用构造器来实例化

<bean  id=”XXBean”  class=”” />

b. 使用静态工厂方法实例化

<bean  id=”XXbean”  class=”XXXfactoryClass”  factory-method=”” />

c. 使用实例工厂方法实例化

<bean  id=”XXfactory”  class=”” />
<bean  id=”XXXbean”  factory-bean=”XXX”  factory-method=”” />

将一个Bean组件交给Spring容器管理,获取spring容器对象和Bean对象

案例

1. 新建web功能

2. 导入jar包

3. 创建Bean1对象

public class Bean1{}

4. 工厂类

public class Bean1Factory {
  public Bean1Factory(){
     System.out.println("创建工厂对象");
  }
  //使用静态方法获得对象
   public static Bean1 getBean1(){
     return new Bean1();
  }
  //使用实例方法获得对象
  public Bean1 getBean(){
    return new Bean1();
  }
}

5. 添加配置文件applicationContext.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd 
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd ">
 
    <!-- 把bean1配置到是pring,让spring管理bean1
         id:该bean的标识,用来区分开每一个bean(类的对象)
         class:指明配置的具体的类,包名+类名,底层利用反射创建对象class.forName()-->
    <bean id="bean1" class="web.test.bean.Bean"></bean>
    <!-- 在spring中调用工厂的静态方法创建对象 -->
    <bean id="bean2" class="web.test.factory.Bean1Factory"    factory-method="getBean1"></bean>
    <!-- 在spring中,调用工厂的实例方法,获得对象 -->
    <!-- 1、先把工厂实例化 -->
    <bean id="factory" class="web.tarena.factory.Bean1Factory"></bean>
    <!-- 2、调用工厂中的实例方法获得对象 -->
    <bean id="bean3" factory-bean="factory"    factory-method="getBean1"></bean>
</beans>

5. 测试类

public class TestSping {
    public void test1() {
        /**
         * ClassPathXmlApplicationContext:用来加载核心配置文件。applicationContext.xml,比较消耗资源,重量级对象,所以应该写成静态的,只加载一次。
         * 重量级对象:功能强大,消耗资源较多,ClassPathXmlApplicationContext和HibernateSessionFactory都是重量级对象
         * BeanFactory接口 Object getBean(String name); name就是指配置文件中的id值 返回结果是Object,spring可以管理任意的对象
         */
        ApplicationContext beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过构造器创建Bean对象
        Bean bean1 = (Bean)beanFactory.getBean("bean1");
        System.out.println(bean1);
        // 通过工厂的静态方法创建Bean对象
        Bean bean2 = (Bean)beanFactory.getBean("bean2");
        System.out.println(bean2);
        // 通过实例化工厂方法创建Bean对象
        Bean bean3 = (Bean)beanFactory.getBean("bean3");
        System.out.println(bean3);
    }

    public void test2() {
        // 单例模式下不同的beanFactory创建出来的Bean对象不是同一个
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("---------------------------");
        Bean bean1 = (Bean)beanFactory.getBean("bean1");
        System.out.println(bean1);
        BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
        Bean bean11 = (Bean)factory.getBean("bean1");
        System.out.println(bean11);

    }
}

spring容器对Bean组件的管理


Bean对象的创建模式

Spring支持singleton(单例)和prototype(原型,非单例)两种模式。Singleton:每次调用getBean()返回同一个对象。prototype:每次调用getBean()返回新的对象。

默认是singleton模式,可以通过<bean>的scope属性修改为prototype模式。例如:<bean  id=”标识符”  scope=”prototype”  class=”Bean组件类型”  />

Bean对象的创建时机

a. singleton模式的Bean组件是在容器实例化时创建的。

b. prototype模式是在调用getBean()方法时创建。

c. singleton模式可以使用<bean>元素的lazy-init=”true”属性将对象的创建时机推迟到调用getBean()方法。也可以在<beans>(根元素)中使用default-lazy-init=”true”推迟所有单例Bean组件的创建时机。

Bean对象的初始化和销毁

初始化

1. 可以利用<bean>元素的init-method=”方法名”属性指定初始化方法。

2. 指定的初始化方法是在构造方法调用后自动执行。若非单例模式,则每创建一个对象,则执行一次初始化方法。

初始化的三种方式

1. 写在构造方法中

2. 写在{}中(代码块);

2. spring框架中<bean>元素写init-method=”方法名”

初始化不能用static{},它是类加载调用,比创建对象要早。

销毁

1. 可以利用<bean>元素的idestory-method=”方法名”属性执行销毁方法。

2. 销毁方法是在容器关闭时触发,而且只适用于singleton模式的组件

//spring容器关闭
AbstractApplicationContext  ac=new ClassPathXmlApplicationContext();
ac.getBean(“feeDAO”);
ac.close();//该方法执行后,Bean对象被销毁

spring框架的IOC特性


IOC概念

IOC,Inverse of Controller被称为控制反转或反向控制,其实真正体现的是”控制转移”。所谓的控制指的是负责对象关系的指定、对象创建、初始化、和销毁等逻辑。

IOC指的是将控制逻辑交给第三方框架或容器负责(即把Action中的控制逻辑提出来,交给第三方负责),当两个组件发生改变时,只需要修改框架或容器的配置即可。

控制反转就是应用本身(Action)不负责依赖对象(Dao)的创建及维护,依赖对象的创建及维护是由外部容器(BeanFactory)负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。

DI概念

DI,Dependency Injection依赖注入

依赖注入就是指:在运行期,由外部容器(BeanFactory)动态地将依赖对象(Dao)注入到组件(Action)中。Spring框架采用DI技术实现了IoC控制思想

Spring提供了两种形式的注入方式:

①(常用)setter方式注入:依靠set方法,将组件对象传入(可注入多个对象)

a. 首先添加属性变量和set方法

b. 在该组件的<bean>定义中采用下面的描述方式 <property  name=”属性名”  ref=”要注入的Bean对象的id值”></property>

c. 属性名与set方法名对应,和属性名无关。例如CostAction中有costDao属性,而他的标准set方法名为setCostDAO,那么配置文件中的name就应该写costDAO(去掉set,首字母小写)。name不是看定义的属性名,而是set方法名。

②(用的少)构造方法注入:依靠构造方法,将组件对象传入

a. 在需要注入的组件中,添加带参数的构造方法。

b. 在该组件<bean>定义中,使用下面格式描述<constructor-arg  index=”参数索引” ref=”要注入的Bean对象的id值” />

DIIOC的关系

Spring是具有IoC特性的框架,实现Ioc是由Spring容器完成的,Spring容器通过DI建立起对象之间的关系。可以这样理解:DI是IoC实现的一种手段,IoC的理论通过DI实现。

案例

UserDao

public interface UserDAO {
    public void saveUser(String user);
}

UserDAOOracleImpl

public class UserDAOOracleImpl implements UserDAO{
    public void saveUser(String user) {
        System.out.println("oracle实现");
    }
}

UserDAOMysqlImpl

public class UserDAOMysqlImpl implements UserDAO{
    public void saveUser(String user) {
        System.out.println("mysql实现");
    }    
}

UserAction

public class UserAction {
    private UserDAO userDao;
    //Action依赖DAO,保存数据。把依赖的UserDao写到方法的外面,可以通过set方法注入不同实现的dao对象
    //这样操作不同的数据库的时候,不用对UserAction进行任何的修改或者完全通过配置文件进行配置
    public void saveUser(String username){
        userDao.saveUser();
    }
    //set方式注入
    //public void setUserDao(UserDAO userDao) {
    //     this.userDao = userDao1;
    //}
     //构造方式注入
    public UserAction(UserDAO userDao) {
        this.userDao=userDao;
    }
}     

applicationContext.xml

<beans ...>
    <!-- 把所有的Dao和Action全部配置到spring当中,全部纳入spring的管理 -->
    <bean id="userDaoMySql" class="com.test.dao.impl.UserDaoMySqlImpl"></bean>
    <bean id="userDaoOracle" class="com.test.dao.impl.UserDaoOracleImpl" ></bean>
    <bean id="userAction”  class="com.tarena.web.action.UserAction" >
      <!-- set方式注入 -->
      <!--<property name="userDao1" ref="userDaoOracle"></property>-->
      <!-- 构造器方式注入 -->
      <constructor-arg ref="userDaoDB2"></constructor-arg>
  </bean>
</beans>

各种数据类型的注入


Bean3

//使用spring创建对象的时候,创建的同时给对象属性赋值
public class Bean3 {
    private int id;
    private String name;
    private String[] arrayValue;
    private List listValue;
    private Set  setValue;
    private Map mapValue;
    private Properties propValue;
    //get set方法
}

appliactionContext.xml

<beans  ..>
    <bean id="bean3" class="web.tarena.bean.Bean3">
    <!-- set方式注入 -->
    <property name="id" value="12"></property>
    <property name="name" value="liu"></property>
    <property name="arrayValue">
        <list>
            <value>a</value>
            <value>b</value>
            <value>c</value>
        </list>
    </property>
    <property name="listValue">
    <!-- list和数组很相似 -->
    <list>
      <value>list1</value>
      <value>list2</value>
      <value>list3</value>
    </list>
  </property>
  <property name="setValue">
    <set>
      <value>set1</value>
      <value>set2</value>
    </set>
  </property>
  <property name="mapValue">
    <map>
      <entry key="k1" value="v1"></entry>
      <entry key="k2" value="v2"></entry>
    </map>
  </property>
  <property name="propValue">
    <props>
      <prop key="p1">v1</prop>
      <prop key="p2">p2</prop>
    </props>
  </property>
</bean>
</beans>       

AOP概念


什么是AOP

AOP,Aspect Oriented Programming被称为面向方面编程。对单个对象(一对一)的解耦用IoC,而当有共通组件,它对应多个其他组件(一对多),则解耦用AOP。如拦截器。这也是为何在程序中大量的用IoC,而AOP却用的很少,因为程序中不可能有很多的共通部分。

AOP主要解决共通处理和目标组件之间解耦。

AOP的相关术语

1. 方面Aspect,指的是封装了共通处理的功能组件。该组件可以作用到某一批目标组件的方法上。方面也可以说是通知的集合。

2. 通知Advice,用于指定方面组件的目标组件方法之间的作用时机。例如:先执行方面组件再执行目标方法,或先执行目标方法再执行方面组件。

3. 目标对象Target,要使用Advice操作的方法的对象

4. 连接点JoinPoint,指的是方面组件和具体的哪一个目标组件的方法有关系。

5. 切入点Pointcut,用于指定目标组件的表达式。指的是方面组件和哪一批目标组件方法有关系。多个连接点组成的集合就是切入点。

AutoProxy动态代理

采用AOP之后,容器返回的对象是代理对象。用户在使用时,由代理对象调用切面组件和目标对象的功能。

spring支持JDK动态代理和cglib动态代理。JDK动态代理默认提供的,spring以JDK代理为主。cglib动态代理,spring需要依赖第3方cglib-nodep-2.1_3.jar来实现。

注意spring在默认情况下

1. 目标对象有接口采用JDK动态代理。比如 FeeDaoImpl implements FeeDAO

2. 目标对象没有接口采用CGLIB代理。

修改配置<aop:config proxy-target-class="true"/> proxy-target-class默认是false,表示有接口使用JDK,没有接口使用cglib代理。设置成true,强制都使用cglib代理

AOP案例

想让所有的操作进行日志记录,那么按以前的方式就需要给所有Action或DAO中添加日志记录的代码,如果Action或者DAO很多,那么不容易维护。而使用AOP机制,则可以很方便的实现上述功能。

1. 导入AOP需要的包 aspectjrt.jar  aspectjweaver.jar

2. 目标对象

3. 切面类

//切面类(Aspect)
public class LoggerBean {
     //这个类下面的方法都是通知。通知(Advice),切面类中的方法就是通知
    public void logger(){
        System.out.println("记录当前的操作");
    }
}

4. 配置文件

<beans ...>
    <!-- 切面类 -->
    <bean id="loggerBean" class="com.test.aop.aspect.LoggerBean"></bean>
    <!-- 目标对象 -->
    <bean id="feeDao" class="com.test.dao.impl.feeDaoImpl"></bean>
    <!-- 配置AOP -->
    <aop:config>
      <!-- 切入点,如何找连接点,pointcut就是一个表达式,用来指向连接点(要操作的方法),within(com.test.dao.impl.*)在这个包下面的所有类和所有方法 -->
       <aop:pointcut expression="within(com.tarena.dao.impl.*)" id="feeDaoPoint"/>
       <!-- 切面,id切面的标识, -->
       <aop:aspect id="loggerAspect" ref="loggerBean">
              <!-- 通知前,就是在调用连接点之前调用方法logger,切入点feeDaoPoint所对应的路径com.test.dao.impl.*,即impl包下所有的方法在执行前都用logger方法 -->
              <aop:before method="logger" pointcut-ref="feeDaoPoint"/>
       </aop:aspect>
   </aop:config>
</beans>

通知类型和切入点


通知类型

通知决定方面组件和目标组件作用的关系。主要有以下几种类型通知

a. 前置通知 <aop:before/>,方面组件在目标方法之前执行

b. 后置通知<aop:after-returning/>,方面组件在目标方法之后执行,目标方法没有抛出异常才执行方面组件

c. 最终通知<aop:after>,方面组件在目标方法之后执行,目标方法有没有异常都会执行方面组件。

d. 异常通知<aop:after-throwing>,方面组件在目标方法抛出异常后执行。

e. 环绕通知<aop:around>,方面组件在目标方法之前和之后执行。环绕通知等价于前置+后置通知

try{
    //前置通知
    //执行目标方法
    //后置通知
} catch(){
    //异常通知
}fially{
    //最终通知
}

切入点

切入点用于指定目标组件和方法,Spring提供了多种表达式写法

方法限定表达式

指定哪些方法启用了方面组件

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

②示例

execution(public * *(..)):匹配容器中所有修饰符是public(不写则无要求的),返回类型、方法名,参数列表也不要求的方法。

execution(* set*(..)):匹配容器中,方法以set开头的所有方法

execution(* org.test.CostDAO.*(..)):匹配CostDAO类中的所有方法。

execution(* org.test.dao.*.*(..)):匹配dao包下所有类所有方法

execution(* org.test.dao..*.*(..)):匹配dao包及子包中所有类所有方法

execution(* com.test.dao.impl.feeDaoImpl.save*(..))

第一个*指的是返回值任意

第二个*指的是方法名以save开头的任意方法

第三个..指的是方法的参数任意

类型限定表达式

指定哪些类型的组件的所有方法启用方面组件(默认就是所有方法都启用,且只到类型,不到方法)

①形式:within(类型)

②示例

within(com.xyz.service.*),匹配service包下的所有类所有方法

within(com.xyz.service..*),匹配service包及其子包中的所有类所有方法

within(org.test.dao.CostDAO),匹配CostDAO所有方法

注意:within(com.xyz.service.*.*)是错误的,只到类名,不到方法名

Bean名称限定

按<bean>元素的id值进行匹配。

①形式:Bean(id值)

②示例

bean(costDAO),匹配id=costDAO的bean对象

bean(*DAO),匹配所有id值以DAO结尾的bean对象

args参数限定表达式

按方法参数类型限定匹配

①形式:args(类型)

②示例

args(java.io.Serializable)匹配方法只有一个参数,并且类型符合Serializable的方法。public void f1(String s)、public void f2(int  i)都能匹配。

上述表达式可以使用&&、||运算符连接使用

案例A-环绕通知

环绕通知与其他通知有点区别,它要求程序员调用目标对象的连接点方法,否则连接点方法不会执行

案例:通过logger方法显示当前用户操作的目标对象的类型以及目标对象操作的方法 (连接点的方法)

1. 导入包 aspectjrt.jar  aspectjweaver.jar  cglib.jar

2. 目标对象

public interface UserDao {
  void saveUser(String username);
}
public class UserDaoImpl implements UserDao{
    //连接点
    public void saveUser(String username) {
        System.out.println("保存操作");
    }
}

3. 切面

public class LoggerBean {
  //利用反射
   //连接点对象ProceedingJoinPoint
  public void logger(ProceedingJoinPoint pjp) throws Throwable{
    //调用目标对象的连接点方法,如果不加这句那么连接点方法不执行
    pjp.proceed();
    //获得当前执行的方法的类型名
    String className=pjp.getTarget().getClass().getName();
     //获得当前执行的方法的名字
    String methodName=pjp.getSignature().getName();
    System.out.println("您正在执行"+className+"类的"+methodName+"方");
  }
}

4. 配置

<beans ...>
    <!-- 切面 -->
    <bean id="loggerBean" class="com.tarena.aop.aspect.LoggerBean"></bean>
    <!-- 目标对象 -->
    <bean id="userDao" class="com.tarena.dao.impl.UserDaoImpl"></bean>
    <!-- 配置AOP -->
    <aop:config>
        <aop:pointcut id="userDaoPointcut"  expression="execution(* com.test.dao..*.*(..))"/>
        <aop:aspect id="loggerAspect" ref="loggerBean">
            <aop:around method="logger" pointcut-ref="userDaoPointcut"/>
        </aop:aspect>
    </aop:config>
</beans>    

案例B-异常通知

目标对象运行产生异常时,把异常信息通过日志方式记录到文件中。在A案例中添加 

1. log4j.properties

#--------console-----------

#log4j.rootLogger=warn,myconsole
#log4j.appender.myconsole=org.apache.log4j.ConsoleAppender
#log4j.appender.myconsole.layout=org.apache.log4j.SimpleLayout

#--------file-----------

log4j.rootLogger=error,myfile
log4j.appender.myfile=org.apache.log4j.FileAppender
log4j.appender.myfile.File=D:\error.htm
log4j.appender.myfile.layout=org.apache.log4j.HTMLLayout

2. 添加切面类

//切面,(截获异常信息)
public class ExceptionLogger {
    private Log log=LogFactory.getLog(this.getClass());
    //将异常的信息写到文件中,D盘下面的error.html
    public void exceptionLogger(Exception ex){
      //1、获得当前异常的堆栈信息
      StackTraceElement[] els=ex.getStackTrace();
      //2、需要放入第一行的内容els[0] (java.lang.NullPointerException)
       log.error(ex.getClass().getName());
       log.error(els[0]);
    }
}

3. 配置信息

<beans ...>
    <!-- 切面 -->
    <bean id="loggerBean" class="com.tarena.aop.aspect.LoggerBean"></bean>
    <bean id="exceptionLogger" class="com.tarena.aop.aspect.ExceptionLogger"></bean>
    <!-- 目标对象 -->
    <bean id="userDao" class="com.tarena.dao.impl.UserDaoImpl"></bean>
    <!-- 配置AOP -->
    <aop:config>
        <aop:pointcut id="userDaoPointcut" expression="execution(* com.test.dao..*.*(..))"/>
        <aop:aspect id="loggerAspect" ref="loggerBean">
            <aop:around method="logger" pointcut-ref="userDaoPointcut"/>
       </aop:aspect>
       <aop:aspect id="exceptionLoggerAspect" ref="exceptionLogger">
         <!-- throwing:和方法exceptionLogger中的参数名相同。注意一定要把异常抛出来才行,try-catch了不行 -->
         <aop:after-throwing method="exceptionLogger" pointcut-ref="userDaoPointcut" throwing="ex"/>
       </aop:aspect>
  </aop:config>
</beans>    

spring注解配置


注解技术从JDK5.0推出,之后很多框架开始提供注解配置形式。Spring框架从2.5版本开始支持注解配置。

功能:简化spring的配置文件,把spring的配置文件的信息,放入到各个类当中。

优点:方便快捷,可以减少spring的配置文件

缺点:当项目过大的时候,里面可能会有很多个类(比如1000个),在每个类当中加入注解。容易出现错误,而且不易于管理和维护。

开始是否使用注解,主要看公司的要求以及项目的规模。

AOP注解(了解)

 @Aspect

 @Before

 @After

 @Around

 @AfterReturning

 @AfterThrowing

 @Pointcut

案例-使用注解方式

1. 在配置文件中加入:xmlns:context="http://www.springframework.org/schema/context",content可以直接管理注解

2. applicationContext.xml文件;

<beans ...xmlns:context="http://www.springframework.org/schema/context" >
    <!-- 开启AOP注解 ,启动注解-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <!-- 切面 -->
    <bean id="exceptionBean" class="com.tarena.aop.aspect.ExecptionLogger"></bean>
    <bean id="loggerBean" class="com.tarena.aop.aspect.LoggerBean"></bean>
    <!-- 目标对象 -->
    <bean id="userDao" class="com.tarena.dao.impl.UserDaoImpl"></bean>
   <!-- 使用注解后,就没有AOP的配置了 -->
</beans>

3. 切面(修改最多的)

// 使用AOP注解,首先确定切面,然后确定通知
@Aspect
public class LoggerBean {

    // 只有一个pointcut
    @Around("execution (* com.tarena.dao..*.*(..))")
    public void logger(ProceedingJoinPoint pjp) throws Throwable {
        pjp.proceed();
        String className = pjp.getTarget().getClass().getName();
        String methodName = pjp.getSignature().getName();
        String key = className + "." + methodName;
        String value = PropertiesUtil.getValue(key);
        System.out.println("用户的操作信息是:" + value);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        System.out.println("操作的时间是:" + dateFormat.format(new Date()));
    }
}
@Aspect
public class ExecptionLogger {
    @Pointcut("execution (* com.tarena.dao..*.*(..))")
    // 定义一个方法,该方法只起到标记一个id的作用
    public void myPointCutId() {
    }

    // 要放两部分信息,pointcut,throwing。pointcut里面不要直接放表达式
    @AfterThrowing(pointcut = "myPointCutId()", throwing = "ex")
    public void exceptionLogger(Exception ex) {
        StackTraceElement[] els = ex.getStackTrace();
        System.out.println(els[0]);
        Logger logger = Logger.getLogger(this.getClass());
        logger.error(ex.getClass().getName());
        logger.error(els[0]);
    }
}

4. 目标对象(没有变化)

public class UserDaoImpl implements UserDao {
    // 连接点
    public void deleteUserById(int id) {
        System.out.println("删除操作");
    }
    public String findUserById(int id) {
        System.out.println("查询操作");
        return null;
    }
    public void saveUser(String uname) {
        System.out.println("保存操作");
        String str = null;
        str.charAt(1);// 抛出异常
    }
    public void updateUser(String user) {
        System.out.println("修改操作");
    }
}

web开发中的注解(组件)

applicationContext.xml文件中有<bean>元素的配置,来生成Bean对象。web开发中的注解用来取消这些配置。简化操作。

   1组件扫描功能

    spring可以按照指定的包路径扫描内部的组件,当发现组件类定义前有相应的注解

    标记,会将该组件纳入spring容器管理中。

    web分为三层,dao是持久层或者是模型层,action或者servlet是控制层。

    @Repository:专门指代Dao层(dao层属于持久层或者模型层)

    @Service:专门指代Service层

    @Controller:专门用来指代控制层(action/servlet)

    @Component:指代任意的一层,切记在web三层中少用,为影响对架构控制。

                 用多了,哪一方是dao,哪一方是service都分不清楚。

    @Resource

    @Autowired

    注意:上述4个注解任意使用也可以,但不符合规范。

          注解只能用在类定义前、方法定义前、成员变量定义前。

    一般面试问的注解都是web开发中的注解,不是指AOP注解。

3、案例,使用组件注解方式

1)applicationContext.xml

<beans ...>

<!-- 开启AOP注解 ,启动注解-->

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

<!-- 启动组件扫描:逐个扫描com.tarena下的类 -->

<context:component-scan

base-package="com.tarena"></context:component-scan>

</beans>

2)切面

@Component

@Aspect

public class ExecptionLogger {

       @Pointcut("execution (* com.tarena.dao..*.*(..))")

       //定义一个方法,该方法只起到标记一个id的作用

       public void myPointCutId(){}

       //要放两部分信息,pointcut,throwing。pointcut里面不要放表达式

       @AfterThrowing(pointcut="myPointCutId()",throwing="ex")

       public void exceptionLogger(Exception ex){

             .....

}

}

@Component

@Aspect

public class LoggerBean {

  @Around("execution (* com.tarena.dao..*.*(..))")

  public void logger(ProceedingJoinPoint pjp) throws Throwable{

.....

  } 

}

 3)目标对象

@Repository("userDao")//userDao就是Bean对象的id标识

public class UserDaoImpl implements UserDao {

       public void deleteUserById(int id) {

              System.out.println("删除操作");

       }

....

}

 4)测试

public class TestSpring{

       public void test1(){

              BeanFactory factory=

new ClassPathXmlApplicationContext("applicationContext.xml");

              UserDao dao=(UserDao) factory.getBean("userDao");

              dao.findUserById(1);//测试LoggerBean切面

              dao.saveUser("");//测试ExceptionLogger切面

       }

}

4、web分层,控制层  业务层  DAO

1)dao层

     public interface UserDao {

             void saveUser(String uname);

             ...

}

public class UserDaoImpl implements UserDao {

       public void saveUser(String uname) {

              System.out.println("dao保存操作");

       }

       public void updateUser(String user) {

              System.out.println("修改操作");

       }

}

2)业务层

根据业务需要1次或者多次的调用Dao层,业务层具体解决问题层。

业务层依赖于dao层对数据库操作,实现业务需要。

public interface UserService {

        void saveUser(String uname);

}

public class UserServiceImpl implements UserService{

       //调用dao

       private UserDao userDao;//省略get set 方法

       public void saveUser(String uname) {

              System.out.println("业务:保存");

              userDao.saveUser(uname);

       }

}

3)action层

省略

4)applicationContext.xml

<beans ...>

       <!-- 配置dao -->

       <bean id="userDao" class="com.tarena.dao.impl.UserDaoImpl"></bean>

       <!--配置service -->

       <bean id="userService" class="com.tarena.service.impl.UserServiceImpl">

              <property name="userDao" ref="userDao"></property>

       </bean>

       <!-- 配置Action(省略) -->

</beans>

5)测试

public void test1(){

       BeanFactory factory=

new ClassPathXmlApplicationContext("applicationContext.xml");

       UserService service=(UserService) factory.getBean("userService");

       service.saveUser("");

}

5、使用注解来维护依赖关系(注入注解)

要求给UserServiceImple注入UserDao属性。

Spring不但支持自己定义的@Autowired注解,还支持由JSR-250规范定义的几个注解,

如:@Resource、 @PostConstruct及@PreDestroy。

@PostConstruct //等价于设置了init-method=”方法名”属性

public void myinit(){...}

@PreDestroy //等价于设置了destroy-method=”方法名”属性

public void mydestroy{...}

@Resource

private UserDao userDao;

userDao是名字,UserDao是类型

1)@Resource

   @Resource是J2EE提供的,需导入Package:javax.annotation.Resource;

     javaee1.5不需要额外导入包,javaee1.4需要导入包common-annotations.jar

   @Resource有两个中重要的属性:name和type 。

     Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为

     bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使

     用type属性时则使用 byType自动注入策略。如果既不指定name也不指定type

     属性,这时将通过反射机制使用byName自动注入策略,byName匹配不到后再使

     用byType自动注入策略。

   @Resource装配顺序

    (1). 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进

         行装配,找不到则抛出异常;

    (2). 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不

         到则抛出异常; 

     (3). 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到

         或者找到多个,都会抛出异常;

    (4). 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;

         如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

不需要set方法

    //凡是出現注解的地方都不需要set方法

2)@Autowired

   @Autowired:跟@Resource功能很相似,都是用来维护依赖的关系。

   @Autowired是spring提供的,默认只根据类型匹配注入。如果匹配到多个将报异常。

   可以手动的按照名称匹配。

   @Autowired

   @Qualifier("userDao")

   private UserDao userDao;

3)@Resource和@Autowired的区别

a、@Autowired 与@Resource都可以用来装配bean. 都可以写在字段上,或写在

   setter方法上;写在字段上可以不用写set方法

b、@Autowired 默认按类型装配。

   如果我们想使用名称装配可以结合 @Qualifier注解进行使用;

c、@Resource(这个注解属于J2EE的),默认安装名称进行装配,名称可以通过

   name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取

   字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。

   当找不到与名称匹配的bean时才按照类型进行装 配。但是需要注意的是,如

   果name属性一旦指定,就只会按照名称进行装配。

  

 d、 推荐使用@Resource注解在字段上,是属于J2EE的,减少了与Spring的耦

     合,这样代码看起就比较优雅 。

     @Resource性能好,如果是@Autowired,会把UserDao接口对应的实现类全部

     遍历一遍  

     企业开发一般都使用@Resource

4)案例

DAO层

接口

public interface UserDao {

      void saveUser(String uname);

}

两个实现类

@Repository("userDao")//userDao就是Bean对象的id标识

@Scope("prototype")//单例还是多例

public class UserDaoImpl implements UserDao {

              public void saveUser(String uname) {

                     System.out.println("保存操作");

              }

}

@Repository

public class UserDaoMysqlImpl implements UserDao{

              public void saveUser(String uname) {

                     ...

}

}

业务层

接口

public interface UserService {

             void saveUser(String uname);

}

实现类

@Service("userService")//userService就相当于<bean>元素中id标识的作用

public class UserServiceImpl implements UserService{

              @Resource

              private UserDao userDao;

              public void saveUser(String uname) {

                     System.out.println("业务:保存");

                     userDao.saveUser(uname);

              }

}

配置文件

<beans ..>

       <!-- 开启AOP注解 ,启动注解-->

       <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    <!-- 启动组件扫描:逐个扫描com.tarena下的类 -->

    <context:component-scan base-package="com.tarena"></context:component-scan>

</beans>

测试类

public void test1(){

              BeanFactory factory=

new ClassPathXmlApplicationContext("applicationContext.xml");

              UserService service=(UserService) factory.getBean("userService");

              service.saveUser("");

       }

八、数据连接池

1、为什么要使用数据连接池?

获得数据库连接的过程DriverManager.getConnection()是非常消耗系统性能的操作,如

果过于频繁获得连接,会导致系统性能急剧下降,甚至崩溃。

一般获得连接会占用85%的时间。一般上线的项目都使用连接池。

2、连接池原理

连接池中有很多创建好的连接。请求过来后,申请连接,连接池返回一个连接,用完连

接以后,释放连接(不是关闭连接),别人可以继续使用这个连接。

连接池主要做三件事:建立连接(服务器启动,建立一定数量的连接)

              管理连接      

释放连接(服务器关闭,连接池也关闭,连接释放)

连接池原理:复用已经建立好的数据库连接

hibernate内部默认有一个小连接池。

3、连接池的使用步骤

1)建立数据库连接池对象(服务器启动的时候创建)

2)按照事先设计好的初始化连接数量,创建数据库的连接

3)对于一个数据库的访问,直接从连接池获取连接

4)操作数据库

5)将连接重新放入连接池中

  (3---5,在项目运行中反复的出现)

6)释放连接池对象

      (服务器关闭,维护期间,释放数据库连接池,释放所有的连接)

4DBCP连接池

    使用必须要导入两个jar包

commons-dbcp-1.2.2.jar

commons-pool.jar

5、连接池的核心类和核心接口

1)DataSource接口  javax.sql.DataSource

       DataSource 对象所表示的物理数据源的连接。作为 DriverManager 工具的替代项,

       DataSource 对象是获取连接的首选方法 。

       DataSource有抽象方法getConnection();由实现类覆盖。

       所有连接池的核心都会间接或直接实现该接口。

2)BasicDataSource类

       org.apache.commons.dbcp.BasicDataSource,实现了DataSource接口

九、spring整合JDBC

1、工具类JdbcTemplate

 spring整合Jdbc所用的工具类,里面封装了所有对jdbc的基本操作。

 企业开发中,一般dao操作数据库都是一条sql语句+工具类的一个方法

 Dao层:

 String sql = “”

 jdbcTemplate.方法(sql,参数)

2、创建JdbcTemplate对象

class JdbcTemplate {

      带DataSource参数的构造方法来生成对应的JdbcTemplate对象。

  public JdbcTemplate(DataSource dataSource) {

              setDataSource(dataSource);

              afterPropertiesSet();

  }

所以创建JdbcTemplate对象对象需要传入一个DataSource参数

3dao

public class CostDaoImpl implements CostDao {

       private JdbcTemplate jdbcTemplate ;

       public void setDataSource(DataSource dataSource){

              jdbcTemplate =  new JdbcTemplate(dataSource);

       }

}

必须注入一个DataSource对象,强调是实现DataSource接口的对象,一般注入的是连

接池核心类对象,比如BasicDataSource。

4、JdbcTemplate的常用方法

update()       增删改

query()                查询

queryForObject()

queryForList()

queryForLong()

queryForMap()

注意:查询对象的操作

jdbc返回的结果封装到ResultSet对象当中,Dao返回的结果,往往是一个entity对象。

需要从ResultSet集合转换成entity对象。需要实现spring提供的RowMapper接口。

或者使用spring的BeanPropertyRowMapper类。

public class CostMapper implements RowMapper{

       //把rs转化成一个Object对象,不会有任何的问题

       public Object mapRow(ResultSet rs, int rowNum) throws SQLException {

              Cost cost=new Cost();

              cost.setId(rs.getInt("ID"));

              cost.setName(rs.getString("NAME"));  .....

              return cost;

       }

}

public Cost findById(int id) {

String sql = "select * from cost" + " where id=?";

CostMapper costMapper = new CostMapper();

// return (Cost) jdbcTemplate.queryForObject(sql, new Object[]{id},costMapper );

return (Cost) jdbcTemplate.queryForObject(sql, new Object[] { id },

                                                 new BeanPropertyRowMapper(Cost.class));

//BeanPropertyRowMapper:实现RowMapper接口的对象

//不稳定,如果对象的字段为空的时候,容易出现异常

// 不同的spring版本,返回不同的结果

}

5、案例

1)实体类以及实体类对应的Mapper类

public class Cost {

       private Integer id;

       private String name;

       private Integer baseDuration;

       private Double baseCost; 

       private Double unitCost;

       private String status;

       private String descr;

       private Date createTime;

       private Date startTime;

       private String costType;

       ....

}

public class CostMapper implements RowMapper{

       //把rs转化成一个Object对象,不会有任何的问题

       public Object mapRow(ResultSet rs, int rowNum) throws SQLException {

              Cost cost=new Cost();

              cost.setId(rs.getInt("ID"));

              cost.setName(rs.getString("NAME"));

              cost.setBaseDuration(rs.getInt("BASE_DURATION"));

              .....

return cost;

       }

}

2)配置文件applicationContext.xml

<beans ....>

<!-- spring整合jdbc -->

<!---让spring来管理数据连接源对象--->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

<!---基本属性 driverClassName  url  username  password --->

<property name="driverClassName"

value="oracle.jdbc.driver.OracleDriver"></property>

       <property name="url"

value="jdbc:oracle:thin:@172.17.3.6:1521:ora10g"></property>

       <property name="username" value="szsd1307"></property>

       <property name="password" value="szsd1307"></property>

       <!-- initialSize:连接池创建的时候,初始化连接数量,不配置默认是0个

              maxWait:如果没有连接,最长的等待时间,单位是毫秒数

              maxActive:连接池在同一时间内分配最大的使用连接数量-->

       <property name="initialSize" value="10"></property>

       <property name="maxWait" value="2000"></property>

       <property name="maxActive" value="50"></property>

</bean>

<!-- 该实现DataSource接口的BasicDataSource注入到dao当中

创建JdbcTemplate对象时,需要传入参数DataSource -->

<bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

       <property name="dataSource" ref="dataSource"></property>

</bean>

</beans>

3)DAO层

接口

public interface CostDao {

       void saveCost(Cost cost);

       void deleteCost(Cost cost);

       void updateCost(Cost cost);

       Cost findById(int id);

       List<Cost> findAll();

       long findCount();

       //查询最高(unit_cost,最低unit_cost,平均unit_cost)

       Map findUnitCost();

}

实现类

public class CostDaoImpl implements CostDao{

       private JdbcTemplate jdbcTemplate;

       //通过外界注入参数(数据库连接参数)

       public void setDataSource(DataSource datasource){

              jdbcTemplate=new JdbcTemplate(datasource);

       }

       public void deleteCost(Cost cost) {

              String sql="delete from COST_QIN where id=?";

              jdbcTemplate.update(sql, new Object[]{cost.getId()});

        //第一个参数放sql语句,第二个参数放对象数组,里面放入?对应的值

       }

       public List<Cost> findAll() {

              String sql="select * from COST_QIN";

              return jdbcTemplate.query(sql,new CostMapper());

       }

       public Cost findById(int id) {

              String sql="select * from cost_qin where id=?";

RowMapper costMapper=new CostMapper();

return (Cost)jdbcTemplate.queryForObject

(sql, new Object[]{id}, costMapper);

       }

       public void saveCost(Cost cost) {

              String sql="insert into COST_QIN(ID,NAME,BASE_DURATION,

  BASE_COST,UNIT_COST,STATUS,DESCR,CREATIME,

  STARTIME,COST_TYPE) " +

                              "values(COST_SEQ.NEXTVAL,?,?,?,?,?,?,?,?,?) ";

              jdbcTemplate.update(sql, new Object[]{cost.getName(),cost.getBaseCost(),

cost.getBaseCost(),cost.getUnitCost(),cost.getStatus(),cost.getDescr(),cost.get

CreateTime(),cost.getStartTime(),cost.getCostType()});

       }

       public void updateCost(Cost cost) {

              String sql="update COST_QIN set NAME=?,BASE_DURATION=?,

 BASE_COST=?,UNIT_COST=?,STATUS=?,DESCR=?,

 CREATIME=?,STARTIME=?,COST_TYPE=? WHERE ID=?";

              jdbcTemplate.update(sql, new Object[]{cost.getName(),cost.getBaseCost(),

cost.getBaseCost(),cost.getUnitCost(),cost.getStatus(),cost.getDescr(),cost.get

CreateTime(),cost.getStartTime(),cost.getCostType(),cost.getId()});

       }

       public long findCount() {

              //sql语句当中,切记尽量少出现"*"

//一般对于数据的都用long类型

              String sql="select count(id) from cost_qin";

              return jdbcTemplate.queryForLong(sql);

       }

       public Map findUnitCost() {

              String sql="select max(unit_cost),min(unit_cost),avg(unit_cost)

         from cost_qin";

              return jdbcTemplate.queryForMap(sql);

       }

}

4)测试类

      public class TestSpring {

       public void test1(){

              BeanFactory factory=new

ClassPathXmlApplicationContext("applicationContext.xml");

              CostDao  costDao=(CostDao) factory.getBean("costDao");

              Cost cost=new Cost();

              cost.setId(168);

              costDao.deleteCost(cost);

       }

....

6DaoSupport 

是spring提供专门用来Dao层公共抽象类,spring建议程序员在写Dao层,

所有的类最好都继承DaoSupport下属子类。

1)针对jdbc:继承JdbcDaoSupport

JdbcDaoSupport:内部包含一个JdbcTemplate对象,以简化操作。

       可以通过 getJdbcTemplate()方法获得JdbcTemplate对象

public abstract class JdbcDaoSupport extends DaoSupport {

       private JdbcTemplate jdbcTemplate;

       public final void setDataSource(DataSource dataSource) {

              if (this.jdbcTemplate == null || dataSource !=

this.jdbcTemplate.getDataSource()) {

                     this.jdbcTemplate = createJdbcTemplate(dataSource);

                     initTemplateConfig();

              }

       }

public final JdbcTemplate getJdbcTemplate() {

         return this.jdbcTemplate;

}

}

   之所以要继承JdbcDaoSupport,主要是因为JdbcDaoSupport类中有一个属性

   JdbcTemplate。不继承也可以,在dao实现类中添加属性JdbcTemplate

2)针对hibernate:继承HibernateDaoSupport  

   包含一个hibernateTemplate

       spring建议使用hibernate做开发的时候,dao最好继承

       HibernateDaoSupport,以便利用里面工具类hibernateTemplate

7、修改Dao实现类,采用继承JdbcDaoSupport方式

public class CostDaoImpl extends JdbcDaoSupport implements CostDao{

// CostDaoImpl 继承了 JdbcDaoSupport类,

//相当于CostDaoImpl有了下面的代码

private JdbcTemplate jdbcTemplate;

       public final void setDataSource(DataSource dataSource) {

              if (this.jdbcTemplate == null || dataSource !=

this.jdbcTemplate.getDataSource()) {

                     this.jdbcTemplate = createJdbcTemplate(dataSource);

                     initTemplateConfig();

              }

       }

//有了属性JdbcTemplate,创建JdbcTemplate依然要注入DataSource参数。

//applicationContext.xml配置文件不需要改变

       public void deleteCost(Cost cost) {

              String sql="delete from COST_QIN where id=?";

              this.getJdbcTemplate().update(sql, new Object[]{cost.getId()});

}

       public List<Cost> findAll() {

              String sql="select * from COST_QIN";

              return this.getJdbcTemplate().query(sql,new CostMapper());

       }

.....

       public Map findUnitCost() {

              String sql="select max(unit_cost),min(unit_cost),avg(unit_cost) from cost_qin";

              return this.getJdbcTemplate().queryForMap(sql);

       }

}

十、spring整合hibernate

1、spring整合Hibernate步骤

1)导入hibernate的jar包 hibernate常用的版本是3.2或者3.5

2)导入hibernate的配置文件

3)生成对应po类和orm映射文件

4)导入spring的jar包

5)导入spring核心配置文件

2、spring整合hibernate的工具类

HibernateTemplate类

封装了spring针对hibernate的方法,简化hibernate的操作。

该类的构造器

public HibernateTemplate(SessionFactory sessionFactory) {

         setSessionFactory(sessionFactory);

         afterPropertiesSet();

}

说明在创建HIbernateTemplate对象时,需要传入一个Sessionfactory参数。

public class CostDaoImpl implements CostDao {

       private HibernateTemplate hibernateTemplate;

//使用spring的DI依赖注入,使用set注入一个SessionFactory

//让spring管理hibernate的数据源

       public void setSessionFactory(SessionFactory sessionFactory){

//创建带sessionFactroy的hibernateTemplate对象

              hibernateTemplate =  new HibernateTemplate(sessionFactory);

       }

}

3、注入SessionFactory

1、创建hibernateTemplate对象时,需要传入一个参数SessionFactory

   SessionFactory代表了hibernate配置文件中的所有信息,sessionfactory只有一份

   1)、数据库的连接信息

   2)、hibernate自身的属性信息

   3)、hibernate映射文件

   注意不是注入DataSource,DataSource只是SessionFactory真的一小部分

2、使用spring核心配置文件注入SessionFactroy(第一种方式)

   <bean id="sessionFactory"

                    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >

       <property name="configLocation"  value="classpath:hibernate.cfg.xml"></property>

   </bean>

   <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

              <property name="sessionFactory" ref="sessionFactory"></property>

   </bean>

   上述配置注入了一个SessionFactory,

   类型为org.springframework.orm.hibernate3.LocalSessionFactoryBean,

   部分源代码:

   public class LocalSessionFactoryBean extends AbstractSessionFactoryBean

implements BeanClassLoaderAware {

       private Configuration configuration;

public void setConfigLocation(Resource configLocation) {

                     this.configLocations = new Resource[] {configLocation};

              }

   }

   LocalSessionFactoryBean类中的属性configuration用来用来加载资源文件,

   这里加载hibernate配置文件。

3、 问题:LocalSessionFactoryBean类型并不是SessionFactory接口类型

      (即没有实现Sessionfactory接口),如何实现注入的?

      LocalSessionFactoryBean 本身不是一个session factory,但是spring会自动把对这

    个bean的引用替换成LocalSessionFactoryBean 里面的真正的session factory。

   (1)在LocalSessionFactoryBean 中有个字段是存放真正的session factory的:

LocalSessionFactoryBean 继承了抽象类AbstractSessionFactoryBean

             抽象类中有:

public abstract class AbstractSessionFactoryBean

              implements FactoryBean, InitializingBean, DisposableBean,

PersistenceExceptionTranslator {

                         private DataSource dataSource;

private SessionFactory sessionFactory;  

                           public Object getObject(); {  

                       returnthis.sessionFactory;  

          }

当引用这个LocalSessionFactoryBean 的时候,比如

applicationContext.getBean("localSessionFactoryBean ")这样,spring返回的不是

LocalSessionFactoryBean 本身,他会自动调用getObject()这个方法,把真正的

session factory返回,得到的都是session factory而不是

LocalSessionFactoryBean 。

(2)LocalSessionFactoryBean实现了org.springframework.beans.factory.FactoryBean

 接 口, spring在装配的时候, 如果发现实现了factory.FactoryBean接口, 就会

 使用FactoryBean#getObject() 方法返回的对象装配。

 如果你想拿到LocalSessionFactoryBean实例, 在id前面加个'&'就可以了,在你

 的配置文件中BeanFactory.getBean('&sessionFactory')拿到的 就是

 LocalSessionFactoryBean的实例.     

4、案例

1)导入hibernate的jar包 hibernate常用的版本是3.2或者3.5

2)导入hibernate的配置文件

<hibernate-configuration>

       <session-factory>

              <!-- 方言,指定Hibernate语句生成的sql类型 -->

              <property name="dialect">org.hibernate.dialect.OracleDialect</property>

              <!-- 连接数据库属性 -->

              <propertyname="connection.url">

jdbc:oracle:thin:@172.17.3.6:1521:ora10g</property>

              <property name="connection.username">szsd1307</property>

              <property name="connection.password">szsd1307</property>

              <property name="connection.driver_class">

oracle.jdbc.OracleDriver</property>

              <!-- 将底层的sql操作显示出来 -->

              <property name="show_sql">true</property>

              <property name="format_sql">true</property>

<!--映射文件->

              <mapping resource="com/tarena/pojo/Cost.hbm.xml" />

       </session-factory>

</hibernate-configuration>

3)生成对应po类和orm映射文件

public class Cost implements java.io.Serializable {

       private Integer id;

       private String name;

       private Long baseDuration;

       private Double baseCost;

       private Double unitCost;

       private String status;

       private String descr;

       private Date creatime;

       private Date startime;

       private String costType;

       get/set方法

}

Cost.hbm.xml 省略

4)导入spring的jar包

5)导入spring核心配置文件

配置文件applicationContext.xml

<beans ..>

       <!-- 利用spring的工具类加载hibernate的核心配置文件hibernate.cfg.xml -->

       <bean id="sessionFactory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<!-- 加载核心配置文件放入sessionfactory属性configLocation中 -->

              <property name="configLocation"

value="classpath:hibernate.cfg.xml"></property>

       </bean>

       <!-- 配置CostDao -->

       <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

              <property name="sessionFactory" ref="sessionFactory"></property>

       </bean>

</beans>

6)DAO层(注意事务问题,下节讲)

public interface CostDao {

       void saveCost(Cost cost);

       void deleteById(int id);

       void updateCost(Cost cost);

       Cost findById(int id);

       List<Cost> findAll();

       //查询总的cost数量

       long findCount();

       List<Cost> findPage(int page,int pageSize);

}

第一种方式:添加一个HibernateTemplate类

public class CostDaoImpl implements CostDao{

       private  HibernateTemplate hibernateTemplate;

       public void setSessionFactory(SessionFactory sessionFactory){

              hibernateTemplate=new HibernateTemplate(sessionFactory);

       }

       public void saveCost(Cost cost) {

              //不要使用hql语句,hql语句可以查询,修改,删除就不是不能保存

              hibernateTemplate.save(cost);

       }

       public void updateCost(Cost cost) {

              hibernateTemplate.save(cost);

       }

       public Cost findById(int id) {

              return (Cost) hibernateTemplate.get(Cost.class, id);

       }

       public List<Cost> findAll() {

              //spring整合hibernate时,查询方法一般使用find方法,find方法返回一

//般都是list集合,spring没有整合uniqueResult,

              //如果使用hql查询,使用find,返回永远都是list

              //这是spring整合hibernate不太成功之一

              String hql="from Cost";

              return hibernateTemplate.find(hql);

       }

       public long findCount() {

              String hql="select count(id) from Cost";

              //最好先变成string再转成int。不要强转,spring的版本不同,返回可能

//是Long,Integer类型

              List list=hibernateTemplate.find(hql);

              long count=Long.parseLong(list.get(0).toString());

              return count;

       }

       public List<Cost> findPage(final int page,final int pageSize) {

              final String  hql="from Cost";

              //spring整合hibernate的时候,对分页没有很好的支持

              //必须要使用hibernate中的session来实现分页

              //使用回调的方式(固定写法,必须记住)

              return (List<Cost>) hibernateTemplate.execute(new HibernateCallback() {

                     //内部类使用外界的变量的时候,外界变量必须使用final修饰

                     @Override

                     public Object doInHibernate(org.hibernate.Session session)

                                   throws HibernateException, SQLException {

                            int begin=(page-1)*pageSize;

                            returnsession.createQuery(hql)

.setFirstResult(begin).setMaxResults(pageSize).list();

                     }

              });

       }

       public void deleteById(int id) {

              Cost cost=new Cost();

              cost.setId(id);

              hibernateTemplate.delete(cost);

             

       }

}

第二种方式:继承HibernateDaoSupport类

public class CostDaoImpl extends HibernateDaoSupport implements CostDao{

       public void saveCost(Cost cost) {

              this.getHibernateTemplate().save(cost);

       }

       public void updateCost(Cost cost) {

              this.getHibernateTemplate().save(cost);

       }

       public Cost findById(int id) {

              return (Cost)this.getHibernateTemplate().get(Cost.class, id);

       }

       public List<Cost> findAll() {

              String hql="from Cost";

              return this.getHibernateTemplate().find(hql);

       }

       public long findCount() {

              String hql="select count(id) from Cost";

              List list=this.getHibernateTemplate().find(hql);

              long count=Long.parseLong(list.get(0).toString());

              return count;

       }

       public List<Cost> findPage(final int page,final int pageSize) {

              final String  hql="from Cost";

             

              return (List<Cost>) this.getHibernateTemplate().

execute(new HibernateCallback() {

                     public Object doInHibernate(org.hibernate.Session session)

                                   throws HibernateException, SQLException {

                            int begin=(page-1)*pageSize;

                            return session.createQuery(hql)

.setFirstResult(begin).setMaxResults(pageSize).list();

                     }

              });

       }

       public void deleteById(int id) {

              Cost cost=new Cost();

              cost.setId(id);

              this.getHibernateTemplate().delete(cost);

       }           

}

5、spring+hibernate如何使用SessionQuery等对象

(1)方式一

 利用HIbernateDaoSupport提供的getSession方法。

 没用到延迟加载的API,那么用这个方式简单些。但是有延迟加载的API,则会

 出现问题:session关闭早了,页面可能获取不到数据;不关闭,一旦出了方法体

 则关不上了。而多次访问数据库后,就发现没结果,因为连接数用完了。

     Session session = getSession();

 ..............利用session进行一些操作.......

 session.close();//注意:一定要释放

 getHibernateTemplate中的API都有释放操作,所以自己不用再写。

(2)方式二

 利用HibernateTemplate.execute()方法,以回调函数方式使用。这种方式不用担心

 方式一出现的问题,session的关闭由HibernateTemplate统一管理。

 getHibernateTemplate().execute(

new HibernateCallBack(Session session){

public Object doInHibernate()throws HibernateException,SQLException{

//回调函数中使用session

}

}

 );

6、spring配置SessionFactory的第2中方式(更常用)

修改applicationContext.xml文件

将hibernate.cfg.xml文件去掉,把该文件的信息配置到applicationContext.xml文件中。

添加数据连接池的配置

<beans ...>

       <!-- 配置SessionFactory的第二种方式(企业项目上线的时候)

                  主要配置的是3部分参数

            1)DataSource(连接池对象)

            2)hibernate属性

            3)orm映射文件 -->

        <!-- 配置DBCP连接池 -->

        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

             <property name="driverClassName"

value="oracle.jdbc.OracleDriver"></property>

             <property name="url"

value="jdbc:oracle:thin:@172.17.3.6:1521:ora10g"></property>

             <property name="username" value="szsd1307"></property>

             <property name="password" value="szsd1307"></property>

             <property name="initialSize" value="10"></property>

        </bean>

        

       <bean id="sessionFactory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

              <property name="dataSource" ref="dataSource"></property>

              <property name="hibernateProperties">

                     <props>

                            <prop key="hibernate.dialect">

org.hibernate.dialect.OracleDialect</prop>

                            <prop key="hibernate.show_sql">true</prop>

                            <prop key="hibernate.format_sql">true</prop>

                     </props>

              </property>

              <property name="mappingResources">

                     <list>

                            <value>com/tarena/pojo/Cost.hbm.xml</value>

                     </list>

              </property>

       </bean>

       <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

              <property name="sessionFactory" ref="sessionFactory"></property>

       </bean>

</beans>

十一、spring事务管理

JDBC的底层是默认自动提交事务,每次执行JDBC都会在底层默认提交事务。HIbernate底层是默认手动提交事务,需要我们程序员自己去提交事务。

真实企业开发中:需要我们控制事务的提交,回滚等,比如银行转账,减钱和加钱同时提交事务才可以。

1、事务的传播特性

1)事务边界

   比如银行转账,减钱开始前和加钱结束后就是事务边界,共用同一个事务。

2)事务的传播特性

   事务的传播特性是指连续一次或者多次对数据库的操作,事务的控制。

   指多次对数据进行操作时,如何对事务进行控制就是事务的传播特性。

   对事务进行控制就是指控制什么时候开启,什么时候提交,什么时候回滚。

      (1)propagation_required  数据库操作1 数据库操作2 数据库操作3 ...

   连续两次或者多次操作数据库,都沿用同一个事务。

   如果存在一个事务,则支持当前事务,如果没有事务,则开启一个事务。

   比如:第一次查询没有事务,第二次删除操作,开启事务,第三次是修改操作,

         沿用删除操作开启的事务。

   增删改是required特性,必须要有事务。

  (2)propagation_not_supported

   非事务执行。一般用于查询操作(比如分页查询)

      (3)企业开发中,一般增删改操作配置成required,查询配置成not_supported

2、事务的隔离级别

   脏数据(永远不要出现):读到没有提交的数据。脏读就是读取没提交的数据

   不可重复读:数据提交到数据库,可以读数据。

               一条数据被修改的同时,另一个人也在修改该数据。

               同一时刻,多个人修改同一条数据,读出来的数据和自己修改的数据

   不一样

   幻象读:    整张表数据被修改,又插入一些新数据

               一个人对所有数据进行修改时,另一个人又插入一些新数据

               一个人访问所有数据的同时又有人添加了一些新数据

   脏读一定不能出现,不可重复读和幻象读可以出现

   1)read_uncommited

  最低的隔离级别,数据没有提交就能读,能看到

       企业开发一定尽量不要使用

   2)read_commited 

  提交后才能读(不能脏读)

   3)repeatable_read

  在我访问某条数据的时候,别人都不能访问,但可以访问其他数据。

  不会出现不可重复读,会出现幻觉读(指的是整张表中所有的数据)

   4)serializable 

      整张表在同一时刻只有一个人可以访问,访问结束后其他人才可以访问。

      不会出现不可重复读,不会出现幻想读。最昂贵的。

   最最常用的隔离级别是read_commited

   隔离一定要避免脏读(数据位提交,一定不能读取)

   面试问在隔离级别中要避免什么?避免脏读。

spring管理事务就是管理事务的传播特性和隔离级别

3、声明式事务(hibernate版本的)

通过spring配置文件来控制事务

通过spring配置来管理我们的事务(事务的传播特性和事务的隔离级别)。

   (1)指定事务管理器

       (事务管理器在spring底层来控制事务的对象,开启事务,提交事务,回滚事务等)

类HibernateTransactionManager中管理事务的方法

1)doBegin(){ hibTx = session.beginTransaction();} 开启事务

2)doCommit(){}                                                   提交事务

3)doRollBack(){}                                                  回滚事务

      <!-- 指定当前的事务管理器 -->

      <bean id="transactionManager"

             class="org.springframework.orm.hibernate3.HibernateTransactionManager">

             <!-- 使用HibernateTransactionManager必须注入一个SessionFactory -->

             <property name="sessionFactory"ref="sessionFactory"></property>

      </bean>

(2)配置事务特性(方法执行的时候,事务如何控制)

     a)事务的传播特性

           PROPAGATION_REQUIRED :增删改

           PROPAGATION_NOT_SUPPORTED:查询

     b)事务的隔离级别

           READ_COMMITED

 c)配置事务的特性(事务的传播特性和事务的隔离级别)

<!--

              transaction-manager指定事务管理器,由transactionManager来管理事务

DEFAULT指的是当前数据库默认的隔离级别

mysql必须修改隔离级别,oracle可以不修改,默认是read_commited

delete*":*匹配后面的任意的名字,比如匹配deleteUser... 其他同理

-->

       <tx:advice id="txAdvice" transaction-manager="transactionManager">

              <tx:attributes>

                     <tx:method name="find*" propagation="NOT_SUPPORTED"

read-only="true" isolation="READ_COMMITTED"/>

                     <tx:method name="save*" propagation="REQUIRED"

isolation="READ_COMMITTED"/>

                     <tx:method name="delete*" propagation="REQUIRED"

isolation="READ_COMMITTED"/>

                     <tx:method name="update*" propagation="REQUIRED"

isolation="READ_COMMITTED"/>

              </tx:attributes>

       </tx:advice>

(3)固定的Aop

<aop:config>

       <aop:pointcut expression="execution(* com.tarena.dao..*.*(..))" id="txPointcut"/>

       <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>

</aop:config>

4、applicationContext.xmlhibernate版本)

将spring整合hibernate的案例添加事务管理

<beans >

       <bean id="sessionFactory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

              <property name="configLocation"

value="classpath:hibernate.cfg.xml"></property>

       </bean>

       <bean id="transactionManager"

class="org.springframework.orm.hibernate3.HibernateTransactionManager">

              <property name="sessionFactory" ref="sessionFactory"></property>

       </bean>

       <tx:advice id="txAdvice" transaction-manager="transactionManager">

              <tx:attributes>

                     <tx:method name="find*" propagation="NOT_SUPPORTED"

read-only="true" isolation="READ_COMMITTED"/>

                     <tx:method name="save*" propagation="REQUIRED"

 isolation="READ_COMMITTED"/>

                     <tx:method name="delete*" propagation="REQUIRED"

isolation="READ_COMMITTED"/>

                     <tx:method name="update*" propagation="REQUIRED"

isolation="READ_COMMITTED"/>

              </tx:attributes>

       </tx:advice>

       <aop:config>

              <aop:pointcut expression="execution(* com.tarena.dao..*.*(..))" id="txPointcut"/>

              <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>

       </aop:config>

       <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

              <property name="sessionFactory" ref="sessionFactory"></property>

       </bean>

</beans>

5、使用注解方式配置事务

1)applicationContext.xml

<beans ...>

       <bean id="sessionFactory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<property name="configLocation"

value="classpath:hibernate.cfg.xml"></property>

       </bean>

       <!-- 1、指定当前事务的管理器

                管理事务 事务开启 提交 回滚 -->

       <bean id="transactionManager"

class="org.springframework.orm.hibernate3.HibernateTransactionManager">

              <property name="sessionFactory" ref="sessionFactory"></property>

       </bean>

       <!-- 2、开启事务的注解配置

            transaction-manager:指明让transactionManager管理事务 -->

       <tx:annotation-driven proxy-target-class="true"

transaction-manager="transactionManager"/>

      

       <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

              <property name="sessionFactory" ref="sessionFactory"></property>

       </bean>

</beans>

2)在业务组件的类定以前或方法中使用@Transactional注解即可

public class CostDaoImpl extends HibernateDaoSupport implements CostDao{

@Transactional(isolation=Isolation.READ_COMMITTED,

propagation=Propagation.REQUIRED)

              public void saveCost(Cost cost) {

                     .....

              }

@Transactional(isolation=Isolation.READ_COMMITTED,

propagation=Propagation.REQUIRED)

              public void updateCost(Cost cost) {

              .....

       }

@Transactional(isolation=Isolation.READ_COMMITTED,

propagation=Propagation.REQUIRED)

              public Cost findById(int id) {

              ....

              }

@Transactional(isolation=Isolation.READ_COMMITTED,

propagation=Propagation.REQUIRED)

              public List<Cost> findAll() {

                     ...

              }

}

3)注意事项

如果将Action当作目标,需要在<tx:annotation-driven>添加 proxy-target-class="true"

属性,表示不管有没有接口,都采用CGLIB方式生成代理类。

6、编程式事务管理

基于Java编程实现事务控制,不推荐使用。

主要是利用TransactionTemplate的execute()方法,以回调方式将多个操作封装在一个

事务中。

7spring针对JDBC的声明式事务

企业开发中,两层架构事务配置在action上,三层架构配置在service上面。

applicationContext.xml文件

<beans ...>

 <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:xe"></property>

      <property name="username"  value="system"></property>

      <property name="password"   value="1234"></property>

      <property name="initialSize"  value="10"></property>

      <property name="maxWait"   value="2000" ></property>

       <property name="maxActive"  value="50"></property>   

 </bean>

<!-- jdbc声明式事务 -->

<!-- 指定jdbc中的事务管理器DataSourceTransactionManager-->

<bean id="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

       <property name="dataSource" ref="dataSource"></property>

</bean>

<!-- 配置事务的特性(事务传播特性和隔离级别) -->

<tx:advice id="txadvice"

transaction-manager="transactionManager">

       <tx:attributes>

              <tx:method name="find*" propagation="NOT_SUPPORTED" read-only="true"

                                                              isolation="READ_COMMITTED"/>

              <tx:method name="save*"  propagation="REQUIRED"

                                                                isolation="READ_COMMITTED" />

              <tx:method name="update*" propagation="REQUIRED"

                                                                isolation="READ_COMMITTED"/>

              <tx:method name="delete*" propagation="REQUIRED"

 isolation="READ_COMMITTED" />

       </tx:attributes>

</tx:advice>

<aop:config>

       <!--事务配置到那个层(Action,dao)是pointcut决定的,

   一般来说如果Action,Dao结构,事务一般配置到Action

   如果是Action,service,dao结构事务一般配置到service      

   切记:事务尽量不要配置到dao层,在web项目中

      -->

      <aop:pointcut  expression="execution (* com.tarena.dao..*.*(..))"  id="curd"/>

     <!-- 针对事务,spring一般使用专用标签advisor,把通知和切入点连接起来-->

     <aop:advisor advice-ref="txadvice"  pointcut-ref="curd"/>

</aop:config>

<bean id="costDao"  class="com.tarena.dao.impl.CostDaoImpl">

       <property name="dataSource" ref="dataSource"></property> 

</bean>

</beans>

十二、spring整合struts2

1struts2 中常量定义

<constant name="" value=""></constant>

struts2这个框架,在运行本身配置很多的常量,而这些是应用于一般性的开发,这些常

量全部都配置在default.properties。

default.properties文件在struts2-core02.1.8.jar包中 /org/apache/struts2/default.properties

1)# struts.objectFactory = spring :由spring来提供struts2中

   action对象的创建及维护,默认情况下给注释了。

   struts本身负责创建action对象的类是:StrutsObjectFactory类

2)struts.i18n.encoding=UTF-8 :struts2默认编码是UTF-8

3)struts.action.extension=action,,

       提交的请求的后缀,struts默认情况下可以接收以.action和不加任何后缀结尾的请求

2、修改常量

    1)default.properties该文件中定义的常量的信息,可以随意的进行修改,修改方法

       在struts.xml中

   <constant name="" value=""></constant>重新定义值

   eg:<constant name="struts.action.extension" value="do"></constant>。

       更改为接收以.do为结尾的请求

   2)spring整合struts2,spring管理struts2中的Action对象的创建及维护,

      必须要修改default.properties中配置信息

  导入一个struts2-spring-plugin-2.0.11.2.jar

      有一个配置文件:struts-plugin.xml中

      <constant name="struts.objectFactory" value="spring" />

      修改default.properties中配置信息,由spring来创建并维护struts2中的Action对象

  struts-plugin.xml文件内容

  <struts>

    <bean type="com.opensymphony.xwork2.ObjectFactory" name="spring"

class="org.apache.struts2.spring.StrutsSpringObjectFactory" />

    指定struts的action对象由spring来创建维护,即StrutsSpringObjectFactory类。

这样struts请求过来时,Action对象将交给整合包spring容器获取,即struts2不再

产生Action对象。

    <constant name="struts.objectFactory" value="spring" />

 </struts>

3struts2中默认继承的包struts-default

<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />

默认关联ActionSupport

<!-- 跳转到新增页面的Action -->

<action name="toAddCost" >

              <result name="success">/WEB-INF/cost/addCost.jsp</result>

</action>

toAddCost请求------》默认关联ActionSupport------》execute方法,返回值是success

4spring整合struts2

1)原理:把struts2中的action对象的创建和维护,全部交给spring 统一的创建和维护。

  必须要导入struts2-spring-plugin-2.0.11.2.jar

  自动修改default.properties中的

  struts.objectFactory = spring,交由spring来维护action对象

2)什么时候加载spring核心配置?(把spring配置文件中bean全部实例化)

   监听器:

   启动服务器,就去实例化spring中的bean,提交性能

3)spring 提供加载配置文件的类:

org.springframework.web.context.ContextLoaderListener

4) 修改web.xml文件

5、案例整合资费模块

1) 首先添加spring,struts2,hibernate的jar包和配置文件

2) 对po类,修改成符合hibernate操作的po和orm映射文件

3) 修改spring核心配置文件,用来整合hibernate

4) 添加spring核心配置文件,用来配置action ,dao

    spring整合框架的配置文件最好单独作为一个配置文件

5) spring整合struts2

6) 重写CostDaoImpl(spring整合hibernate)

7) 重构Action,去掉工厂,使用spring的IOC,提供Action所依赖dao对象

1)导入包

2)po类和orm映射文件

3)applicationContext_hibernate.xml文件

   <beans ...>

<!-- 配置DataSource -->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

              <property name="driverClassName"

value="oracle.jdbc.driver.OracleDriver"></property>

              <property name="url"

value="jdbc:oracle:thin:@172.17.3.6:1521:ora10g"></property>

              <property name="username" value="szsd1307"></property>

              <property name="password" value="szsd1307"></property>

              <property name="initialSize" value="10"></property>

              <property name="maxWait" value="2000"></property>

              <property name="maxActive" value="50"></property>

   </bean>

<!-- 配置SessionFactory -->

   <bean id="sessionFactory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

              <property name="dataSource" ref="dataSource"></property>

              <property name="hibernateProperties">

                     <props>

                            <prop key="hibernate.dialect">

org.hibernate.dialect.OracleDialect</prop>

                            <prop key="hibernate.show_sql">true</prop>

                            <prop key="hibernate.format_sql">true</prop>

                     </props>

              </property>

              <property name="mappingResources">

                     <list>

                            <value>web/netctoss/cost/entity/Cost.hbm.xml</value>

                            <value>web/netctoss/account/entity/Account.hbm.xml</value>

                            ....

                     </list>

              </property>

   </bean>

<!-- 指定事务管理器 -->

<bean id="transactionManager"

class="org.springframework.orm.hibernate3.HibernateTransactionManager">

              <property name="sessionFactory" ref="sessionFactory"></property>

</bean>

<!-- 配置事务特性 -->

<tx:advice id="txAdvice" transaction-manager="transactionManager">

              <tx:attributes>

                     <tx:method name="find*" propagation="NOT_SUPPORTED"

isolation="READ_COMMITTED" read-only="true"/>

                     <tx:method name="delete*" propagation="REQUIRED"

isolation="READ_COMMITTED"/>

                     <tx:method name="update*" propagation="REQUIRED"

isolation="READ_COMMITTED"/>

                     <tx:method name="save*" propagation="REQUIRED"

isolation="READ_COMMITTED"/>

                     <!-- 添加action中的execute方法,暂时先用required -->

                     <tx:method name="execute" propagation="REQUIRED"

isolation="READ_COMMITTED"/>

              </tx:attributes>

</tx:advice>

<!-- AOP -->

<aop:config>

              <aop:pointcut expression="execution(* web.netctoss.cost.action.*.*(..) )"

id="costPointcut"/>

              <aop:pointcut expression="execution(* web.netctoss.account.action.*.*(..) )"

id="accountPointcut"/>

              <aop:pointcut expression="execution(* web.netctoss.service.action.*.*(..) )"

id="servicePointcut"/>

              <aop:advisor advice-ref="txAdvice" pointcut-ref="costPointcut"/>

              <aop:advisor advice-ref="txAdvice" pointcut-ref="accountPointcut"/>

              <aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>

</aop:config>

 </beans>

4)applicationContext_bean.xml

<!--资费模块模块 action,dao

   把struts2中的Action,纳入spring的管理,

   struts2中的Action的创建和维护都交给spring统一处理

   还有一个问题,struts2中的action是多例,spring中的bean是单例-->

<bean id="costDao" class="web.netctoss.cost.dao.impl.CostDAOImpl">

              <property name="sessionFactory" ref="sessionFactory"></property>

</bean>

<bean id="findCostAction" class="web.netctoss.cost.action.FindCostAction"

scope="prototype">

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

</bean>

5)action配置文件

<package name="cost" namespace="/cost" extends="netctoss">

<!-- struts中的action对象都是由spring来创建和维护,不用struts2来维护

    每一个action中的class属性的值,指向spring生成的Action对象bean的id -->

       <action name="findCost" class="findCostAction">

                     <interceptor-ref name="netctossStack"></interceptor-ref>

                     <!-- 属性注入 -->

                     <param name="pageSize">3</param>

                     <result name="success">/WEB-INF/cost/cost_list.jsp</result>

       </action>

6)修改action类

public class FindCostAction {

       .....输入输出属性

       private CostDAO costDao; 依赖注入dao类

       public String execute(){

              try {

                     costs=costDao.findByPages(page, pageSize);

                     totalPage=costDao.findTotalPage(pageSize);

              } catch (Exception e) {

                     e.printStackTrace();

                     return "error";

              }

              return "success";

}

 }

7)修改dao类

添加工具类HibernateTemplate类

8)修改web.xml文件

<web-app ...>

       <!-- 配置参数 -->

      <context-param>

             <param-name>contextConfigLocation</param-name>                                                 <param-value>classpath:applicationContext_*.xml</param-value>

      </context-param>

      <!-- 配置监听器,加载spring的核心配置文件 -->

      <listener>

<listener-class>

org.springframework.web.context.ContextLoaderListener

</listener-class>

      </listener>

      <filter>

              <filter-name>Struts2</filter-name>

              <filter-class>

                     org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

              </filter-class>

       </filter>

       <filter-mapping>

              <filter-name>Struts2</filter-name>

              <url-pattern>/*</url-pattern>

       </filter-mapping>

</web-app>

十三、Spring MVC

struts2和webwork是基于过滤器实现的

struts1和spring是基于servlet实现的

struts1的Action,servlet,springMVC的Controller是单例的,struts2的Action是多例的

springMVC流程

1、客户端发送请求

2、客户端发送的请求到达控制器,控制器由Servlet(DispacherServlet)实现的,完成请求的转发

3、该控制器(DispatcherServlet)调用一个用于映射的类HandlerMapping

   该类用于将请求映射到对应的处理器来处理请求

4、HandlerMapping将请求映射到对应的处理器Controller(相对于Action)

   在Spring当中如果写一些处理器组件,一般实现Controller接口

5、在Controller中就可以调用一些Service或DAO来进行数据操作

6、ModelAndView可以存放从Dao中取出的数据,还可以存放响应视图的一些数据

7、如果想将处理结果返回给用户,那么在Sping框架中还提供了一个视图组件ViewResolver,

   该组件根据Controller返回的标识,找到对应的视图,将响应返回给用户

案例

1、新建一个web项目导入jar包

       commons-logging.jar       spring-webmvc.jar        spring.jar

2、web.xml文件

       <web-app ...>

             <!-- springMVC首先截获所有.do结尾的请求,都交给DispatcherServlet统一处理

                   DispatcherServlet加载src目录下的spring-mvc.xml配置文件

                   springMVC的controller是单例

            -->

             <servlet>

                    <servlet-name>springMVC</servlet-name>

                    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

                  <init-param>

                            <param-name>contextConfigLocation</param-name>

                            <param-value>classpath:spring-mvc.xml</param-value>

                     </init-param>

             </servlet>

             <servlet-mapping>

                    <servlet-name>springMVC</servlet-name>

                    <url-pattern>*.do</url-pattern>

             </servlet-mapping>

</web-app>

3、login.jsp

<!-- struts1和springMVC所截获.do结尾的请求

          struts2的请求后缀可以任意修改 -->

       <form action="login.do" method="post">

              用户名:<input type="text" name="username"><br>

              密码:<input type="password" name="password"><br>

              <input type="submit" value="登录">

              <span style="color:red;">${errormessage }</span>

       </form>

       ok.jsp

<body>

       ${message }

</body>

4、control

   User类

public class User {

              //用来保存请求发送的请求数据,

              //每一个请求都有一个对应的user对象来保存数据

              private String username;

       private String password;

get/set方法

}

public class LoginControl extends SimpleFormController{

       //核心方法onSubmit,等价于struts2中的execute方法

       //                      servlet中的service(doPost和doGet方法)

      

       //command指代用来保存用户提交请求参数的对象,比如user对象

       @Override

       protected ModelAndView onSubmit(HttpServletRequest request,

                     HttpServletResponse response, Object command, BindException errors)

                     throws Exception {

              //1.接收请求参数

              User user = (User) command;

              //2.判断用户名为liu,密码为123才通过

       if(user!=null&&"liu".equals(user.getUsername())&&

"123".equals(user.getPassword())){

                     //3.用来保存数据,显示到页面中

                     // ModelAndView表示返回的信息,两部分信息

                     // ModelAndView(跳转页面的名字,要显示到页面中的信息                                                      ModelMap map = new ModelMap();

                     map.put("message", user.getUsername()+"登录成功");

                     return new ModelAndView("ok", map);//

              }else{

                     ModelMap map = new ModelMap();

                     map.put("errormessage", "登录失败,用户名或者密码错误");

                     return new ModelAndView("login", map);//

              }

       }

  5、sprin-mvc.xml

<!-- springMVC分成3个部分

                第一部分controlBean

                第二部分映射关系HandleMapping

                第三部分跳转信息 -->

               

             

      <!-- 配置bean信息 -->

       <bean id="loginControl" class="com.tarena.control.LoginControl">

              <property name="commandClass" value="com.tarena.control.User"></property>

       </bean>

       <!-- 请求和control的对应关系 -->

       <bean id="urlHandlerMapping"

class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

              <!-- mappings  请求和对应的处理类映射  -->

              <property name="mappings">

                     <props>

                            <!-- 有多少个请求就写多少个 -->

                            <prop key="login.do">loginControl</prop>

                     </props>

              </property>

       </bean>

      

       <!-- 跳转信息 -->

       <bean id="viewResolver"

   class="org.springframework.web.servlet.view.InternalResourceViewResolver">

              <property name="suffix" value=".jsp"></property><!-- 后缀 -->

              <property name="prefix" value="/"></property><!-- 前缀 -->

       </bean>

原文地址:https://www.cnblogs.com/qin-derella/p/6772928.html