spring学习笔记

Day01:
 1:Spring(Rode Johoson)是什么:开源的,用来简化企业级开发的,分层的,轻量级的框架;(sourceforge.net|open-open.com开源网站);
         轻量级是相对于传统的(比如Jboss,weblogic),它占用的资源少,是一种非侵入式框架;
         
       框架:一个软件的半成品;
         
 2:为什么 要使用spring:a:对大量的企业级服务作了再次的封装(事务,安全,日志,消息,任务管理,邮件,通讯,数据访问)。
        a1:简化了API(提供了更方便的接口来使用企业级服务);  a2:处理很多细节问题(异常处理,资源的获取与释放);
        
       b:提供了一个轻量级的容器,支持IOC(控制反转|DI:依赖注入)和AOP(面向切面编程),通过IOC可以使得应用程序中的各个模块松散耦合在一起,
        方便维护与测试;通过AOP,可以为模块提供声明式的基础服务(事务,安全);
        
       c:spring是一个框架,支持企业级开发的各个方面:即可以使用spring全部功能,也可以只使用其部分功能;
        c1:对表示层:支持struts,jsf... 自身实现spring mvc;
        c2:对业务层:支持事务,安全|支持IOC,AOP|支持任务管理,消息服务,远程调用...支持实例池...
        c3:对持久层:支持hibernate/ibatis,支持JDBC
        c4:对动态语言:工作流等等第三方产品提供了集成
       
       d:是一个非侵入式的解决方案
       
 3:spring的组成:
 
