spring知识

一、spring概述
 spring是一个开源的控制反转(inversion of control,IOC)和面向切面(AOP)的容器框架,主要目的是简化企业开发。
 
二、IOC控制反转
 public class PersonService {
  private PersonDao personDao = new PersonDao();
  public void save(Person person)
  {
   personDao.save(person);
  }
 }
 PersonDao是在应用内部创建及维护的,所谓控制反转就是应用本身不负责依赖对象的创建及维护,而是由外部容器负责,这样控制权就由应用转移到了外部容器。
 
三、依赖注入
 public class PersonService {
  private PersonDao personDao;
  // 构造器注入,容器把创建好的依赖对象注入进PersonService,也可使用setter方法进行注入。
  public PersonService(PersonDao personDao)
  {
   this.personDao = personDao;
  }
  public void save(Person person)
  {
   personDao.save(person);
  }
 }
 所谓依赖注入,就是指在运行期,由外部容器动态的将依赖对象注入到组件中。

四、spring的优点
 1、降低组件之间的耦合度,实现软件各层之间的解耦。
 2、可以使用容器提供的众多服务,如事务管理服务,消息服务等等,当我们使用容器管理事务时,就不再需要手工控制事务,也不需要处理复杂的事务传播,只需要通过声明式的事务属性配置就可实现。
 3、容器提供单例模式支持,开发人员不再需要自己编写实现代码。
 4、容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。
 5、容器提供众多的辅助类,使用这些类能加速应用的开发,如JdbcTemplate、HibernateTemplate。
 6、spring对于主流的应用框架提供了集成支持,如集成Hibernate、JPA、Struts等,更便于应用的开发。
 
五、使用spring需要的jar
 1、基本应用需要下列jar文件:
 dist\spring.jar
 lib\jakarta-commons\commons-logging.jar
 2、如果使用了切面编程,还需要下列jar文件:
 lib\aspectj\aspectjweaver.jar和aspectjrt.jar
 lib\cglib\cglib-nodep-2.1.3.jar
 3、如果使用了JSR-250的注解,如@Resource/@PostConstruct/@PReDestroy,还需要下列jar文件
 lib\j2ee\common-annotations.jar。
 
六、spring的配置文件模板
 <?xml version="1.0" encoding="UTF-8"?>
 <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-2.5.xsd">
 
   <bean id="..." class="...">
     <!-- collaborators and configuration for this bean go here -->
   </bean>
 
   <bean id="..." class="...">
     <!-- collaborators and configuration for this bean go here -->
   </bean>
 
   <!-- more bean definitions go here -->
 
 </beans>

七、实例化spring容器
 实例化spring容器常用的两种方式:
 1、在类路径下寻找配置文件来实例化容器。
 ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});
 2、在文件系统中寻找文件来实例化容器,通用性差,一般少用。
 ApplicationContext ctx = new FileSystemXmlApplicationContext(new String[]{"d:\\beans.xml"});
 spring的配置文件可以指定多个,可以通过String数组传入。

八、编写spring配置文件时,不能出现帮助信息的解决办法
 1、联网,eclipse会自动从网络下载scheme文件并缓存到硬盘。
 2、手动添加scheme文件,方法如下:
 windows->preferences->myeclipse->files and editors->xml->xmlcatalog,点击"add",在出现的窗口中,Key Type中选择URI,在location中选择“File System”,然后在spring解压目录的dist/resources目录中选择spring-beans-2.5.xsd,Key Type修改为Scheme location,key修改为http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

id不能包含特殊字符,如果包含用到特殊字符,需要配置name属性。

