spring 总结

来源:互联网 发布:vmware12 mac os补丁 编辑:程序博客网 时间:2024/06/05 23:39
1.spring是什么?
   是一个开源的控制反转和面向切面的容器框架
2.控制反转就是应用本身不负责依赖对象的创建和维护,
依赖对象的创建和维护是由外部容器负责的
 这样控制权就由应用转移到了外部容器,
控制权的转移就是所谓反转
3.依赖注入:在运行期间,由外部容器动态的将依赖对象
注入到组件中
public class PersonServiceBean{
private PersonDao personDao;
//通过构造器参数,让容器把创建好的依赖对象注入进
PersonServiceBean,当然也可以使用setter方法进行注入
pubic PersonServiceBean(PersonDao personDao){
this.personDao=personDao;
}
pubic void save(Person person){
personDao.save(person);
}
}
4.使用spring时候,不需要手动控制事务
   例如:hibernate需要开启事务和提交事务
         jdbc需要设置手动提交事务和提交事务
  如果使用spring,我们也不需要处理复杂的事务传播行为
5.spring用到的jar包:
  dist/spring.jar
  lib/jakarta-commons/commons-logging.jar
  如果使用了切面编程,还需要
  lib/aspectj/aspectjweaver.jar和aspectjrt.jar
  lib/cglib/cglib-nodep-2.1_3.jar
  如果使用了JSR-250中的注解,如@Resource/@PostConstruct/@PreDestory还需要
  lib/j2ee/common-annotations.jar
6.实例化spring容器的常用两种方式:
 一.在类路径下寻找配置文件来实例化容器
    ApplicationContext ctx=new ClassPathXmlApplicationContext(new String[]{"beans.xml"})
 二.在文件系统路径下寻找配置文件来实例化容器
   ApplicationContext ctx=new FileSystemXmlApplicationContext(new String[]{"d:\\beans.xml"})
  spring配置文件可以有多个,通过String数组传入
7.配置文件中:
  bean中的id和name属性类似 id中不能有特殊字符,name中可以有特殊字符
  class属性中指定的是类而不是接口
  获取bean的方法:
       ApplicationContext ctx=new ClassPathXmlApplicationContext(new String[]{"beans.xml"})
       PersonService personService=(PersonService)ctx.getBean("配置文件中设置的name或者id的名字");