Spring IoC内容:一:概念,分类
  1:什么是IOC:Inversion of Control控制反转又称依赖注入
   a:对象之间的依赖关系交给程序的外部(容器框架)
   b:容器在运行时,依据配置,动态地建立对象之间的依赖关系;
   
   IOC优点:a:模块之间的关系松散耦合;b:易测试
   
  2:分类(IOC的实现):a:基于set方法 b:基于构造器
  
  

  二:IOC的基本使用(基本装配)
   a:容器:分类:BeanFactory|ApplicationContext|Web 获得:配置文件(xml) ,实例化ClassPathXmlApplicationContext.getBean()获得一个对象
      
   装配方式:
    1:基于set方法:
        A:对于基本类型(8种+String)
        <property name="属性名">
         <value>值</value>
        </property> (自动做类型转换)
        <!-- id唯一  | 不允许出现“/”等特殊字符,可以使用以name来命名  |bean name="s1,s2,s3" -->
        <bean id="someBean"  class="ioc1.SomeBean" init-method="init" destroy-method="cleanup">
        // Bean类要求提供一个缺省构造器init()做一些初始化操作:获得资源|cleanup()在Bean被销毁之前,被调用,用业释放资源
         <property name="str1">
          <value>string1</value>
         </property>
         <property name="val1">
          <value>100</value>
         </property>
        </bean>
        ///
        <property name="str1" value="string1"/>
        
        ac.registerShutdownHook();后调用destroy-method方法
        B:对象类型
        <property name="属性名">
         a:<ref local="id(被注入的Bean的名称)"/>|只会在当前的配置文件中查找id
         b:<ref bean="id"/>|搜索所有已加载的配置文件<property name="ob" ref="otherBean"/><!-- ref bean -->
         c:嵌套被注入Bean的定义|被嵌套的Bean只能被所在的Bean使用
        </property> (自动做类型转换)
        
        c:集合类型
         
         List(a:可以注入基本类型的包装类,对象,集合类型|b:如果使用泛型只能注入对应类型|c:有序,允许重复元素),
                  <property name="listProperty">
                   <list>
                    <value>string1</value>
                    <value>string1</value>
                    <value>string3</value>
                   </list>
                  </property>
                  
         Set(a:可以注入基本类型的包装类,对象,集合类型|b:如果使用泛型只能注入对应类型|c:无序,不允许重复元素),
         
                  <property name="setProperty">
                   <set>
                    <value>string1</value>
                    <value>string1</value>
                    <value>string3</value>
                   </set>
                  </property>
                  
         Map,
                 <property name="mapProperty">
                  <map>
                   <entry key="key1">
                    <value>value1</value>
                   </entry>
                   
                   <!-- key是对象
                   <entry>
                    <key><ref bean=""/></key>
                    <value>value2</value>
                   </entry>
                   -->
                  </map>
                 </property>
          key:字符串,用key属性指定;key是对象,用key元素指定
          
         Properties:
                 <property name="props">
                  <props>
                   <prop key="key2">value2</prop>
                  </props>
                 </property>
     2:基于构造器方式
     <Constructor-arg>
      <value>,<ref>,<list>
        
   这两种方法比较:Constructor|属性比较多,可能会有过多的构造器|可能会产生循环依赖
    
   示例spring_ioc:ioc2包下:分散配置文件的方式
  
  三:IOC的高级使用(复杂装配)
   1:自动装配>提示:byName按属性,byType按属性类型,constructor按构造器中参数类型,autodetect([di'tekt]'发现,发觉)检查Beane有无缺省构造器,有byType,无Constructor
       缺点:易出错,配置文件不够清晰;
       使用场合:构建系统原型
      <bean id="otherBean" class="ioc5.OtherBean">
       <property name="val1" value="string1"></property>
      </bean>
       
      <bean id="someBean" class="ioc5.SomeBean" />
      
   2:工厂方式的装配:
       A:简单工厂step1:产品的创建过程封装 step2:使用spring,配置---》ioc6       
        <bean id="car" class="ioc6.CarFactory" factory-method="getCar"/><!-- 这个方法必须是一个静态方法 -->
        
       B:实例工厂---》ioc7
       
   3:Bean定义的继承《配置信息》
       A:有直接继承关系的
           <!-- abstract这个属性在客户端不能实例化了 -->
          <bean id="abstractStudent" class="ioc8.Student" abstract="true">
           <property name="classes" value="sd1009"/>
          </bean>
          
          <bean id="student1" parent="abstractStudent">
           <property name="name" value="LWSX"/>
           <property name="age" value="23"/>
          </bean>
          
       B:没有直接继承关系的---》ioc8
          <bean id="abstractBean" abstract="true">
           <property name="str1" value="string1"/>
          </bean>
          <bean id="someBean" class="ioc8.SomeBean" parent="abstractBean">
           <property name="val1" value="100"/>
          </bean>
       
       
       
       Bean的范围
       scope=singleton默认《一样的对象》
       prototype原型
       reguest:当Http请求到达,创建这个Bean,当请求结束 ,销毁
       session
       global-session(portlet)
  
  
  四:组件的生命周期
   Bean的生命周期:
     1:容器先读取配置文件
     2:调用BeanFactoryPostProcessor(Bean工厂的后处理Bean)对配置文件进行修正(可选)
     3:实例化
     4:装配
     5:回调方法:
      回调接口)
       5.1:ApplicationContextAware获得容器的引用
       
          @Override
          public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
           // 容器调用这个方法
           ac=arg0;
          }
       
       5.2:BeanPostProcessor(后处理Bean)经常用来扩展容器的功能:在对象初始化之前之后调用
         <!-- 注册后处理Bean:让容器知道其存在 -->
         <bean class="ioc10.EncryptBean"/>
         ---------------------------------------------------------------------------------
           @Override//Object:被处理的Bean
           public Object postProcessAfterInitialization(Object arg0, String arg1)
             throws BeansException {
            Field[] fields = arg0.getClass().getDeclaredFields();
            AccessibleObject.setAccessible(fields, true);
            try{
             for(int i=0;i<fields.length;i++){
              if(fields[i].getType().equals(java.lang.String.class)){
               String origVal=(String) fields[i].get(arg0);
               String encryptVal=origVal+" encrypted";
               fields[i].set(arg0, encryptVal);
              }
             }
            }catch(Exception e){
             e.printStackTrace();
            }
            return arg0;
           }

           @Override
           public Object postProcessBeforeInitialization(Object arg0, String arg1)
             throws BeansException {
            //什么也不做,不能返回空
            return arg0;
           }
         
       5.3:BeanFactoryPostProcessor(Bean工厂的后处理):在Bean实例化之前可以去修改Bean的配置
          Spring对其实现:
          
           a:分散配置文件:PropertyPlaceholderConfigure
              <!-- 读取资源文件 -->
              <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
               <property name="location" value="ioc10\\info.properties"/>
              </bean>
              
           b:设置属性编辑器:CustomEditorConfigurer
           属性编辑器的编程:
             A:写一个类,继承java.beans.PropertyEditorSupport(属性编辑器类)覆盖相应方法setAsText--setValue(addr);//设置回去
             
               <bean id="person" class="ioc11.Person">
                <property name="addr" value="beijing-dzslwsx"/>---->这里的地址不要用ref了用value
                <property name="birthday" value="1989-06-26"></property>
               </bean>
             
             B:设置属性编辑器
             ——————————————————————————————————————————
               <!-- 设置属性编辑器类 -->
               <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
                <property name="customEditors">
                 <map>
                  <entry key="ioc11.Address" value="ioc11.AddressEditor"/>
                  <entry key="java.util.Date" value="ioc11.DateEditor"/>
                 </map>
                </property>
               </bean>
             ——————————————————————————————————————————
               
               <!-- 设置属性编辑器类 -->
               <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
                <property name="customEditors">
                 <map>
                  <entry key="ioc11.Address">
                   <bean class="ioc11.AddressEditor"/>
                  </entry>
                  <entry key="java.util.Date">
                   <bean class="ioc11.DateEditor"/>
                  </entry>
                 </map>
                </property>
               </bean>
             数组默认已经存在了
             
     6:初始化:init-method="初始化的方法名"
     7:就绪
     8:销毁:destroy-method="方法名"
  
  五:事件处理机制
     优点:最低的耦合
     ApplicationListener接口
     step1:自定义事件类 继承抽象类ApplicationEvent
     step2:写一个监听器类 实现ApplicationListener
     step3:Bean调用ApplicationContext来发布事件
     示例:spring_ioc:ioc12包
     
      不满足条件发布这个事件ac.publishEvent(new RegisterEvent(this));
      --------------------
      自定义事件类
      public class RegisterEvent extends ApplicationEvent{
       public RegisterEvent(Object arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
       }
      }
      --------------------
      使用监听器处理事件
      public class RegisterListener implements ApplicationListener{
       public void onApplicationEvent(ApplicationEvent arg0) {
        // TODO Auto-generated method stub
        if(arg0 instanceof RegisterEvent){
         System.out.println("illegale age!");
        }
       }
      }
      --------------------
      配置文件
      <bean id="customerService" class="ioc12.CustomerService"/>
      <!-- 注册监听器 -->
      <bean class="ioc12.RegisterListener"/>
     
======================================================================================================================================================================
======================================================================================================================================================================  
     