九、仿spring容器代码
 1、类BeanDefinition用于定义bean对象,包括id,类名。
 public class BeanDefinition {
  private String id;
  private String className;
  
  public String getId() {
   return id;
  }
  public void setId(String id) {
   this.id = id;
  }
  public String getClassName() {
   return className;
  }
  public void setClassName(String className) {
   this.className = className;
  }
  public BeanDefinition(String id, String className) {
   this.id = id;
   this.className = className;
  }
 }
 2、ItcastClassPathXmlApplicationContext主要功能包括:读取xml配置文件,实例化bean,获取bean实例等功能。代码如下:
 /**
  * 仿spring容器
  */
 public class ItcastClassPathXmlApplicationContext {
  private List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
  private Map<String, Object> sigletons = new HashMap<String, Object>();
 
  public ItcastClassPathXmlApplicationContext(String fileName) {
   this.readXml(fileName);
   this.instanceBeans();
  }
 
  /**
   * 完成bean的实例化
   */
  private void instanceBeans() {
   try {
    for (BeanDefinition beanDefinition : beanDefinitions) {
     if (null != beanDefinition.getClassName()
       && !"".equals(beanDefinition.getClassName())) {
      sigletons.put(beanDefinition.getId(), Class.forName(
        beanDefinition.getClassName()).newInstance());
     }
    }
   } catch (InstantiationException e) {
    e.printStackTrace();
   } catch (IllegalAccessException e) {
    e.printStackTrace();
   } catch (ClassNotFoundException e) {
    e.printStackTrace();
   }
  }
 
  /**
   * 读取配置文件
   * @param fileName 配置文件名称
   */
  private void readXml(String fileName) {
   SAXReader saxReader = new SAXReader();
   Document document = null;
 
   try {
    URL xmlPath = this.getClass().getClassLoader()
      .getResource(fileName);
    document = saxReader.read(xmlPath);
    Map<String, String> nsMap = new HashMap<String, String>();
    nsMap.put("ns", " 加入命名空间
    XPath xsub = document.createXPath("//ns:beans/ns:bean");// 创建beans/bean查询路径
    xsub.setNamespaceURIs(nsMap);// 设置命名空间
    List<Element> beans = xsub.selectNodes(document);// 获取文档下所有bean节点
    for (Element element : beans) {
     String id = element.attributeValue("id");// 获取id属性值
     String clazz = element.attributeValue("class");// 获取class属性值
     BeanDefinition beanDefinition = new BeanDefinition(id, clazz);
     beanDefinitions.add(beanDefinition);
    }
   } catch (DocumentException e) {
    e.printStackTrace();
   }
  }
  
  /**
   * 获取bean实例
   * @param beanName bean名称
   * @return
   */
  public Object getBean(String beanName)
  {
   return this.sigletons.get(beanName);
  }
 }

十、三种实例化bean的方式
 1、使用类构造器实例化
 <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean>
 2、使用静态工厂方法实例化
 <bean id="personService2" class="cn.itcast.service.impl.PersonServiceBeanFactory" factory-method="createPersonServiceBean"></bean>
 public class PersonServiceBeanFactory {
  public static PersonServiceBean createPersonServiceBean()
  {
   return new PersonServiceBean();
  }
 }
 3、使用实例工厂方法实例化
 <bean id="personServiceFactory" class="cn.itcast.service.impl.PersonServiceBeanFactory"></bean>
 <bean id="personService3" factory-bean="personServiceFactory" factory-method="createPersonServiceBean2"></bean>
 public class PersonServiceBeanFactory {
  public PersonServiceBean createPersonServiceBean2()
  {
   return new PersonServiceBean();
  }
 }
 
十一、bean的作用域
 1、singleton
 在每个spring ioc容器中一个bean定义只有一个对象实例,默认情况下会在容器启动时初始化bean,但可指定bean节点的lazy-init="true"来延迟初始化bean,这时只有第一次获取bean时才会初始化bean,例如:
 <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" lazy-init="true"></bean>
 如果想对所有bean都应用延迟初始化,可以在根节点beans设置:
 <beans default-lazy-init="true"/>
 注意:延迟加载一般不建议使用,启动时加载各个类,出现问题可以及时处理,延迟加载后,错误只能在运行时才能发现,不利于维护。
 2、prototype
 每次从容器获取bean都是新的对象。
 3、request
 4、session
 5、global session
 
十二、指定bean的初始化方法和销毁方法
 <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" init-method="init" destroy-method="destory"></bean>

十三、依赖注入方法
 1、使用构造器注入
 public PersonServiceBean(PersonDao personDao, String name) {
  this.personDao = personDao;
  this.name = name;
 }
 <bean id="personServiceConstructor" class="cn.itcast.service.impl.PersonServiceBean">
  <constructor-arg index="0" type="cn.itcast.dao.PersonDao" ref="personDao"></constructor-arg>
  <constructor-arg index="1" value="itcast"></constructor-arg>
 </bean>
 2、使用属性setter方法注入
 public void setPersonDao(PersonDao personDao) {
  this.personDao = personDao;
 }
 <bean id="personServiceSetter" class="cn.itcast.service.impl.PersonServiceBean">
  <property name="personDao" ref="personDao"></property>
 </bean>
 3、使用Field注入(用于注解方式)
 注入依赖对象可以采用手工装配和自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果。
 
十四、依赖注入---手工装配
 手工装配依赖对象,有两种编程方式
 1、在xml配置文件中,通过在bean节点下配置,例如:
 <bean id="personServiceConstructor" class="cn.itcast.service.impl.PersonServiceBean" init-method="init" destroy-method="destory">
  <constructor-arg index="0" type="cn.itcast.dao.PersonDao" ref="personDao"></constructor-arg> //构造器注入
  <property name="name" value="itcast"></property> //属性setter方法注入
 </bean>
 2、在java代码中使用@Autowired或@Resource注解方式进行装配,使用注解方式需要在xml配置文件中配置如下信息:
 <beans xmlns="

http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    <context:annotation-config></context:annotation-config>
 </beans>
 这个配置隐式注册了多个对注释进行解析处理的处理器:AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor。
 注意:@Resource注解在spring安装目录下的lib\j2ee\common-annotations.jar中。
 @Autowired和@Resource注解的区别:
 @Autowired默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean时才按类型装配。
 @Autowired
 private PersonDao personDao;//用于字段上
 @Autowired
 public void setPersonDao(PersonDao personDao) {//用于属性的setter方法上
  this.personDao = personDao;
 }
 @Autowired注解按类型装配依赖对象,默认情况下要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按名称装配,可以结合@Qualifier注解一起使用,例如:
 @Autowired @Qualifier("personDaoBean")
 private PersonDao personDao;
 @Resource注解和@Autowired注解一样,也可以标注在字段属性的setter方法上,但他默认按名称装配。名称可以通过@Resource的name属性指定,如果没有指定name属性,当注解标注在字段上,则默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,则默认取属性名作为bean名称寻找依赖对象。
 @Resource(name="personDaoBean")
 private PersonDao personDao;//用于字段上
 注意:如果没有指定name属性,并且按照默认的名称依然找不到依赖对象时,@Resource注解会回退到按类型装配,但一旦指定了name属性,就只能按名称装配了,此时如果根据name找不到依赖对象,则会报错。
 @AutoWired是spring注解,@Resource是j2ee注解,建议使用@Resource。
 
十五、集合类型的装配
 set、list、properties、map集合的注入配置:
 <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">
  <property name="personDao" ref="personDao"></property>
  <property name="sets">
   <set>
    <value>set1</value>
    <value>set2</value>
    <value>set3</value>
   </set>
  </property>
  <property name="lists">
   <list>
    <value>list1</value>
    <value>list2</value>
    <value>list3</value>
   </list>
  </property>
  <property name="properties">
   <props>
    <prop key="key1">value1</prop>
    <prop key="key2">value2</prop>
    <prop key="key3">value3</prop>
   </props>
  </property>
  <property name="maps">
   <map>
    <entry key="map_key1" value="map_value1"></entry>
    <entry key="map_key2" value="map_value2"></entry>
    <entry key="map_key3" value="map_value3"></entry>
   </map>
  </property>
 </bean>
 
十六、通过在classpath自动扫描方式把组件纳入spring容器中管理
 在一个大型项目中,通常会有成百上千个组件,如果这些组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便。spring2.5为我们引入了组件自动扫描机制,它可以在类路径下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入spring容器中管理。
 要使用自动扫描机制,需要打开以下配置信息:
 <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    <context:component-scan base-package="cn.itcast"></context:component-scan>
 </beans>
 其中base-package为需要扫描的包(含子包)。
 @Service用于标注业务层组件;
 @Controller用于标注控制层组件;
 @Repository用于标注数据访问组件;
 @Component泛指组件,当组件不好归类时,可以使用这个注解进行标注。
 
十七、依赖注入---自动装配依赖对象
 无需手工配置,系统自配装配,由于存在不可预知性,不推荐使用。
 <bean id="" class="" autowire="byType"/>
 autowire属性取值如下:
 1、byType:按类型装配,可以根据属性的类型,在容器中寻找跟该类型匹配的bean,如果发现多个,将抛出异常,如果没有找到,则属性值为null。
 2、byName:按名称装配,可以根据属性的名称,在容器中寻找跟该属性同名的bean,如果没有找到,则属性值为null。
 3、constructor:与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,将抛出异常。
 4、autodetect:通过bean类的自省机制来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。
 
十八、AOP---代理对象
 请求---代理对象---目标对象
 jdk代理类:
 public class JDKProxyFactory implements InvocationHandler {
  private Object targetObject;
  
  public Object createProxyInstance(Object targetObject)
  {
   this.targetObject = targetObject;
   return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), this.targetObject.getClass().getInterfaces(), this);
  }
 
  public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
   PersonServiceBean personServiceBean = (PersonServiceBean) this.targetObject;
   Object result = null;
   if(null != personServiceBean.getUser())
   {
    result = method.invoke(targetObject, args);//调用目标对象targetObject的method方法,传入参数args
   }
   return result;
  }
 }
 cglib代理类:
 public class CglibProxyFactory implements MethodInterceptor {
  private Object targetObject;
  
  public Object createProxyInstance(Object targetObject)
  {
   this.targetObject = targetObject;
   Enhancer enhancer = new Enhancer();
   enhancer.setSuperclass(this.targetObject.getClass());//代理继承目标类,对目标类中所有非final方法进行覆盖
   enhancer.setCallback(this);
   return enhancer.create();
  }
  
  public Object intercept(Object proxy, Method method, Object[] args,
    MethodProxy methodProxy) throws Throwable {
   PersonServiceBean personServiceBean = (PersonServiceBean) this.targetObject;
   Object result = null;
   // 环绕通知
   if(null != personServiceBean.getUser())
   {
    // 前置通知
    try
    {
     result = methodProxy.invoke(targetObject, args);//调用目标对象targetObject的method方法,传入参数args
     // 后置通知
    }
    catch(Exception e)
    {
     // 例外通知
    }
    finally
    {
     // 最终通知
    }
   }
   return result;
  }
 }

 