8.spring管理bean的原理
//解析配置文件 兼容ref和基本数据类型 不兼容内部bean
 public class ItcastClassPathXMLApplicationContext{
 
 private List<BeanDefinition> beanDefines=new ArrayList<BeanDedinition>();
 
 private Map<String,Object> sigletons=new HashMap<String,Object>();
 public ItcastClassPathXMLApplicationContext(String filename){
 this.readXML(finlname);
 this.instanceBeans();
 this.annotationInject();
 this.injectObject();
}
 //注解处理
public void annotationInject(){
for(String beanName:sigletons.keySet()){
 Object bean=sigletons.get(beanName);
 if(bean!=NULL){
  try{
    PropertyDescriptor[] ps=Introspector.getBeanInfo(bean.getClass().getPropertyDescriptors());
    for(PropertyDescriptor properdesc:ps){
      Method setter=properdesc.getWritMethod();
      if(setter!=null&&!setter.isAnnotationPresent(ItcastResource.class))){
        ItcastResource resource=setter.getAnnotation(ItcastResource.class);
        Object value=null;
        if(resource.name()!=null&&!"".equals(resource.name())){
          value=digletons.get(resouce.name());
        }else{
         value=sigletons.get(properdesc.getName());
         if(value==null){
           for(String key:sigletons.keySet()){
              if(properdesc.getPropertyType().isAssignableForm(sigletons.get(key).getClass())){
                 value=sigletons.get(key);
                 break;
              }
           }
         }
        }
        setter.setAccessible(true);
        setter.ivoke(bean,value);
      }
   }
Field[] fields=bean.getClass().getDeclaredFileds();
for(Field field:fields){
if(field.isAnnotationPresent(ItcastResource.class))){
        ItcastResource resource=setter.getAnnotation(ItcastResource.class);
        Object value=null;
        if(resource.name()!=null&&!"".equals(resource.name())){
          value=digletons.get(resouce.name());
        }else{
         value=sigletons.get(field.getName());
         if(value==null){
           for(String key:sigletons.keySet()){
              if(field.getType().isAssignableForm(sigletons.get(key).getClass())){
                 value=sigletons.get(key);
                 break;
              }
           }
         }
        }
        field.setAccessible(true);//允许访问private字段
        field.set(bean,value);
      }
}
  }catch(){}
 }
}
}
//为bean对象的属性注入值
public void injectObject(){
for(BeanDefinition beanDefinition:beanDefines){
 Object bean=Sigletons.get(beanDefinition.getId());
  if(bean!=null){
   try{
      //返回所有的属性描述
      PropertyDescriptor[] ps=Introspector.getBeanInfo(bean.getClass().getPropertyDescriptors());
      for(PropertyDefinition propertyDefinition:beanDefinition.getPropertys()){
         for(PropertyDescriptor properdesc:ps){
             if(propertyDefinition.getName().equals(propertydesc.getName())){
                 Method setter=properdesc.getWriterMethod();//获取属性的setter方法
                 if(setter!=null){
 Object value=nul;
                  if(prpertyDefinition.getRef()!=null&&!"".equals(propertyDefinition.getRef().trim())){
                  value=sigletons.get(propertyDefinition.getRef());
                   
                }else{
                   //加入apache的commons-beanutils工具包
                   value=ConvertUtils.covert(propertyDefinition.getValue(),properdesc.getPropertyType());
 
                }
setter.setAccessible(true);
                   setter.invoke(bean,value);//把引用对象注入到属性
                 }
                break;
             }
         }
      }
   }
 }catch(Exception e){
  e.printStackTrace();
 }
}
}
//完成bean的实例化
public void instanceBeans(){
for(BeanDefinition beanDefinition:beanDefines)
   try{
      if(beanDefinition.getClassName()!=null&&!"".equals(beanDefinition.getClassName().trim()))
          sigletons.put(beanDefinition.getId(),Class.forName(beanDefinition.getClassName()).newInstance());
   }catch(Exception e){
   e.printStackTrace();
   }
}
//读取xml配置文件
public void readXML(String filename){
 SAXReader saxReader=new SAXReader();
 Document document=null;
 try{
   URL xmlpath=this.getClass().getClassLoader().getRsource(filename);
   document=saxReader.read(xmlpath);
   Map<String,String> nsMap=new HashMap<String,String>();
   nsMap.put("ns","http://www.springframework.org/schema/beans");//加入命名空间
   XPath xsub=document.createXPath("//ns:beans/ns:bean");//创建beans/bean查询路径;
   xsub.setNamespaceURIs(nsMap);//设置命名空间
  //获取文档下的所有bean节点
   List<Element> beans=xsub.selectNodes(document);
  for(Element element:beans){
     String id=element.attributeValue("id");
     String clazz=element.attributeValue("class");
     BeanDefinition beanDefine=new BeanDefinition(id,clazz);
     XPath propertysub=element.createXPath("ns:property");
     propertysub.setNamespaceURIs(nsMap);//设置命名空间
     List<Element> propertys=propertysub.selectNodes(element);
    for(Element property:propertys){
      String propertyName=property.attributeValue("name");
      String propertyRef=property.atrriuteValue("ref"); 
      String propertyValue=property.atrriuteValue("value"); 
// System.out.println(propertyName+"="+propertyRef);
      PropertyDefinition propertyDefinition=new PropertyDefinition(propertyName,propertyRef,propertyValue);
     beanDefine.getPropertys().add(propertyDefinition);
   }
    beanDefines.add(beanDefine);     
  }
}catch(Exception e){
  e.printStackTrace();
}
}
//获取bean实例
public Object getBean(String beanName){
return this.sigletons.get(beanName);
}
}
//bean的配置
public class BeanDefinition{
private String id;
private String className;
private List<AttributeDefinition> propertys=new ArrayList<AttributeDefinition>();  
public BeanDefinition(String id,String className){
this.id=id;
this.className=className;
}
//属性的getter和setter方法
略......
}
//bean的属性
public class PopertyDefition{
private String name;
private String ref;
private String value;
public PropertyDefinition(String name,String ref,String value){
this.name=name;
this.ref=ref;
this.value=value;
}
//属性的getter和setter方法
略......
}
9.三种实例化bean的方式:
  1.使用构造器实例化
   <bean id="orderService" class="cn.itcast.OrderServiceBean"/>
  2.使用静态工厂方法实例化
 <bean id="personService" class="cn.itcast.service.OrderFactory" factory-method="createOrder"/>
    public class OrderFactory{
     public static OrderServiceBean createrOrder(){
      return new OrderServiceBean();
     }
  }
  3.使用实例工厂方法实例化
 <bean id="personServiceFactory" class="cn.itcast.service.OrderFactory"/>
 <bean id="personService" factory-bean="personServiceFactory"  factory-method="createOrder"/>
 public class OrderFactory{
   public OrderServiceBean createOrder(){
     return new OrderServiceBean();
  }
 }