Spring AOP:
 一:AOP思想,相关的概念,优点;
  1:什么是AOP?
    面向切面编程
    
    ★面向切面编程思想:将具体业务逻辑中的交叉业务逻辑(可以被共享,与具体业务无关)抽取出来,封装成切面(包含了交叉业务逻辑+位置),
         然后使用AOP容器将切面织入到目标对象(只封装具体业务逻辑);
         
  2:AOP相关概念:8
      α:切面┈┈泛指交叉业务逻辑;(Aspect)
      β:通知┈┈具体的交叉业务逻辑;(Advice)比如:事务处理通知(TransationAdvice)
      γ:连接点┈┈切面可以织入的位置;(方法,属性)(JoinPoint)
      δ:切入点┈┈通知可能织入到哪些目标对象哪些方法;(PointCut)
      ε:引入┈┈是一种特殊的通知,可以动态地为目标对象来添加新的属性和方法;(Introduction)
      ζ:目标对象┈┈(Target)|织入┈┈(weaving)|代理对象┈┈(proxy)
      
  3:AOP如何实现:
           ①静态织入:特殊的编译器,在编译阶段,将切面代码插入到目标对象的字形码当中。(性能好)代表:"AspectJ";
      ②动态织入:在运行阶段,通过动态代理机制,将切面代码插入到目标对象,生成一个代理对象;
      
       委托:可以为被委托类(目标类)提供“增值”服务!
       代理:特殊的委托,委托类与目标类实现相同的接口!
       
       静态代理|代理类与目标类一一对应
       动态代理|由系统依据目标对象以及需要提供的“增值”服务(InvocationHandler接口:制订“增值”如何织入到目标对象的规则);
         在运行时来自动生成一个代理对象;(Proxy:具体生成代理对象);
             public class LogInvocationHandler implements InvocationHandler{
              private Object target;
              
              public LogInvocationHandler(Object target) {
               this.target = target;
              }
              
              @Override
              public Object invoke(Object arg0, Method arg1, Object[] arg2)
                throws Throwable {
               //织入日志服务
               System.out.println(arg1.getName()+"execute at:"+new Date());
               Object rsObj=arg1.invoke(target, arg2);
               return rsObj;
              }

             }
             ------------------------------------------------------------------------
             ISomeService target = new SomeServiceImpl();
             //arg0:目标对象的ClassLoader|arg1:目标类所实现的接口|arg2:InvocationHander
             ISomeService proxy =(ISomeService)
                  Proxy.newProxyInstance(target.getClass().getClassLoader(),
                        target.getClass().getInterfaces(),
                        new LogInvocationHandler(target));
             System.out.println("proxy:"+proxy.getClass().getName());
             proxy.doSome();
             
    
 二:AOP的编程;
   1:spring AOP的基本原理(实现机制):
      采用动态代理来实现“织入”;
      ①:默认,采用JDK的Proxy来生成代理对象
      ②:如果目标类没有实现接口,采用cglib来生成代理对象(有限制:代理对象是目标类的子类,所以目标类不能是final类);
             cglib生成的代理对象性能较好|Proxy生成代理对象性能销差
             cglib生成代理类时间较长|Proxy生成代理类时间较短
   
   2:通知的使用(只给了交叉业务逻辑)
   
      ①:Before:前置通知,在目标方法执行之前执行;
         特点:a:不改变目标方法执行的结果|b:不能够阻止目标方法被执行|c:目标方法执行之前执行
         
         MethodBeforeAdvice接口
         
              before(Method method,
                Object[] args,
                Object target)
                throws Throwable
                
              这个接口为我们提供了获得目标方法,参数以及目标对象的机会,由于已经得到了方法参数,所以有机会使用运行时
              参数实现通知,然而,你不能改变这些值,也就是你不能替换参数对象,你无法改变这些对象,实现的时候要注意!
              
              MethodBeforeAdvice惟一能阻止目标方法被调用 的途径是抛出异常(或调用System.exit()),但是不希望这样做,
              抛出异常的结果依赖抛出的异常的类型,如果异常是RuntimeException或者如果异常是目标方法声明抛出的异常的话,
              异常将传播到调用方法。否则,Spring框架将捕获这个异常,并且重新包装在RuntimeException中再次抛出去。
                 
         step1:实现接口(before方法)
          ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
         step2:使用ProxyFactoryBean(类似于JDK中的Proxy,可以用配置文件来配置)来织入通知
          ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
            <!-- 置入的过程
             step1:配置目标对象-->
            <bean id="someServiceTarget" class="aop3.SomeServiceImpl"/>
            
            <!-- step2:配置切面-->
            <bean id="logAdvice" class="aop3.LogAdvice"/>
            
            <!-- step3:配置代理-->
            <bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">
                      ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
               <!-- 代理类实现的接口,如果没有实现接口,则不用配置 -->
             <property name="proxyInterfaces" value="aop3.ISomeService"/>
             
               <!-- 目标对象 -->
             <property name="target" ref="someServiceTarget"/>
             
             <!-- 切面-->
             <property name="interceptorNames">
              <list>
               <value>logAdvice</value>
              </list>
             </property>
             
             <!-- 改变默认生成代理的机制,强制使用cglib生成代理对象 -->
             <property name="proxyTargetClass" value="true"/>
             
            </bean>
         
         
         
      ②:After-returning:后置通知,在目标方法执行之后执行;
         特点:a:不改变目标方法执行的结果|b:不改变目标方法执行的流程|c:目标方法执行之后执行
         
         AfterReturningAdvice接口
         
             afterReturning(Object returnValue,
                 Method method,
                 Object[] args,
                 Object target)
                 throws Throwable
                 
             这个通知给你机会得到调用的方法,传入的参数以及目标对象。你也可以获得被通知方法的返回值。
             这个接口返回空。虽然你可以得到目标方法的返回值,但是你不能替换返回值。
             
             
             
      ③:Around:环绕通知(拦截器)
        特点:a:可以改变目标方法执行的结果|b:也可以改变目标方法执行的流程|c:目标方法执行之前,之后均可执行
        MethodInterceptor接口
          第一:能够控制目标方法是否真的被调用,能过调用MethodInvocation.proceed(),方法来调用目标方法;
          第二:MethodInterceptor让你可以控制返回的对象,就是说你可以返回一个与proceed()方法返回对象完全不同的对象,
            但是要谨慎使用,必要时才用。
        
        MethodInterceptor接口
        
            public class SomeServiceInterceptor implements MethodInterceptor{
             
             public Object invoke(MethodInvocation arg0) throws Throwable {
              //方法之前的操作
              System.out.println(arg0.getMethod().getName() + " execute at:" + new Date());
              
              //执行目标方法
              Object rsObj = arg0.proceed();
              
              //方法之后的操作
              System.out.println("welcome to use again.");
              return rsObj;
             }

            }
            
            
            
      ④:After-throwing:异常处理通知,在目标方法抛出异常之后执行,处理异常,异常处理之后会将异常抛给调用者;
      
        ThrowsAdvice(标识接口)
        
            public void afterThrowing(IllegalNameException ine){
             System.out.println(ine.getMessage());
            }
        
      
              
      ⑤引入通知:
        也是切面(Introduction):动态地为目标类中添加新的方法,属性;引入类中加入 --------》aop7
      
        本质:动态地给一个类提供一个接口和实现
        
         编程:
          step1:将新增加的方法放在一个新的接口(IA)中;
          step2:写一个引入类需要现实(IA)接口还要现实IntroductionInterceptor接口(这个接口中去判断);
          step3:配置引入;
          ——————————————————————————————————————————————————
            ((IOtherService)service).doOther();
            public class MyIntroductionInterceptor implements IOtherService,IntroductionInterceptor{
              @Override
              public void doOther() {
               // TODO Auto-generated method stub
               System.out.println("doOther()...");
              }

              
              @Override
              public Object invoke(MethodInvocation arg0) throws Throwable {
               if(implementsInterface(arg0.getMethod().getDeclaringClass())){
                return arg0.getMethod().invoke(this, arg0.getArguments());
               }
               return arg0;
              }

              @Override
              public boolean implementsInterface(Class intf) {
               
               //这个方法的含义是判断调用类型是否是参数类型或者其父类型
               //比如
               //ArrayList.class.isAssignableFrom(ArrayList.class)  true
               return intf.isAssignableFrom(IOtherService.class);
              }

             }
          
          ——————————————————————————————————————————————————
             <bean id="someServiceTarget" class="aop7.SomeServiceImpl"/>
             
             <bean id="myIntro" class="aop7.MyIntroductionInterceptor"/>
             
             <bean id="myIntroAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
              <constructor-arg>
               <value>aop7.IOtherService</value>
              </constructor-arg>
              <constructor-arg>
               <ref local="myIntro"/>
              </constructor-arg>
             </bean>
             
             <!-- 如果目标类没有实现任何接口,在使用引入时,一定要设置proxyTargetClass=true -->
             <bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">
              <property name="proxyInterfaces" value="aop7.ISomeService"/>
              
              <property name="target" ref="someServiceTarget"/>
              
              <property name="interceptorNames">
               <list>
                <value>myIntroAdvisor</value>
               </list>
              </property>
              
             </bean>
       
          ——————————————————————————————————————————————————
   
   
      一个类实现了两个接口怎么办?
      <!-- 代理类实现的接口,写法>
      <property name="proxyInterfaces">
       <list>
        <value></value>
        <value></value>
       </list>
      </property>
      
      方法这样执行:((OtherService)service).doOther();
   
   
   
   3:切入点: Advisor= Advice(切面:交叉业务逻辑) + Pointcut(织入的位置)
      默认情况下,切面会织入到所有的方法之上;
      
      ◆自定义切入点:Pointcut接口 :
             ClassFilter接口__getClassFilter()如何选择目标类:
                ClassFilter一个方法matches(Class clazz目标对象所对应的class对象) 返回boolean
                
             MethodMatcher接口__getMethodMatcher():
                MethodMatcher:三个方法
                   a:boolean  isRuntime()
                     false:是一个静态切入点(依据方法的静态特征<方法名>)
                     true:这个切入点是一个动态切入点c方法才会执行了
                   b:matches(Method method目标方法,Class targetClass) method.getName()可以做出选择return true/false;
                   c:matches(Method method目标方法,Class targetClass,Object[] args方法的参数)
                     动态切入点耗时间性能低,可依据参数选择是否用切入点  
          
          PointcutAdvisor接口:
          
             <!-- step1 配置目标对象 -->
             <bean id="someServiceTarget" class="aop5.SomeServiceImpl"/>

             <!--
              step2:配置切面
             -->
             <bean id="logAdvice" class="aop5.LogAdvice"/>
             <bean id="myPointcut" class="aop5.MyPointcut"/>
             <bean id="logAdvisor" class="aop5.LogAdvisor">
              <property name="advice" ref="logAdvice"/>
              <property name="pointcut" ref="myPointcut"/>
             </bean>
             
             <!--
              step3:配置代理
             -->
             <bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">--------这个类一次只能为一个目标对象配置代理
              <!-- 代理类实现的接口,如果没有实现接口,则不用配置 -->
              <property name="proxyInterfaces" value="aop5.ISomeService"/>
              <!-- 目标对象 -->
              <property name="target" ref="someServiceTarget"/>
              <!--  切面-->
              <property name="interceptorNames">
               <list>
                <value>logAdvisor</value>
               </list>
              </property>
             </bean>
      ——————————————————————————————————————————————————————————————
   
      ◆系统预定义的切入点
          NameMatchMethodPointcutAdvisor:
           setMappedName(String)方法名
           setClassFilter(ClassFilter)目标类选择
             <!-- step1 配置目标对象 -->
             <bean id="someServiceTarget" class="aop6.SomeServiceImpl"/>
           
             <!--
              step2:配置切面
             -->
             <bean id="logAdvice" class="aop6.LogAdvice"/>
             <bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
              <property name="advice" ref="logAdvice"/>
              <property name="mappedNames">
               <list>
                <value>do*</value>   --------->以do开头的所有方法   
               </list>
              </property>
             </bean>
             <!--
              step3:配置代理
             -->
             <bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">
              <!-- 代理类实现的接口,如果没有实现接口,则不用配置 -->
              <property name="proxyInterfaces" value="aop6.ISomeService"/>
              <!-- 目标对象 -->
              <property name="target" ref="someServiceTarget"/>
              <!--  切面-->
              <property name="interceptorNames">
               <list>
                <value>logAdvisor</value>
               </list>
              </property>
             </bean>
             
             
          规则表达式切入点:RegexpMethodPointcut:具体看图片
          
 