十九、AOP---基本概念
 1、Aspect(切面):横切性关注点的抽象即为切面,它与类相似只是两者的关注点不一样,类是对事物特征的抽象,切面是横切性关注点的抽象。
 2、joinpoint(连接点):那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是属性或类构造器。
 3、Pointcut(切入点):指我们要对那些joinpoint进行拦截的定义。
 4、Advice(通知):只拦截到joinpoint之后所要做的事情。分为前置通知,后置通知,异常通知,最终通知,环绕通知。
 5、Target(目标对象):代理的目标对象。
 6、Weave(织入):指将aspect应用到target对象并导致proxy对象创建的过程。
 7、Introduction(引入):在不修改代码的前提下,Introduction可以在运行期为类动态的添加一些方法或属性。

二十、使用spring进行面向切面编程
 要进行AOP编程,首先我们需要需要在spring配置文件中引入aop命名空间:
 <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans     
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
 <beans>
 spring提供了两种切面使用方式:
 1、基于xml配置方式进行AOP开发。
 2、基于注解方式进行AOP开发。
 
二十一、基于注解方式声明切面
 首先启动对@Aspect注解的支持,配置<aop:aspectj-autoproxy></aop:aspectj-autoproxy>。
 <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans     
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
 <beans>
 自定义拦截器代码:
 @Aspect
 public class MyInterceptor {
  @Pointcut("execution (* cn.itcast.service.impl.PersonServiceBean.*(..))")
  private void anyMethod(){}//声明一个切入点
  
  @Before("anyMethod() && args(name)")//拦截参数只有一个,并且必须是字符串类型的方法
  public void doAccessCheck(String name)
  {
   System.out.println("前置通知:"+name);
  }
  
  @AfterReturning(pointcut="anyMethod()",returning="result")//拦截返回类型为字符串的方法
  public void doAfterReturning(String result)
  {
   System.out.println("后置通知:"+result);
  }
  
  @After("anyMethod()")
  public void After()
  {
   System.out.println("最终通知");
  }
  
  @AfterThrowing(pointcut="anyMethod()",throwing="e")
  public void doAfterThrowing(Exception e)
  {
   System.out.println("例外通知:"+e);
  }
  
  @Around("anyMethod()")
  public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable
  {
   System.out.println("进入方法");
   Object result = pjp.proceed();
   System.out.println("退出方法");
   return result;
  }
 }
 没有异常时输出:
 前置通知:zhangsan
 进入方法
 我是save()方法
 最终通知
 后置通知:null
 退出方法
 发生异常时输出:不会执行后置通知和环绕通知的退出通知。
 前置通知:zhangsan
 进入方法
 最终通知
 例外通知:java.lang.RuntimeException: Exception
 