10.bean的作用域:
  PersonService personService1=(PersonService)ctx.getBean("配置文件中设置的name或者id的名字");
  PersonService personService2=(PersonService)ctx.getBean("配置文件中设置的name或者id的名字");
  那么怎样判断personService1和personService2是不是一个同一个对象??
  看看System.out.println(personService1==personService2)输出结果是true还是false;
  输出为true,可知我们使用的都是同一个对象。那么这样让他每次获取
  都是一个新的对象呢??????
  bean的作用域:
  singleton
      在每个spring IOC容器中一个bean定义只有一个对象实例。
  默认情况下会在容器启动时候初始化bean,但是我们可以指定bean节点的lazy-init="true"来延迟初始化
  bean,这时候只有第一次获取bean才会初始化bean。如:
  <bean id="" class="" lazy-init="true"/>
  如果想对所有的bean都采用延迟初始化,可以在根节点beans设置default-lazy-init="true"
  prototype
     每次从容器获取bean都是新的对象(每次调用getBean()方法)
  request
  session
  global session
  指定作用域:<bean id="" class="" scope=""/>
11.bean的生命周期:
   默认情况下是singleton,容器启动时候就实例化bean
   prototype是在调用getBean方法时候实例化bean
  
 如果我们让bean懒加载的话,那么想对bean进行初始化,怎么办呢?
public class PersonServiceBean implements PersonService{
pubic void init(){
.....
}
pubic void destory(){
.....
}
}   
<bean id="" class="" lazy-init="true" init-method="init" destory-method="destory"/>
执行ctx.close()时候会执行destory方法
11.注入依赖对象
  基本类型注入:
  <bean id="" class="">
     //构造函数注入
     <constructor-arg index="0" type="java.lang.String" value="xx"/>
    //属性setter方法注入
    <property name="name" value="xx"/>  
  </bean>
 注入其他bean
 方式一:
   <bean id="orderDao" class=""/>
   <bean id="" class="">
      <property name="orderDao" ref="orderDao"/>
   </bean>
方式二:(使用内部bean,但是该bean不能被其他bean使用)
  <bean id="" class="">
     <property name="orderDao">
        <bean class=""/>
     </property>
 </bean>
12.  注入集合类型的对象
set类型的集合
<bean id="" class="">
     <property name="sets">
        <set>
           <value>第一个<value/>
           <value>第一个<value/>
        </set>
     </property>
</bean>
list集合
<bean id="" class="">
     <property name="lists">
        <list>
           <value>第一个<value/>
           <value>第一个<value/>
        </list>
     </property>
</bean>
properties类型
<bean id="" class="">
     <property name="properties">
        <props>
           <prop key="key1">value1</prop>
           <prop key="key2">value2</prop>
        </props>
     </property>
</bean>
map类型
<bean id="" class="">
     <property name="maps">
        <map>
           <entry key="key-1" value="vlaue-1"/>
           <entry key="key-1" value="vlaue-1"/>
        </map>
     </property>
</bean>
13.通过构造器注入
 <bean id="" class=""> 
//注入基本类型   
     <constructor-arg index="0" type="java.lang.String" value="xx"/>
//注入引用类型
<constructor-arg index="1" type="cn.wuxiaoxiao.PersonDao" ref="personDao"/>  
  </bean>
14.使用注解方式注入
如果我们使用注解的方式就必须加入以下的命名空间
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframwork.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
<context:annotation-config/>
这个配置隐式的注册了多个对注释进行解析处理的处理器:AutowireAnnotationBeanPostProcessor,
CommonAnnotionBeanPostProcessor
PersistenceAnnotationBeanPostProcessor,
RequireAnnotationBeanPostProcesstor
注:@Resource注解在spring安装目录的lib\j2ee\common-annotations.jar
建议使用@Resource,他是java中的而不是spring中的
在java代码中使用@Autowire或者@Resource注解方式进行装配,这两个注解的区别是:
 @Autowire默认按照类型装配,@Resource默认按照名称装配,当找不到与名称匹配的bean才会按照类型装配
 @Autowire
 private PersonDao personDao;//用于字段上
 @Autowire
 public void setOrderDao(OrderDao orderDao){//用于属性的settter方法上
  this.orderDao=orderDao;
 }