======================================================================================================================================================================
======================================================================================================================================================================   
   
   4:自动配置代理--------一次性为多个目标对象配置代理;
     ①:依据Bean的名字(ID)
       BeanNameAutoProxyCreator:后处理Bean
         void setBeanNames(String[] beanNames) :用来指定需要指定的目标对象
           <property name="beanNames">
            <list>
            
         void setInterceptorNames(String[] interceptorNames):将切面指定
          
           <bean id="someService" class="aop8.SomeServiceImpl"/>
           <bean id="otherService" class="aop8.OtherServiceImpl"/>
           
           <bean id="logAdvice" class="aop8.LogAdvice"/>
           
           <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <property name="beanNames">
             <list>
              <value>someService</value>
              <value>otherService</value>
             </list>
            </property>
            <property name="interceptorNames">
             <list>
              <value>logAdvice</value>
             </list>
            </property>
           </bean>
      ——————————————————————————————————————————————————
       
     ②:依据Advisor与目标对象自动匹配
       DefaultAdvisorAutoProxyCreator:将所有的Advisor与目标对象匹配,生成代理,要求切面必须是一个Advisor
         <bean id="someService" class="aop9.SomeServiceImpl" />
         <bean id="otherService" class="aop9.OtherServiceImpl" />

         <bean id="logAdvice" class="aop9.LogAdvice" />
         
         <bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
          <property name="mappedNames">
           <list>
            <value>doSome</value>
            <value>doOther</value>
           </list>
          </property>
          <property name="advice" ref="logAdvice"/>
         </bean>
         
         <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
         </bean>
       
      ——————————————————————————————————————————————————
      
      
   5:使用标注与切入点表达式来进行AOP的编程--------》aop10
     以上是基于接口使用AOP,现在通过标注使用AOP:借的是AspectJ(AOP框架);
       编程:
        step1:引入AspectJ相关的库
        step2:编写切面类:(是一个POJO类)
          a:类前用@Aspect :加在切面类之前 ,标识这是一个切面
          b:编写通知(交叉业务逻辑:通过方法)并且添加标注(@Before|)以及切入点表达式(比如 execution(x doSome(...)):在方法前)
          c:配置代理:
             ①:自动配置代理
             ②:使用schema元素来自动配置代理
     --------------------------------------------------------------------------------------------------------
     @Aspect :加在切面类之前 ,标识这是一个切面
     @Before(切入点表达式):前置通知
     @AfterReturning:后置通知
     @AfterThrowing:异常处理通知
     @After:在目标方法执行完毕或者发生异常之后被调用
     @Around:环绕通知
     @DeclareParents引入 Introduction
     --------------------------------------------------------------------------------------------------------
     切入点表达式(Pointcut expressions)8种:
       execution:
       execution(方法修饰符<可选> 返回类型<必须是*号是任意的返回类型> 方法名(参数<可选:是..时任意,参数类型如果是java.lang中类型不必写上包名,其它要写>)) );
          
     --------------------------------------------------------------------------------------------------------
     <aop:aspectj-autoproxy>:指示spring容器,自动配置代理
      a:导入AOP命名空间
      b:在配置文件当中,添加标注
      
        --------------------------------------------------------------------------------------------------------
        @Aspect
        public class BankServiceAspect {
         @Before("execution(* openAccount(..))")
         public void log(JoinPoint jp){
          System.out.println(jp.getSignature().getName()+" execute at:  "+new Date());
         }
         
         @AfterReturning(value="execution(* withdraw(..))",returning="retVal")//asm参数名绑定
         public void welcome(JoinPoint jp,double retVal){
          //获得目标方法的返回结果
          if(retVal>10000)
           System.out.println("请提前预约!");
          
          System.out.println("welcome to use again.");
         }
         
         @Around("execution(* openAccount(..))")
         public Object transationManage(ProceedingJoinPoint pjp) throws Throwable{//ProceedingJoinPoint这个接口来调用目标方法
          System.out.println("Begin Transaction...");
          
          Object rsObj=null;
          try{
           rsObj=pjp.proceed();//这个异常要抛出去
          }catch(Exception e){
           System.out.println("Rollback Transaction...");
           throw e;
          }
          
          System.out.println("Commit Transaction...");
          return rsObj;
         }
         
         @AfterThrowing(value="execution(* deposite(..))",throwing="bae")//参数名绑定bae这个对象在下面才可以获得
         public void exceptionHandler(JoinPoint jp,BankAppException bae){
          System.out.println(bae.getMessage());
         }
         
         @DeclareParents(value="aop10.BankServiceImpl",defaultImpl=aop10.StockService.class)
         public IStockService stockService;
        }
      

        <?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: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/>
         
         <bean id="bankService" class="aop10.BankServiceImpl"/>
         <bean class="aop10.BankServiceAspect" />
         
        </beans>
        --------------------------------------------------------------------------------------------------------
        引入:
         a:定义新的接口,添加新的方法
         b:写一个pojo类实现新的接口
         c:
         