二十二、基于xml配置方式声明切面
 <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean>
 <bean id="myXmlInterceptor" class="cn.itcast.service.MyXmlInterceptor"></bean>
 <aop:config>
   <aop:aspect id="asp" ref="myXmlInterceptor">
    <aop:pointcut expression="execution(* cn.itcast.service.impl.PersonServiceBean.*(..))" id="mycut"/>
    <aop:before method="doAccessCheck" pointcut-ref="mycut"/>
    <aop:after-returning method="doAfterReturning" pointcut="mycut"/>
    <aop:after method="after" pointcut="mycut"/>
    <aop:after-throwing method="doAfterThrowing" pointcut="mycut"/>
    <aop:around method="doBasicProfiling" pointcut="mycut"/>
   </aop:aspect>
 </aop:config>
 
二十三、声明切面表达式
 execution(返回值 包名.类名.方法名(参数类型))
 execution(* cn.itcast.service..*.*(..))//拦截某包及其子包下的所有类所有方法
 execution(!void cn.itcast.service.impl.PersonServiceBean.*(..))//拦截PersonServiceBean类中返回值类型不为void的方法
 
二十四、spring+jdbc整合开发
 使用spring+jdbc集成步骤如下:
 1、配置数据源:
 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="org.gjt.mm.mysql.Driver"></property>
  <property name="url" value="jdbc:mysql://localhost:3306/itcast?useUnicode=true&amp;character=UTF-8"></property>
  <property name="username" value="root"></property>
  <property name="password" value="123456"></property>
  <!-- 连接池启动时的初始值 -->
  <property name="initialSize" value="1"></property>
  <!-- 连接池的最大值 -->
  <property name="maxActive" value="500"></property>
  <!-- 最大空闲值 -->
  <property name="maxIdle" value="2"></property>
  <!-- 最小空闲值 -->
  <property name="minIdle" value="1"></property>
 </bean>
 2、配置事务
 配置事务需要在xml配置文件中引入用于声明事务的命名空间,事务的配置方式有两种:注解方式和基于XML配置方式。
 1>采用注解方式配置事务,精确控制,灵活,建议使用。
 <?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:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans     
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-2.5.xsd
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
            http://www.springframework.org/schema/tx     
            http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
  
   <!-- 指定属性文件存放路径 -->    
   <context:property-placeholder location="classpath:jdbc.properties"/>
  
     <!-- 配置数据源 -->
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
   <property name="driverClassName" value="${driverClassName}"></property>
   <property name="url" value="${url}"></property>
   <property name="username" value="${username}"></property>
   <property name="password" value="${password}"></property>
   <!-- 连接池启动时的初始值 -->
   <property name="initialSize" value="${initialSize}"></property>
   <!-- 连接池的最大值 -->
   <property name="maxActive" value="${maxActive}"></property>
   <!-- 最大空闲值 -->
   <property name="maxIdle" value="${maxIdle}"></property>
   <!-- 最小空闲值 -->
   <property name="minIdle" value="${minIdle}"></property>
  </bean>
  
  <!-- 声明事务管理器 -->
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"></property>
  </bean>
  
  <!-- 注解方式配置事务 -->
  <tx:annotation-driven transaction-manager="txManager"/>
  
  <bean id="personService" class="cn.itcast.bean.impl.PersonServiceBean">
   <property name="dataSource" ref="dataSource"></property>
  </bean>
 </beans>
 PersonServiceBean代码:
 @Transactional
 public class PersonServiceBean implements PersonService {
  // private DataSource dataSource;
  private JdbcTemplate jdbcTemplate;
 
  public void setDataSource(DataSource dataSource) {
   this.jdbcTemplate = new JdbcTemplate(dataSource);
  }
 
  @Transactional(noRollbackFor=RuntimeException.class)
  public void delete(Integer personid) {
   jdbcTemplate
     .update("delete from person where id=?", new Object[] { personid },
       new int[] { java.sql.Types.INTEGER });
   throw new RuntimeException("运行期异常");
  }
 
  @Transactional(propagation=Propagation.NOT_SUPPORTED)
  public Person getPerson(Integer personid) {
   return (Person)jdbcTemplate.queryForObject("select * from person where id=?",
     new Object[] { personid },
     new int[] { java.sql.Types.INTEGER }, new PersonRowMapper());
  }
 
  public List<Person> getPersons() {
   return ( List<Person>)jdbcTemplate.query("select * from person",
     new PersonRowMapper());
  }
 
  public void save(Person person) {
   jdbcTemplate.update("insert into person(name) values(?)",
     new Object[] { person.getName() },
     new int[] { java.sql.Types.VARCHAR });
  }
 
  public void update(Person person) {
   jdbcTemplate.update("update person set name=? where id=?",
     new Object[] { person.getName(), person.getId() }, new int[] {
       java.sql.Types.VARCHAR, java.sql.Types.INTEGER });
  }
 }
 2>采用基于XML方式配置事务:
 <!-- xml方式配置事务 -->
 <aop:config>
  <aop:pointcut expression="execution(* cn.itcast.service..*.*(..))" id="transactionPointcut"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointcut"/>
 </aop:config>
 <tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
   <tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/>
   <tx:method name="*"/>
  </tx:attributes>
 </tx:advice>