@Autowire注解是按照类型装配依赖对象,默认情况下它要求依赖对象必须存在如果允许为null,可以设置它required属性为false,如果我们想使用按照名称装配,可以结合@Qualifie注解一起使用 如下:
 @Autowire @Qualifie("personDaoBean")
 private PersonDao personDao;
@Resource默认按照名称装配,可以通过name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象
@Resource(name="personDaoBean")
private PersonDao personDao;//用于字段上
注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖的对象时候,会回退到按照类型装配,但一旦指定了name属性,就只能按照名称装配了
15.编码解析@Resource原理
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD,ElementType.METHOD)
public @interfalce ItcastResource{
public String name() default "";
}
注解没有实现任何功能,还要有解析程序
16.
注入依赖对象分为手工注入和自动注入
以上是手工注入
下面说说自动注入:不推荐使用
<bean id="" class="" autowroe="byType"/>
autowire属性取值如下:
byType:按照类型装配,可以根据属性的类型,在容器中寻找跟该类型匹配的bean,如果发现多个,那么抛出异常,如果找不到 即属性值为null
byName:按照名称匹配,可以根据属性的名称 在容器中寻找跟该属性名相同的bean,如果没有找到,属性值为null
construtor与byType类似,不同之处在于他应用于构造器参数,如果在容器中没有找到与构造器参数中类型一致的bean,那么抛出异常
autodetect:通过bean类的自省机制(introspection)来决定使用construtor还是byType方式进行自动装配,如果发现默认的构造器,那么使用byType方式
17.通过在classpath自动扫描方式把组件纳入spring容器中管理
  前面我们是使用xml的bean定义来配置组件,spring2.5为我们引入了组件自动扫描机制,他可以在类路径下寻找标注了@Component @Service @Controller @Respository注解的类,并把这些类纳入进spring容器中管理。他的作用和在xml文件中使用bean节点的配置组件是一样的,要使用自动扫描机制,我们需要打开一下配置信息:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframwork.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