======================================================================================================================================================================
======================================================================================================================================================================   

Spring对持久层的支持:  
   
   模板方法(“开闭原则”模式):
    模版类的作用:
     ①:封装了业务流程(不变);
     ②:可以事先确定的业务先实现,可以被共享;
     ③:将变化的部分留给子类来实现;
   
   一:Spring对持久层支持采取的“策略”:
     ①:采用DAO模式(目的将具体的持久层技术与业务层解耦)
     ②:采用模版方法来简化具体持久层技术的使用
       Ⅰ:资源的管理<比如Connection session的获取与关闭>
       Ⅱ:异常的处理(重新定义了一套异常类----运行时异常,提供异常的具体细节)
       Ⅲ:事务的管理
     ③:使用IOC来解耦持久层与业务层
     
   二:编程:
    ㈠:spring对JDBC支持:
      step1:配置DataSource: (a:使用应用服务器提供的数据源|b:使用单独的产品:比如Apache(BasicDatasource),spring的Drivermanager(学习))
      //step2:配置模版类(JdbcTemplate),Datasource注入
      step2:配置DAO,继承JdbcDaoSupport模版注入
      step3:配置Service,DAO注入
       
       ————————————————————————————————————————————————————
       重要使用:
       private JdbcTemplate jt;
       
       Object[] params= new Object[]{c.getId()};
       jt.update(sql,params);
       
       findByName(): return (Customer) jt.queryForObject(sql, params,new CustomerRowMapper());
       findAll(): return jt.query(sql, new CustomerRowMapper());
       
       public class CustomerRowMapper implements RowMapper{}(使用RowMapper定义如何将ResultSet变成java对象)
       @Override
       public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
        Customer c = new Customer();
        c.setId(rs.getLong("id"));
        c.setName(rs.getString("name"));
        c.setAge(rs.getInt("age"));
        return c;
       }
       
       ————————————————————————————————————————————————————
       配置文件:
         <!-- DataSource -->
         <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
          <property name="driverClassName">
           <value>com.mysql.jdbc.Driver</value>
          </property>
          <property name="url">
           <value>jdbc:mysql://localhost:3306/tarena</value>
          </property>
          <property name="username">
           <value>root</value>
          </property>
          <property name="password">
           <value>LWSX</value>
          </property>
         </bean>
         
         <!-- JdbcTemplate -->
         <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
          <property name="dataSource" ref="dataSource" />
         </bean>
         
         <!-- DAO -->
         <bean id="customerDAO" class="dao.impl.CustomerDAOJdbcImpl">
          <property name="jt" ref="jdbcTemplate" />
         </bean>
         
         <!-- Service -->
         <bean id="customerService" class="service.impl.CustomerServiceSpringImpl">
          <property name="customerDAO" ref="customerDAO" />
         </bean>
      
       ————————————————————————————————————————————————————
       