二十四、事务传播属性
 REQUIRED:业务方法需要在一个事物中运行,如果方法运行时,已经处在一个事物中,那么假如该事物,否则为自己创建一个新的事务。
 NOT_SUPPORTED:声明方法不需要事务,如果方法没关联到一个事物,容器不会为它开启事务,如果方法在一个事物中被调用,该事物会被挂起,在方法调用结束后,原先的事务便会恢复执行。
 REQUIRESNEW:不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事物中,则原有事务会被挂起,新的事务会被创建,知道方法执行结束,新事务才算结束,原有的事务才会会发执行。
 MANDATORY:指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务,如果业务方法在没有事务的环境下调用,容器就会抛出异常。
 SUPPORTS:如果业务方法在某个事务范围内被调用,则方法成为事务的一部分,如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。
 Never:执行业务方法绝对不能在事务范围内执行,如果业务方法在某个事务中执行,容器会抛出异常,只有业务方法没有关联到任何事务,才能正常执行。
 NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按required属性执行,它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点,内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器有效。
 
二十五、spring2.5+hibernate3.3+struts1.3整合开发
 1、导入ssh框架包:
 1>hibernate核心安装包下的:
 hibernate3.jar
 lib\required\*.jar
 lib\option\ehcache-1.2.3.jar
 hibernate注解安装包下的:
 lib\test\slf4j-log4j12.jar
 2>spring安装包下的:
 dist\spring.jar
 dist\modules\spring-webmvc-struts.jar
 lib\jakarta-commons\commons-logging.jar、commons-dbcp.jar、commmons-pool.jar
 lib\aspectj\aspectjweaver.jar、aspectjrt.jar
 lib\cglib\cglib-nodep-2.1.3.jar
 lib\j2ee\common-annotations.jar
 lib\log4j\log4j-1.2.15.jar
 3>struts安装包下:
 所有jar包,建议把jstl-1.0.2.jar和standard-1.0.2.jar更换为1.1版本。spring中已经存在一个anltr-2.7.6.jar,所以把struts中的anltr-2.7.2.jar删除,避免jar包冲突。
 4>数据库驱动jar包
 mysql-connector-java-5.1.18-bin
 
 2、spring配置文件beans.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:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans     
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-2.5.xsd
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
            http://www.springframework.org/schema/tx     
            http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
           
     <!-- 打开注解方式 -->      
     <context:annotation-config></context:annotation-config>
       
     <!-- 指定属性文件存放路径 -->
     <context:property-placeholder location="classpath:jdbc.properties"/>
    
     <!-- 配置数据源 -->
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
   <property name="driverClassName" value="${driverClassName}"></property>
   <property name="url" value="${url}"></property>
   <property name="username" value="${username}"></property>
   <property name="password" value="${password}"></property>
   <!-- 连接池启动时的初始值 -->
   <property name="initialSize" value="${initialSize}"></property>
   <!-- 连接池的最大值 -->
   <property name="maxActive" value="${maxActive}"></property>
   <!-- 最大空闲值 -->
   <property name="maxIdle" value="${maxIdle}"></property>
   <!-- 最小空闲值 -->
   <property name="minIdle" value="${minIdle}"></property>
  </bean>
  
  <!-- 配置hibernate二级缓存 -->
  <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
   <property name="dataSource" ref="dataSource"></property>
   <property name="mappingResources">
    <list>
     <value>cn/itcast/bean/Person.hbm.xml</value>
    </list>
   </property>
   <property name="hibernateProperties">
    <value>
     hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
     hibernate.hbm2ddl.auto=update
     hibernate.show_sql=false
     hibernate.format_sql=false
    </value>
   </property>
  </bean>
  
  <!-- 配置事务管理器 -->
  <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
   <property name="sessionFactory" ref="sessionFactory"></property>
  </bean>
  
  <!-- 配置注解方式声明事务 -->
  <tx:annotation-driven transaction-manager="txManager"/>
  
  <!-- 配置业务bean -->
  <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean>
 </beans>
 
 3、编写Person.java和Person.hbm.xml配置文件:
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 <hibernate-mapping package="cn.itcast.bean">
  <class name="Person" table="person">
   <id name="id">
    <generator class="native"></generator>
   </id>
   <property name="name" length="10" not-null="true"></property>
  </class>
 </hibernate-mapping>
 
 4、编写PersonServiceBean代码,抽取PersonService接口:
 @Transactional
 public class PersonServiceBean implements PersonService {
  @Resource
  private SessionFactory sessionFactory;
 
  public void save(Person person) {
   // 获取容器中被管理的session
   sessionFactory.getCurrentSession().persist(person);
  }
 
  public void update(Person person) {
   sessionFactory.getCurrentSession().merge(person);
  }
 
  @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
  public Person getPerson(Integer personid) {
   return (Person) sessionFactory.getCurrentSession().get(Person.class,
     personid);
  }
 
  public void delete(Integer personid) {
   sessionFactory.getCurrentSession()
     .delete(
       sessionFactory.getCurrentSession().load(Person.class,
         personid));
  }
  
  @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
  public List<Person> getPersons() {
   return sessionFactory.getCurrentSession().createQuery("from Person")
     .list();
  }
 }
 
 5、单元测试hibernate和spring整合:
 public class PersonServiceTest {
  private static PersonService personService = null;
  
  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
   ApplicationContext  ctx = new ClassPathXmlApplicationContext("beans.xml");
   personService = (PersonService) ctx.getBean("personService");
  }
 
  @Test
  public void testSave() {
   personService.save(new Person("ssh"));
  }
 
  @Test
  public void testUpdate() {
   Person person = personService.getPerson(1);
   person.setName("张三");
   personService.update(person);
  }
 
  @Test
  public void testGetPerson() {
   Person person = personService.getPerson(1);
   System.out.println(person.getName());
  }
 
  @Test
  public void testDelete() {
   personService.delete(1);
  }
 
  @Test
  public void testGetPersons() {
   List<Person> persons = personService.getPersons();
   for(Person person : persons)
   {
    System.out.println(person.getId()+":"+person.getName());
   }
  }
 }
 6、如果action没有交给spring管理,可通过如下语句获取spring容器实例:
 WebApplicationContext ctx = WebApplicationContextUtils
    .getWebApplicationContext(this.getServlet().getServletContext());
 把action交给spring管理后,可以使用依赖注入在action中注入业务层bean,确保action的path属性值与bean的名称相同。
 struts配置:
 <action path="/person/list"></action>
 spring配置:
 <bean name="/person/list" class="cn.itcast.web.action.PersonAction"></bean>
 在struts配置文件中添加进spring的请求控制器。该请求控制器会根据action的path属性到spring容器中寻找和该属性值同名的bean,如果找到则使用该bean处理用户请求。
 <controller>
  <set-property property="processorClass" value="org.springframework.web.struts.DelegatingRequestProcessor" />
 </controller>
 