<context:component-scan base-package="cn.itcast"/>
其中base-package为需要扫描的包(子包)
@Service用于标注业务层组件,@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件。而@Component泛指组件,当组件不好归类的时候,我们使用这个进行注解
注解放在类上 不是接口
@Service默认bean的名称是类名,可以这样指定@Service("peronService")
@Service("peronService") @Scope("prototype")指定bean的作用域
public class PersonServiceBean implements PersonService{
//指定初始化函数
@PostConstruct
public void init(){}
//指定销毁函数
@PreDestory
public void destory(){}

}
18.
AOP----代理对象
下面举个例子:没有使用第三方的aop框架
1.拦截所有业务方法
2.判断用户是否有权限,有权限就允许他执行业务方法,没有权限不允许执行业务方法(是否有权限是根据user是否为null作为判断依据)
客户端在调用目标对象之前先经过代理对象,代理对象实现了目标对象的所有接口,所以通过代理对象的调用能够把方法的调用委派给目标对象,也就是好像代理对象调用了目标对象的方法。
代理有两种实现方案:静态代理和动态代理  动态代理最为常用
java中有Propxy类,来为目标对象动态创建代理对象,前提是目标对象必须实现接口
public interface PersonService{
.....
}
public class PersonServiceBean implements PersonService{
private String user=null;
public PersonServiceBean(String user){
this.user=user;
}
......
}
public class JDKProxyFactory implements InvocationHandler{
private Object targetObject;
public Object createProxyIntance(Object targetObject){
this.targetObject=targetObject;
//代理对象 代理对象的所有接口 InvocationHandler是回调(就是拦截方法时候会触发哪个类上面的方法),当对代理对象的业务方法进行调用的时候,那么这个调用操作会被this这个对象拦截,那么会调用下面的invoke方法,invoke中再把方法委派给目标对象
return Proxy.newProxyInstance(this.targetIObject.getClass().getClassLoader(),this.targetObject.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy,Method method,Object[] args) throw Throwable{
 PersonServiceBean bean=(PersonServiceBean)this.targetObject;
 Object result=null;
 if(bean.getUser()!=null){
   //.....advice()//前置通知
   try{
   result=method.invoke(targetObject,args);
   //.....afteradvice()//后置通知
   }catch(){
     //......exceptionadvice()//例外通知
   } finally{
    //....finallyadvice();//最终通知
   }
}
 return result;
}
}
测试:
JDKProxyFactory factory=new JDKProxyFactory();
PersonService service=(PersonService)factory.createProxyInstance(new PersonServiceBean("dfd"));
service.save("sss");
如果目标对象没有实现接口,那么不能用Proxy来创建代理对象了,那么我们可以使用第三方框架cglib类,他在spring框架下面
public class CGlibProxyFactory implements MethodInterceptor{
private Object targetObject;
public Object createProxyIntance(Object targetObject){
this.targetObject=targetObject;
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(this.targetObject.getClass());//cglib创建代理对象是通过继承目标对象并且覆盖所有的非final修饰的方法
enhancer.setCallback(this);//回调
return enhancer.create();
}
public Object intercept(Object proxy,Method method,Object[] args,MethodProxy methodProxy) throw Throwable{
 PersonServiceBean bean=(PersonServiceBean)this.targetObject;
 Object result=null;
 if(bean.getUser()!=null){
   result=methodProxy.invoke(targetObject,args);
 }
 return result;
}
AOP中的概念:
略....
19.使用spring进行aop编程
使用注解方式:
首先进行aop编程,首先我们要在spring的配置文件中引入aop命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
<aop:aspectj-autoproxy>
使用的接口和类和上面的PersonService一样
/**
*切面
*/
@Aspect
public class MyInterceptor{
//切入点  定义要进行拦截的方法
execution (   *        cn.itcast.service  ..      *.      *  (      ..      ))
执行       返回类型        包             子包   类     方法    方法的参数(随意,有也行,没有也行)
//当执行PersonServiceBean中的所有方法时候 都会进行拦截
@Pointcut(“execution(* cn.itcast.serviceimpl.PersonServiceBean.*(..))”)
private void anyMethod(){}//声明一个切入点
@Before("anyMethod()")//前置通知
//如果前置通知想得到用户输入参数,这样写
@Before("anyMethod() && args(name)")并且在前置通知的函数中加上参数
那么前置通知只会拦截含有一个参数的方法
public void doAccessCheck(String name){
  .......
}
@AfterReturning("anyMethod()")//后置通知
//如果获得返回结果,那么这样写:
@AfterReturning(pointcut="anyMethod()",returning="result")并且后置通知的方法中加上参数
public void doAccessCheck(String result){
  .......
}
@After("anyMethod()")//最终通知
public void doAccessCheck(){
  .......
}
@AfterThrow("anyMethod()")//异常通知
//得到例外
@AfterThrow(pointcut="anyMethod()",throwing="e")并且例外通知的方法中加上参数
public void doAccessCheck(Exception e){
  .......
}
@Around("anyMethod()")//环绕通知(先执行前置通知--aaa--执行方法---后置通知--最终通知--bbb)有了环绕通知,其他通知都可以不写
public Object doBasicProfiling(ProceeingJoinPoint pjp) throw Throwable{
//if(){//判断用户是否有权限
System.out.println("aaa");
Object result=pjp.proceed();
System.out.println("bbb");
//}
return result;
}
}
配置文件:
<bean id="myInterceptor" class="cn.itcast.service.MyInterceptor"/>
客户端:
  ......
上面是基于注解的方式,下面是基于xml方式:
<bean id="orderservice" class="cn.itcast.service.OrderServiceBean"/>
<bean id="log" class="cn.itcast.service.MyInterceptor">//切面的配置
<aop:config>
 <aop:aspect id="myaop" ref="log">
   <aop:poingcut id="mycut" expression="execution(* cn.itcast.service.*.*(..))"/>
   <aop:before pointcut-ref="mycut" method="doAccessCheck"/>
   <aop:after-returning pointcut-ref="mycut" method="doAccessCheck"/>
   <aop:after-throwing pointcut-ref="mycut" method="doAccessCheck"/>
   <aop:after pointcut-ref="mycut" method="doAccessCheck"/>
   <aop:around pointcut-ref="mycut" method="doAccessCheck"/>
 </aop:aspect>
</aop:config>
20.Spring+JDBC组合开发
步骤:
1.配置数据源 如:
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destory-method="close">
    <property name="driverClassName" value="org.git.mm.mysql.Driver"/>
    <property name="url" value="jdbc:msyql://localhost:3306/itcast?userUnicode=true&amp;characterEncoding=UTF-8"/>  
    <property name="username" value="root"/>
    <property name="password" value=""/>
    <!--连接池启动时的初始值-->
     <property name="initialSize" value="1"/> 
    <!--连接池的最大值-->
     <property name="maxActive" value="200"/> 
    <!--最大空闲值,当经过一个高峰时间后,连接池可以慢慢将已经用不到得连接慢慢释放一部分,一直减少到maxIdle为止-->
     <property name="maxIdle" value="2"/> 
    <!--最小空闲值,当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请-->
     <property name="minIdle" value="1"/>    
    ..........
  </bean>
2.配置事务,配置事务时,需要在配置文件中引入用于声明事务的tx命名空间,事务的配置有两种:注解方式和xml配置方式
采用注解方式:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>
<!--采用@Transactional注解使用事务-->
<tx:annotation-driven transcation-manager="txManager"/>
在配置文件中打开命名空间:
xmls:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
下面举个例子:
pubic interface PersonService{}
public class PersonServiceBean implements PersonService{
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource){
this.jdbcTemplate=new JdbcTemplate(dataSource);
}
public void delete(Integer personid){
jdbcTemplate.update("delete from person where id=?",new Object[]{personid},new int[]{java.sql.Types.INTEGER});
}
public Person getPerson(Integer personid){
return (Person)jdbcTemplate.queryForObject("select * from person where is=?",new Object[]{personid},new int[]{java.sql,Types.INTEGER},new PersonRowMapper());
}
public void save(Person person){
jdbcTemplate.update("insert into person(name) value(?)",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});
}
pubic List<Person> getPersons(){
return (List<Person>)jdbcTemplate.query("select * from person",new PersonRowMapper());
}
}
public class PersonRowMapper implements RowMapper{
pblic Object mapRow(ResultSet rs,int index) throws SQLException{
 Person person=new Person(rs.getString("name"));
 person.setId(rs.getInt("id"));
 return person;
}
}
配置文件:
<bean id="personService" class="">
  <property name="dataSource" ref="dataSource"/>