======================================================================================================================================================================
======================================================================================================================================================================        
       
       
    ㈡:spring对Hibernate支持:
      step1:配置DataSource
      step2:配置SessionFactory
      step3:配置DAO 继承HibernateDaoSupport
      step4:配置service
      
      使用第三方的数据源:
        a:将jar文件加入到classpath
        b:配置
    
    
        ————————————————————————————————————————————————————
        重要使用:
        public class CustomerDAOHibernateImpl extends HibernateDaoSupport implements CustomerDAO{

         @Override
         public void delete(Customer c) {
          // TODO Auto-generated method stub
          getHibernateTemplate().delete(c);
         }


         @Override
         public void delete(String name) {
          // TODO Auto-generated method stub
          Customer c = findByName(name);
          getHibernateTemplate().delete(c);
         }
         
         @Override
         public List<Customer> findAll() {
          // TODO Auto-generated method stub
          return getHibernateTemplate().find("from Customer c");
         }

         @Override
         public Customer findByName(final String name) {
          // TODO Auto-generated method stub
          //有多个可以参数使用数组
          //return (Customer)getHibernateTemplate().findByNamedParam("from Customer c where c.name=:n", "n", name).get(0);
          //使用HibernateCallback方式:即可以获得模版类的管理资源的好处,又可以按照熟悉的Hibernate的API来编程
          HibernateTemplate template = getHibernateTemplate();
          return (Customer) template.execute(new HibernateCallback(){
           
           
           @Override
           public Object doInHibernate(Session session)throws HibernateException, SQLException {
            String hql="from Customer c where c.name=:n";
            return session.createQuery(hql).setString("n", name).uniqueResult();
           }
           
          });
          
         }

         @Override
         public void modify(Customer c) {
          // TODO Auto-generated method stub
          getHibernateTemplate().merge(c);
         }

         @Override
         public void save(Customer cust) {
          // TODO Auto-generated method stub
          //模版类是线程安全的
          getHibernateTemplate().save(cust);
         }


        }

        
        ————————————————————————————————————————————————————
        配置文件:
          <!-- DataSource -->
          <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
           <property name="driverClassName">
            <value>com.mysql.jdbc.Driver</value>
           </property>
           <property name="url">
            <value>jdbc:mysql://localhost:3306/tarena</value>
           </property>
           <property name="username">
            <value>root</value>
           </property>
           <property name="password">
            <value>LWSX</value>
           </property>
          </bean>

          <!-- SessionFactory -->
          <bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
           <property name="dataSource">
            <ref bean="dataSource" />
           </property>
           <property name="mappingResources">
            <list>
             <value>entity.\Customer.hbm.xml</value>
            </list>
           </property>
           <property name="hibernateProperties">
            <props>
             <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
             <prop key="hibernate.show_sql">true</prop>
             <prop key="hibernate.hbm2ddl.auto">create-drop</prop>
            </props>
           </property>
          </bean>
          
          <!-- DAO -->
          <bean id="customerDAO" class="dao.impl.CustomerDAOHibernateImpl">
           <property name="sessionFactory" ref="mySessionFactory"/>
          </bean>
          
          <!-- Service -->
          <bean id="customerService" class="service.impl.CustomerServiceSpringImpl">
           <property name="customerDAO" ref="customerDAO"/>
          </bean>
       
        ————————————————————————————————————————————————————
    