二十六、hibernate二级缓存配置
 hibernate二级缓存配置文件名称为ehcache.xml,存放在类路径下,配置如下:
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
  diskStore 缓存对象存放在硬盘上的位置
  defaultCache 节点为默认的缓存策略
  maxElementsInMemory 内存中最大允许存在的对象数量
  eternal 设置缓存中的对象是否永远不过期
  overflowToDisk 把溢出的对象存放到硬盘上
  timeToIdleSeconds 指定缓存对象空闲多长时间就过期,过期的对象会被清除掉
  timeToLiveSeconds 指定缓存对象总的存活时间
  diskPersistent 当jvm结束是否持久化对象
  diskExpiryThreadIntervalSecond 指定专门用于清除过期对象的监听线程的轮询时间
  -->
 <ehcache>
  <diskStore path="D:\cache"/>
  <defaultCache maxElementsInMemory="1000" eternal="false" overflowToDisk="true"
  timeToIdleSeconds="120"
  timeToLiveSeconds="180"
  diskPersistent="false"
  diskExpiryThreadIntervalSeconds="60"/>
  
 <cache name="cn.itcast.bean.Person" maxElementsInMemory="100" eternal="false" overflowToDisk="true"
  timeToIdleSeconds="120"
  timeToLiveSeconds="180"
  diskPersistent="false"
  diskExpiryThreadIntervalSeconds="60"/>
 </ehcache>
 测试二级缓存:从数据库中取出一条记录,关闭数据库之后,依然能读取出正确结果。
 public void testGetPerson() {
  Person person = personService.getPerson(3);
  System.out.println(person.getName());
  try {
   System.out.println("请关闭数据库");
   Thread.sleep(15000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println("第二次开始获取");
  Person person1 = personService.getPerson(3);
  System.out.println(person1.getName());
 }
 
二十七、ssh整合开发常见问题解决
 1、使用spring解决struts1.3乱码问题
 <filter>
  <filter-name>encoding</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <init-param>
   <param-name>encoding</param-name>
   <param-value>UTF-8</param-value>
  </init-param>
 </filter>
 <filter-mapping>
  <filter-name>encoding</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
 2、使用spring解决hibernate因session关闭导致的延迟加载异常问题
 <filter>
  <filter-name>openSessionInViewFilter</filter-name>
  <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>openSessionInViewFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
 
二十八、spring2.5+hibernate3.3+struts2整合开发
 和整合struts1差不多,区别在于:
 1、导入struts2的jar包:
 struts2的lib目录下所有不带-plugin结尾的jar文件,除了struts2-spring-plugin-2.0.11.1.jar。
 2、web.xml配置文件:
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:beans.xml</param-value>
 </context-param>
 
 <!-- 对spring容器进行实例化 -->
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 
 <!-- 配置struts2过滤器 -->
 <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>
 3、struts.xml配置文件:
 <!-- 指定action对象由spring容器创建 -->
  <constant name="struts.objectFactory" value="spring"/>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值