</bean>
上面的没有使用spring事务,那么每条语句是在自己的事务中执行,
如:
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});
//第二条语句又开启了一个事务
return (List<Person>)jdbcTemplate.query("select * from person",new PersonRowMapper());
}
要打开事务,那么在业务bean上加上 如下:
@Transactional(告诉spring该bean在执行每个人方法前打开事务,执行方法后关闭事务,而不是根据每条语句就另外开启一个事务)
public class PersonServiceBean implements PersonService
 
1.事务传播属性:
  采用声明的事务管理:spring容器在默认情况下对于运行期例外(unchecked exception)会进行回滚,但是对于用户例外(check exception)不进行回滚
  那么怎么改变这样的规则:在方法上面通过:@Transactional(rollbackFor=Exception.class)这样的设置,可以让发生用户例外时候也能够回滚
  如果某个方法不需要事务:@Transacational(propagation=Propagation.NOT_SUPPORTED,readOnly=)
  事务传播属性:
  REQUIRED:业务方法需要在一个事务中运行,如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务,默认
  NOT_SUPPORTED:声明方法不需要事务,如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被声明,该事务会被挂起,在方法被调用后,原先的事                 务便会恢复执行
  REQUIRESNEW:属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务,如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法结               束,新事务才算结束,原先的事务才会恢复执行
  MANSATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务,如果业务方法没有在事务的环境下调用,容器就会抛出例外
  SUPPORTS:这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法为该事务的一部分,如果业务方法在事务范围外被调用,则方法在没有事务的环境下调用
  Never:指定业务方法绝对不能在事务范围内执行,如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行
  NESTED:如果一个活动的事务存在,则运行在 一个嵌套的事务中,如果没有活动的事务,则按照REQUIRED属性执行,他使用了一个单独的事务,这个事务拥有多个可以回滚的          保存点,内部事务的回滚不会对外部事务造成影响,他只对DataSourceTransacationManager事务管理器起效