======================================================================================================================================================================
======================================================================================================================================================================  
Spring对事件的支持:spring_transaction
   事务当作一个切面,动态地织入到目标对象,形成一个代理对象。
   
   ①事务概念:事务可以保证一系列的操作可以作为一个工作单元来执行机制;
   ②事务特性:
     Ⅰ:事务的传播行为(客户端发起的事务,如何影响被调用者的事务Bean类)
       七个:(7种=EJB 的 6 种传播行为+嵌套式事务
        PROPAGATION_REQUIRED(有则用,无容器提供)一般用于数据的写操作
        PROPAGATION_SUPPORTS(有则用,没有不提供)一般用于数据的读操作
        PROPAGATION_REQUIRES_NEW(客户端有挂起,Bean建一个|客户端没有,Bean还是建一个)
        
        嵌入式事务:一个事务由多个子工作单元组成,每一个子工作单元都可以单独回滚;SAVEPOINT
           Spring 对事务的边界多了一种嵌套事务(PROPAGATION_NESTED)。
           PROPAGATION_NESTED:
           如果客户端启动了事务 T1,那么 Bean 启动一个嵌套在 T1中的子事务 T2;
           如果客户端没有启动事务,那么 Bean 会启动一个新的事务,类似于REQUIRED_NEW
    
     Ⅱ:隔离性
     Ⅲ:只读事务(可以对查询操作优化)
     Ⅳ:事务的超时
     Ⅴ:回滚规则:
       运行时异常,回滚|受查,提交|默认
       受查异常要用:设置:+异常类型,提交
            -异常类型,回滚
       Spring 的容器对于非受查异常(服务模块中抛出的非受查异常),会回滚事务。对于受查异常,会提交事务。
       如果即使发生了某种受查异常,也要回滚事务,可以用 “- 异常类型“来声明。同样,对于非受查异常,如果不要求回滚事务,可以用"+异常类型"来声明。 
     
   -------------------------------------------------------------------------------------------------------------------------------------

   <一>:采取策略:
     1:采用一致的编程模型来处理事务
       a:本地事务:只涉及到一个数据资源。分布式事务:一个事务涉及到多个数据资源。都可以来用相同的方式来编程;
       b:使用事务管理器,来将应用程序与底层容器具体的事务机制解耦PlatformTransactionManager接口:
                       ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
                       实现:
                        DataSourceTransactionManager
                        HibernateTransactionManager
                        JdoTransactionManager
                        JtaTransactionManager
       
     2:声明:对持声明式的事务,通过配置文件/标注来声明事务特性;|spring通过AOP的方式来将事务作为一个切面注入到业务对象当中的;
     3:分布式:spring对分布式事务的支持,分布式事务如何实现:通过事务管理器JTA,它通过两个阶段提交协议管理:提交准备:询问|提交:提交;
         a:在容器外使用:(不使用应用服务器,比如:weblogic,jboss)使用支持分布式事务的事务管理器(JTATransactionManager);比如“JOTM”产品;
         b:在容器内使用:直接使用容器提供的分布式事务的支持;
         
   spring用工具看spring.xml结构 
   -------------------------------------------------------------------------------------------------------------------------------------
         
   <二>:spring对Hibernate事务的支持:
    ⑴:采用接口:
      步骤:
       step1:DataSource
       step2:SessionFactory
       step3:配置事务管理器
       step4:DAO
       step5:配置目标对象(业务层中的对象)
       step6:配置事务代理
         
          配置文件:_______________________________________________________________________________________
            
            <!-- DataSource -->
            <bean id="dataSource"
             class="org.springframework.jdbc.datasource.DriverManagerDataSource">
             <property name="driverClassName">
              <value>com.mysql.jdbc.Driver</value>
             </property>
             <property name="url">
              <value>jdbc:mysql://localhost:3306/tarena</value>
             </property>
             <property name="username">
              <value>root</value>
             </property>
             <property name="password">
              <value>LWSX</value>
             </property>
            </bean>
            <!-- SessionFactory -->
            <bean id="mySessionFactory"
             class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
             <property name="dataSource">
              <ref bean="dataSource" />
             </property>
             <property name="mappingResources">
              <list>
               <value>entity\Account.hbm.xml</value>
               <value>entity\Stock.hbm.xml</value>
              </list>
             </property>
             <property name="hibernateProperties">
              <props>
               <prop key="hibernate.dialect">
                org.hibernate.dialect.MySQLDialect
               </prop>
               <prop key="hibernate.show_sql">true</prop>
               <prop key="hibernate.hbm2ddl.auto">update</prop>
              </props>
             </property>
            </bean>
            <!-- 配置事务管理器 -->
            <bean id="myTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
             <property name="sessionFactory" ref="mySessionFactory"/>
            </bean>
            <!-- Dao -->
            <bean id="abstractDAO" abstract="true">
             <property name="sessionFactory" ref="mySessionFactory"/>
            </bean>
            
            <bean id="accountDAO" class="dao.impl.AccountDAOHibernateImpl" parent="abstractDAO"/>
            <bean id="stockDAO" class="dao.impl.StockDAOHibernateImpl" parent="abstractDAO"/>
            <!-- Service  target-->
            <bean id="transferServiceTarget" class="service.impl.TransferServiceSpringImpl">
             <property name="accountDAO" ref="accountDAO"/>
             <property name="stockDAO" ref="stockDAO"/>
            </bean>
            
            <!-- 配置事务代理 -->
            <bean id="transferService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
             <property name="target" ref="transferServiceTarget"/>
             <property name="transactionManager" ref="myTransactionManager"/>
             <property name="transactionAttributes">
              <props>
               <prop key="open*">PROPAGATION_REQUIRED</prop>
               <prop key="query*">PROPAGATION_SUPPORTS,readOnly</prop>
               <prop key="transfer">PROPAGATION_REQUIRED,-TransferException</prop>
              </props>
             </property>
            </bean>
            _______________________________________________________________________________________
     
     
      ⑵:spring中使用标注来添加事务管理:
      步骤:
       1:之前要引入tx命名空间,指示spring容器使用标注来提供事务切面:其中去找一下
       2:在业务对象当中添加@Transactional来声明事务切面(方法前面)
       step1: DataSource
       step2: SessionFactory
       step3: HibernaterTransactionManager
       step4: DAO
       step5: Service
          
       配置文件:_______________________________________________________________________________________
       
          <!-- DataSource -->
          <bean id="dataSource"
           class="org.springframework.jdbc.datasource.DriverManagerDataSource">
           <property name="driverClassName">
            <value>com.mysql.jdbc.Driver</value>
           </property>
           <property name="url">
            <value>jdbc:mysql://localhost:3306/tarena</value>
           </property>
           <property name="username">
            <value>root</value>
           </property>
           <property name="password">
            <value>1234</value>
           </property>
          </bean>
          <!-- SessionFactory -->
          <bean id="mySessionFactory"
           class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
           <property name="dataSource">
            <ref bean="dataSource" />
           </property>
           <property name="mappingResources">
            <list>
             <value>entity\Account.hbm.xml</value>
             <value>entity\Stock.hbm.xml</value>
            </list>
           </property>
           <property name="hibernateProperties">
            <props>
             <prop key="hibernate.dialect">
              org.hibernate.dialect.MySQLDialect
             </prop>
             <prop key="hibernate.show_sql">true</prop>
             <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
           </property>
          </bean>
          <!-- 配置事务管理器 -->
          <bean id="myTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
           <property name="sessionFactory" ref="mySessionFactory"/>
          </bean>
          <!-- Dao -->
          <bean id="abstractDAO" abstract="true">
           <property name="sessionFactory" ref="mySessionFactory"/>
          </bean>
          <bean id="accountDAO" class="dao.impl.AccountDAOHibernateImpl" parent="abstractDAO"/>
          <bean id="stockDAO" class="dao.impl.StockDAOHibernateImpl" parent="abstractDAO"/>
          <!-- Service-->
          <bean id="transferService" class="service.impl.TransferServiceSpringImpl2">
           <property name="accountDAO" ref="accountDAO"/>
           <property name="stockDAO" ref="stockDAO"/>
          </bean>
          
          <tx:annotation-driven transaction-manager="myTransactionManager"/>
          _______________________________________________________________________________________
          
        类的用法:_______________________________________________________________________________________
          @Transactional(propagation=Propagation.REQUIRED)
          public void openAccount(String name, double balance) {}

          @Transactional(propagation=Propagation.REQUIRED)
          public void openStock(String name) {}

          @Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
          public double queryBalance(String accName) {}

          @Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
          public double queryQty(String stockName) {}

          @Transactional(propagation=Propagation.REQUIRED,rollbackFor=TransferException.class)
          public void transfer(String accName, String stockName, double amt) throws TransferException{}
                 
        
          _______________________________________________________________________________________
          
          
   -------------------------------------------------------------------------------------------------------------------------------------
   <三>:spring对JDBC事务的支持:(同上)
     a:基于配置文件:
       1:DataSource
       2:事务管理器DataSourceTransactionManager
       3:DAO
       4:配置目标对象
       5:配置事务代理TransactionProxyFactoryBean

     b:基于标注方式:
       1:DataSource
       2:事务管理器DataSourceTransactionManager
       3:DAO
       4:配置目标对象service
       5:之前要引入tx命名空间,指示spring容器使用标注来提供事务切面|在业务对象当中添加@Transactional来声明事务切面(方法前面)


   -------------------------------------------------------------------------------------------------------------------------------------

======================================================================================================================================================================
======================================================================================================================================================================
Spring当中支持分布式事务:
  A:应用不在应用服务器(weblogic ,jboss, was)当中运行------》spring_transaction3
    step1:选择一个支持JTA事务能力的事务管理器(weblogic ,jboss, was,JOTM:java open transaction manager开源应用服务器的一部分)
    step2:将JOTM相关的jar文件加入classpath,并且提供相关的配置文件
    step3:在Spring中配置JOTM:
       ①:DataSource必须要支持分布式事务“XADataSource”,JDBC驱动也要支持
       ②:事务管理器用:JTATransactionManager
       ③:配置JOTM
       
  B:就用在应用服务器当中运行:spring可以将分布式事务交给应用服务器
  -------------------------------------------------------------------------------------------------------------------------------------
  
Spring对Struts的对持:
  Struts(表示层)+Spring(中间层:业务层,持久层)+Hibernate(数据库):SSH<--------->Jsp+servlet+EJB:JSE
  一:集成的方式:
    1:要解决的问题:
      ①:web应用怎么样获得spring容器的引用
         可以使用Listener/plugin加载spring的代码
         
      ②:Action如何获得被spring容器管理的Bean
         用getBean()/IOC的方式
         
      ③:集成:
        使用ActionSupport(spring提供的):getWebApplicationContext()可以获得spring的引用
          step1:加载spring:Listener:web.xml/plugin:struts.xml方式加载  配置文件路径默认从根目录下搜索的
          step2:就用中的Action继承ActionSupport
          step3:调用getWebApplicationContext()获得容器的引用
   
  二:编程:
    1:web获得spring容器引用:spring_struts工程
      直接继承ActionSupport
       优点:不影响struts原有编程风格简单
       缺点:struts依据spring,作“IOC”方式倡导不符
    

Spring是一个开源的Java框架,用于构建企业级应用程序。它提供了一种轻量级的、非侵入式的开发方式,通过依赖注入和面向切面编程等特性,简化了Java应用程序的开发过程。 以下是关于Spring学习的一些笔记: 1. IoC(控制反转):Spring通过IoC容器管理对象的创建和依赖关系的注入。通过配置文件或注解,将对象的创建和依赖关系的维护交给Spring容器来管理,降低了组件之间的耦合度。 2. DI(依赖注入):Spring通过依赖注入将对象之间的依赖关系解耦。通过构造函数、Setter方法或注解,将依赖的对象注入到目标对象中,使得对象之间的关系更加灵活和可维护。 3. AOP(面向切面编程):Spring提供了AOP的支持,可以将与业务逻辑无关的横切关注点(如日志、事务管理等)从业务逻辑中分离出来,提高了代码的可重用性和可维护性。 4. MVC(模型-视图-控制器):Spring提供了一个MVC框架,用于构建Web应用程序。通过DispatcherServlet、Controller、ViewResolver等组件,实现了请求的分发和处理,将业务逻辑和视图展示进行了分离。 5. JDBC和ORM支持:Spring提供了对JDBC和ORM框架(如Hibernate、MyBatis)的集成支持,简化了数据库访问的操作,提高了开发效率。 6. 事务管理:Spring提供了对事务的支持,通过声明式事务管理和编程式事务管理,实现了对数据库事务的控制和管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值