其他的属性
  readOnly:只读事务,不能更新
  timeout:事务的超时时间
  isolation:事务的隔离级别(是有数据库决定的而不是spring容器)
    数据库系统提供了四种事务隔离级别:
      Read Uncommited:读未提交的数据(会出现脏读,不可重复读,幻读)
      Read Commited:读已经提交的数据(会出现不可重复读,幻读)
      Repeatable Read:可重复读(会出现幻读)
      Serializable:串行化
   脏读:一个事物读取另一个没有提交的更新数据
   不可重复读:在同一个事务中,多次读取同一数据返回的结果有所不同,换句话说:后续读取可以读到另一事务已提交的更新数据,相反,“可重复读”在同一个事务中多次读取数据时候,能够保证所读数据一样,也就是,后续读取不能读取到另一事务已经提交的更新数据
   幻读:一个事务可以读取到另一事务已提交的insert数据
2.spring+hibernate
像上面我们配置好了数据源,那么hibernate的session就有spring容器管理,我们配置sessionfactory:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
   <property name="dataSource" ref="dataSource"/>
   <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=update
              // hibernate.show+_sql=true
              // hibernate.format_sql=false
              //使用二级缓存 hibernate.cache.user_second_level_cache=true
              //使用查询缓存    hibernate.cache.use_query_cache=false
               //指定缓存产品的类      hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
          </value>
   </property>
</bean>
接着配置事务管理器:
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
   <property name="sessionFactory" ref="sessionFactory"/>
</bean>
采用注解的方式定义事务的声明:
<tx:annotation-driven transaction-manager="txManager"/>
Service类:
@Transactional
pulbic class PersonServiceBean{
@Resource private SessionFactory sessionFactory;
public vodi save(Person person){
sessionFactory.getCurrentSession().persist(person);
}
public void update(Person person){
sessionFactory.getCurrentSession().merge(person);//将游离状态的对象同步到数据库
}
//将读取的操作的事务关闭
@Transactional(propagat=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));
}
public List<Person> getPerson(){
return sessionFactory.getCurrentSession().createQuery("from Person").list();
}
}
hibernate二级缓存:
首先在spring的配置文件中如上面进行配值
然后在classpath下面配置ehcache.xml
使用spring解决hibernate因session关闭导致的延迟加载例外问题
<filter>
  <filter-name>OpenSessionInViewFilter</filter-name>
  <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mappeing>
  <filter-name>OpenSessionInView</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
spring集成JPA(hibernate实现)
在spring配置文件:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">  
   <property name="persistenceUnitName" value="itcast"/>   
</bean>
那么persistence.xml文件放在classpath下面的META-INF目录下面
接着配置事务管理器:
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
   <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
采用注解的方式定义事务的声明:
<tx:annotation-driven transaction-manager="txManager"/>
Service类:
@Transactional
pulbic class PersonServiceBean implements PersonService{
@PersistenceContext private EntityManager em;
public vodi save(Person person){
em.persist(person);
}
public void update(Person person){
em.merge(person);//将游离状态的对象同步到数据库
}
//将读取的操作的事务关闭
@Transactional(propagat=Propagation.NOT_SUPPORTED,readOnly=true)
public Person getPerson(Integer personid){
return (Person)em.find(Person.class,personid);
}
public void delete(Integer personid){
em.delete(em.getReference(Person.class,personid));
}
public List<Person> getPerson(){
return em.createQuery("select o from Person o").getResultList();
}
}

spring集成struts2:
使用到了struts2的lib目录下所有不带-plugin结尾的jar文件,但是除了struts2-spring-plugin-2.0.11.1.jar
首先实例化spring容器(在web.xml中添加):
//指定spring的配置文件,默认从web根目录寻找配置文件,我们可以通过spring提供的classpath:前缀指定从类路径下寻找
<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.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*<url-pattern>
</filter-mapping>
如果action没有交给spring容器管理时,我们通过下面语句获得spring容器实例
WebApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext(this.getServlet().getServletContext());
PersonService personService=(PersonService)ctx.getBean("personService");
request.setAttribute("persons",personService.getPerson());
return mapping.findForward("list");
如果我们把action交给spring管理后,我们可以使用依赖注入在action中注入业务层的bean,确保action的class属性和spring的id属性一样
1 0
原创粉丝点击