面试时被问到spring是如何控制事务的?你是怎么回答的?

时间:2023-01-26 18:27:20
几次面试都遇到这样的问题,解释不出来。

就知道如何使用spring这框架,却说不来其原理,惭愧。

小弟诚心求教!

46 个解决方案

#1


spring的事务是通过“声明式事务”的方式对事务进行管理,即在配置文件中进行声明,通过AOP将事务切面切入程序。最大的好处是大大减少了代码量,比如:

Transaction tx=session.getTransaction();
session.beginTransaction();
tx.commit();
tx.rollback();

等等这类代码不用在每个方法中重复的去写,简化了程序,提高了工作效率。

#2


AOP 面试时被问到spring是如何控制事务的?你是怎么回答的?

#3


有P惭愧的,用框架/了解框架原理/写框架是一个层面的事吗。

#4


引用 3 楼 forgetsam 的回复:
有P惭愧的,用框架/了解框架原理/写框架是一个层面的事吗。

有道理,如果目前拿4000块钱一个月,那么你不必懂它是怎么实现的。如果我是面试官我也会这样的问题,我觉不期许你都能知道,但如果你刚好都知道那不是太好了么

#5


引用 4 楼 whos2002110 的回复:
Quote: 引用 3 楼 forgetsam 的回复:

有P惭愧的,用框架/了解框架原理/写框架是一个层面的事吗。

有道理,如果目前拿4000块钱一个月,那么你不必懂它是怎么实现的。如果我是面试官我也会这样的问题,我觉不期许你都能知道,但如果你刚好都知道那不是太好了么


确实这样!

#6


1.IOC控制反转:控制权由对象本身转向容器,由容器对bean对象进行控制。
2.AOP面向切面编程:把具体的类创建对应的代理类,通过代理类来对具体类进行操作。
spring是一个容器,通过spring这个容器来对对象进行管理,根据配置文件来实现spring对对象的管理。
就这样理解吧,暂时我也只能这么回答,太深入我也不知道怎么说了

#7


SPRING的事务贯彻始终的

源代码没有读过
但是不管AOP还是IOC都有事务支持的

推测一下
SPRING是一个大的容器,一个大的工厂类
那么当你从SPRING中获取一个对象的时候
在建立对象的时候
先开启了事务,然后将对象给你,让 你去使用
在你方法结束后会交回对象
这个时候提交事务并关闭事务

这些操作都在框架内实现
所以只要使用了SPRING就一定会被事务所包围着

#8


面试时被问到spring是如何控制事务的?你是怎么回答的?

#9


衷心感谢以上几位的回答~!

#10


要明白事务是怎么样的一个概念,自己写事务又如何做

try{
// 业务逻辑
if(成功)
  commit();
}catch(e){
  // 出现异常
  rollback();
}

spring会捕获到你往上抛的异常,然后帮你try catch,如果发现捕获到异常,会就把connection不提交,直接回滚,所以我们在配置声明式事务的时候会有一个参数是什么异常类,默认应该是runtimexcepttion吧...

#11


去看看Java的动态代理就明白原理是怎么回事了。

#12


框架自动给你管理事务!具体是什么实现还真不清楚!

#13


一般我遇上这个问题,我就说 ,配置好了,自动回管理事务,他要是问怎么配置,我就说别人配置的。

#14


我的建议是这样的,首先回答出IOC和AOP,然后简单的简绍这两个东西,说的不需要太多,但是要达到重点,然后,直接offer,

#15


Spring是通过AOP的手段达到事务控制的,具体实现是靠spring-asm.jar和cglib.jar,因为这两个jar都提供了与动态代理有关的功能,实现运行时植入新特性的功能。类似的功能也可以通过我们手工实现,如果对字节码等概念掌握比较好,可以充分利用apache bcel库进行更为细致的功能控制。

以上内容不真实不可靠,仅供面试吹牛使用。你这么回答对方基本也不会深入问了,其实面试的人也不会具体细节的。

#16


1楼正解,温故一下!

#17


帮楼主顶起让更多人看到

#18


引用 6 楼 caochuankui 的回复:
1.IOC控制反转:控制权由对象本身转向容器,由容器对bean对象进行控制。
2.AOP面向切面编程:把具体的类创建对应的代理类,通过代理类来对具体类进行操作。
spring是一个容器,通过spring这个容器来对对象进行管理,根据配置文件来实现spring对对象的管理。
就这样理解吧,暂时我也只能这么回答,太深入我也不知道怎么说了


very  good!

#19


-- 根据上楼几位的回答,我结合了最佳的答案恍然大悟,谢谢各位神

Spring 的事务,可以说是 Spring AOP 的一种实现。

AOP面向切面编程,即在不修改源代码的情况下,对原有功能进行扩展,通过代理类来对具体类进行操作。 

spring是一个容器,通过spring这个容器来对对象进行管理,根据配置文件来实现spring对对象的管理。

spring的事务声明有两种方式,编程式和声明式。spring主要是通过“声明式事务”的方式对事务进行管理,即在配置文件中进行声明,通过AOP将事务切面切入程序,最大的好处是大大减少了代码量。
 

#20


頂 ,面試題目

#21


会用和会制造和知道里面的构造不是一个层次,比如 你知道用手机打电话,如何实现电话的不知道。

#22


This is certainly the  Runescape 3 Gold best advantage, whereby you can understand the strategic practice of a win-win game. Diablo 3 guides will help you to  Old School Runescape Gold conquer the monsters in the game field, whereby you can handle them with all ease.

#23


顶,很常见的面试问题

#24


面试时被问到spring是如何控制事务的?你是怎么回答的?采纳重点

#25


好多大神,顶礼膜拜,我连用还没学会

#26


spring有两种事务配置方式,一种是配置的事务管理器,另一种的是代码控制的事务
配置的事务管理器的方式是我们经常用到的经常会用到在配置文件中。代码控制的事务分为jdbc模板的和事务管理器的,jdbc默认自动提交,事务管理器的和咱们通常的一样会有commit  rollback等操作。闲 的时候看一下开发指南吧

#27


谁能再讲讲AOP的事情

#28


认为26楼是正解

#29


坐等给分,必须给分

#30


顶 一个,常见的面试提呀

#31


Spring 的事务,可以说是 Spring AOP 的一种实现。

AOP面向切面编程,即在不修改源代码的情况下,对原有功能进行扩展,通过代理类来对具体类进行操作。 

spring是一个容器,通过spring这个容器来对对象进行管理,根据配置文件来实现spring对对象的管理。

spring的事务声明有两种方式,编程式和声明式。spring主要是通过“声明式事务”的方式对事务进行管理,即在配置文件中进行声明,通过AOP将事务切面切入程序,最大的好处是大大减少了代码量。

#32


引用 11 楼 Inhibitory 的回复:
去看看Java的动态代理就明白原理是怎么回事了。


说实话  我看了动态代理 面试时被问到spring是如何控制事务的?你是怎么回答的?,,也不是很懂 和spring的  事务 有什么联系,,,看来我还得在修炼修炼。。。

#33


配置完成后,好像是用注解做的,事物都交给容器了,具体怎么实现还真不太了解。

#34


主要是通过配置或注解方式使用AOP扩展原有业务,当捕获到指定异常的时候就会回滚;
关键字:AOP、异常

#35


推荐一个Spring的详细教程呗

#36


spring的AOP是通过IOC来实现的,仔细体会一下,很有趣的

#37


引用 楼主 wsyangzuda 的回复:
几次面试都遇到这样的问题,解释不出来。

就知道如何使用spring这框架,却说不来其原理,惭愧。

小弟诚心求教!



面向切面编程

AOP

Aspect Oriented Program
的首字母缩写)
 
,我们知道,面向对象的
特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中
往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一
个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。
  
      
但是人们也发现,在分散代码的同时,也增加了代码的重复性。什么意思呢?比如说,
我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须
在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设
计让类与类之间无法联系,而不能将这些重复的代码统一起来。
  
    
也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后
再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,
它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入
代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是
面向切面的编程。
   
      
一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些
方法则叫切入点。有了
AOP
,我们就可以把几个类共有的代码,抽取到一个切片中,等到
需要时再切入对象中去,从而改变其原有的行为。
  
这样看来,
AOP
其实只是
OOP
的补充而已。
OOP
从横向上区分出一个个的类来,而
AOP
则从纵向上向对象中加入特定的代码。有了
AOP

OOP
变得立体了。如果加上时间维度, 
AOP
使
OOP
由原来的二维变为三维了,由平面变成立体了。从技术上来说,
AOP
基本上
是通过代理机制实现的。
   
     AOP
在编程历史上可以说是里程碑式的,对
OOP
编程是一种十分有益的补充
  

#38


原理
AOP(Aspect Oriented Programming),也就是面向方面编程的技术。AOP基于IoC基础,是对OOP的有益补充。
  AOP将应用系统分为两部分,核心业务逻辑(Core business concerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,所有大中型应用都要涉及到的持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等。
  AOP正在成为软件开发的下一个光环。使用AOP,你可以将处理aspect的代码注入主程序,通常主程序的主要目的并不在于处理这些aspect。AOP可以防止代码混乱。
  Spring framework是很有前途的AOP技术。作为一种非侵略性的、轻型的AOP framework,你无需使用预编译器或其他的元标签,便可以在Java程序中使用它。这意味着开发团队里只需一人要对付AOP framework,其他人还是像往常一样编程。
  AOP概念
  让我们从定义一些重要的AOP概念开始。
  — 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。
  — 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
  — 通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。
  — 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。
  — 引入(Introduction):添加方法或字段到被通知的类。Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现IsModified接口,来简化缓存。
  — 目标对象(Target Object):包含连接点的对象,也被称作被通知或被代理对象。
  — AOP代理(AOP Proxy):AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
  — 编织(Weaving):组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
  各种通知类型包括:
  —  Around通知:包围一个连接点的通知,如方法调用。这是最强大的通知。Aroud通知在方法调用前后完成自定义的行为,它们负责选择继续执行连接点或通过返回它们自己的返回值或抛出异常来短路执行。
  —  Before通知:在一个连接点之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
  —  Throws通知:在方法抛出异常时执行的通知。Spring提供强制类型的Throws通知,因此你可以书写代码捕获感兴趣的异常(和它的子类),不需要从Throwable或Exception强制类型转换。
  —  After returning通知:在连接点正常完成后执行的通知,例如,一个方法正常返回,没有抛出异常。
  Around通知是最通用的通知类型。大部分基于拦截的AOP框架(如Nanning和Jboss 4)只提供Around通知。
  如同AspectJ,Spring提供所有类型的通知,我们推荐你使用最为合适的通知类型来实现需要的行为。例如,如果只是需要用一个方法的返回值来更新缓存,你最好实现一个after returning通知,而不是around通知,虽然around通知也能完成同样的事情。使用最合适的通知类型使编程模型变得简单,并能减少潜在错误。例如,你不需要调用在around通知中所需使用的MethodInvocation的proceed()方法,因此就调用失败。
  切入点的概念是AOP的关键,它使AOP区别于其他使用拦截的技术。切入点使通知独立于OO的层次选定目标。例如,提供声明式事务管理的around通知可以被应用到跨越多个对象的一组方法上。 因此切入点构成了AOP的结构要素。
 拦截器(也称拦截机)
    拦截机 (Interceptor), 是 AOP (Aspect-Oriented Programming) 的另一种叫法。AOP本身是一门语言,只不过我们使用的是基于JAVA的集成到Spring 中的 SpringAOP。同样,我们将通过我们的例子来理解陌生的概念。

 接口类
Java代码     
1. <SPAN style="FONT-SIZE: medium">package com.test.TestSpring3;   
2.   
3. public interface UserService // 被拦截的接口   
4. ...{   
5.     public void printUser(String user);   
6. }   
7. </SPAN>  
 实现类
Java代码     
1. <SPAN style="FONT-SIZE: medium">package com.test.TestSpring3;   
2.   
3. public class UserServiceImp implements UserService // 实现UserService接口   
4. ...{   
5.     public void printUser(String user) ...{   
6.         System.out.println("printUser user:" + user);// 显示user   
7.     }   
8. }   
9.   
10. </SPAN>  
 AOP拦截器
Java代码     
1. <SPAN style="FONT-SIZE: medium">package com.test.TestSpring3;   
2.   
3. import org.aopalliance.intercept.MethodInterceptor;   
4. import org.aopalliance.intercept.MethodInvocation;   
5.   
6. public class UserInterceptor implements MethodInterceptor   
7. // AOP方法拦截器   
8. ...{   
9.   
10.     public Object invoke(MethodInvocation arg0) throws Throwable ...{   
11.   
12.         try ...{   
13.   
14.             if (arg0.getMethod().getName().equals("printUser"))   
15.             // 拦截方法是否是UserService接口的printUser方法   
16.             ...{   
17.                 Object[] args = arg0.getArguments();// 被拦截的参数   
18.                 System.out.println("user:" + args[0]);   
19.                 arg0.getArguments()[0] = "hello!";// 修改被拦截的参数   
20.   
21.             }   
22.   
23.             System.out.println(arg0.getMethod().getName() + "---!");   
24.             return arg0.proceed();// 运行UserService接口的printUser方法   
25.   
26.         } catch (Exception e) ...{   
27.             throw e;   
28.         }   
29.     }   
30. }   
31. </SPAN><SPAN style="FONT-SIZE: medium">   
32. </SPAN>  
 测试类
Java代码     
1. <SPAN style="FONT-SIZE: medium">package com.test.TestSpring3;   
2.   
3. import org.springframework.beans.factory.BeanFactory;   
4.   
5. import org.springframework.beans.factory.xml.XmlBeanFactory;   
6. import org.springframework.context.ApplicationContext;   
7. import org.springframework.context.support.ClassPathXmlApplicationContext;   
8. import org.springframework.context.support.FileSystemXmlApplicationContext;   
9. import org.springframework.core.io.ClassPathResource;   
10. import org.springframework.core.io.Resource;   
11. import org.springframework.web.context.support.WebApplicationContextUtils;   
12.   
13. public class TestInterceptor ...{   
14.   
15.     public static void main(String[] args) ...{   
16.         ApplicationContext ctx = new FileSystemXmlApplicationContext(   
17.                 "classpath:applicationContext.xml");   
18. //        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");       
19.            
20.         UserService us = (UserService) ctx.getBean("userService");   
21.         us.printUser("shawn");   
22.   
23.     }   
24. }</SPAN><SPAN style="FONT-SIZE: medium">   
25. </SPAN>  
 配置文件
 
   
Xml代码     
1. <SPAN style="FONT-SIZE: medium"><?xml version="1.0" encoding="UTF-8"?>  
2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">  
3. <beans>  
4.     <bean id="userServiceImp"  
5.         class="com.test.TestSpring3.UserServiceImp" />  
6.   
7.     <bean id="userInterceptor" class="com.test.TestSpring3.UserInterceptor" />  
8.   
9.     <bean id="userService"  
10.         class="org.springframework.aop.framework.ProxyFactoryBean">  
11.       <!-- 代理接口 -->  
12.         <property name="proxyInterfaces">  
13.             <value>com.test.TestSpring3.UserService</value>  
14.         </property>  
15.        <!-- 目标实现类 -->  
16.         <property name="target">  
17.             <ref local="userServiceImp" />    
18.       </property>  
19.         <!-- 拦截器 -->  
20.         <property name="interceptorNames">  
21.             <list>  
22.                 <value>userInterceptor</value>  
23.             </list>  
24.         </property>  
25.     </bean>  
26.   
27. </beans>  
28. </SPAN>  
 
 输出:
  user:shawn
   printUser---!
  printUser user:hello!

#39


结论:调用方法的时候 传入的值被拦截修改了.
拦截器中的事务管理(事务拦截机)
 如果不采用拦截机的机制时,在使用JDBC进行数据库访问时,存在两种情况: 
• 自动提交        这是JDBC驱动默认的模式,每次数据库操作(CRUD)成功完成后,都作为一个单独的事务自动提交,如果未成功完成,即抛出了 SQLException 的话,仅最近的一个操作将回滚。 
• 非自动提交    这是想更好的控制事务时需要程序地方式进行控制: 
o 在进行该事务单元的任何操作之前 setAutoCommit(false) 
o 在成功完成事务单元后 commit() 
o 在异常发生后 rollback()
自动提交模式是不被推荐的,因为每个操作都将产生一个事务点,这对于大的应用来说性能将受到影响;再有,对于常见的业务逻辑,这种模式显得无能为力。比如:
转帐,从A帐户取出100元,将其存入B帐户;如果在这两个操作之间发生了错误,那么用户A将损失了100元,而本来应该给帐户B的,却因为失败给了银行。
所以,建议在所有的应用中,如果使用 JDBC 都将不得不采用非自动提交模式(你们要能发现了在我们的 JDBC 那个例子中,我们采用的就是自动提交模式,我们是为了把精力放在JDBC上,而不是事务处理上),即我们不得不在每个方法中:
Java代码     
1. <SPAN style="FONT-SIZE: medium">try {       
2.  // 在获得连接后,立即通过调用 setAutoCommit(false) 将事务处理置为非自动提交模式  // Prepare Query to fetch the user Information          
3.      pst = conn.prepareStatement(findByName);                    
4.        // ...            conn.commit();          
5.  }  catch(Exception ex) {          
6.      conn.rollback();         
7.       throw ex;          
8.  }finally {      
9.          try {       
10.            // Close Result Set and Statement     
11.           if (rset != null) rset.close();                  
12.          if (pst != null) pst.close();                           
13.     } catch (Exception ex) {                  
14.        ex.printStackTrace();                   
15.        throw new Exception("SQL Error while closing objects = " + ex.toString());               
16. }     
17. }   
18. </SPAN>  
 这样代码在AOP的倡导者看来是“肮脏”的代码。他们认为,所有的与事务有关的方法都应当可以集中配置(见声明性事务控制),并自动拦截,程序应当关心他们的主要任务,即商业逻辑,而不应和事务处理的代码搅和在一起。

我先看看 Spring 是怎么做到拦截的:
Spring 内置支持的事务处理拦截机
这里因为要用到JpetStore项目中的代码,我们将 applicationContext.xml 全部内容列出:
<?xml version="1.0" encoding="UTF-8"?>

<!--
  - Application context definition for JPetStore's business layer.
  - Contains bean references to the transaction manager and to the DAOs in
  - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").

    Jpetstore 的应用上下文定义,包含事务管理和引用了在 dataAccessContext-local/jta.xml(具体使用了哪个要看 web.xml 中的 'contextConfigLocation' 的配置)中注册的DAO
-->
<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"
       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.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
    
    <!-- ========================= GENERAL DEFINITIONS ========================= -->

    <!-- Configurer that replaces ${...} placeholders with values from properties files 
         占位符的值将从列出的属性文件中抽取出来
     -->
    <!-- (in this case, mail and JDBC related properties) -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>WEB-INF/mail.properties</value>
                <value>WEB-INF/jdbc.properties</value>
            </list>
        </property>
    </bean>
    
    <!-- MailSender used by EmailAdvice 
         指定用于发送邮件的 javamail 实现者,这里使用了 spring 自带的实现。此 bean 将被 emailAdvice 使用
     -->
    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="${mail.host}"/>
    </bean>
    
    
    
    <!-- ========================= BUSINESS OBJECT DEFINITIONS ======================== -->

    <!-- 不需要,因为被 SpringMVC 的实现使用 Generic validator for Account objects, to be used for example by the Spring web tier -->
    <bean id="accountValidator" class="org.springframework.samples.jpetstore.domain.logic.AccountValidator"/>
    
    <!-- 不需要,因为被 SpringMVC 的实现使用 Generic validator for Order objects, to be used for example by the Spring web tier -->
    <bean id="orderValidator" class="org.springframework.samples.jpetstore.domain.logic.OrderValidator"/>
    
    <!--
        主要的商业逻辑对象,即我们所说的门面对象
        注入了所有的DAO,这些DAO是引用了 dataAccessContext-xxx.xml 中定义的DAO
        门面对象中的所有方法的事务控制将通过下面的 aop:config 来加以控制

      - JPetStore primary business object (default implementation).
      - Transaction advice gets applied through the AOP configuration below.
   -->
    <bean id="petStore" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="categoryDao" ref="categoryDao"/>
        <property name="productDao" ref="productDao"/>
        <property name="itemDao" ref="itemDao"/>
        <property name="orderDao" ref="orderDao"/>
    </bean>
    
    
    <!-- ========================= ASPECT CONFIGURATION ======================== -->
    <!-- AOP配置,用来控制哪些方法将需要进行事务处理,采用了AspectJ 的语法 -->
    <aop:config>
        <!--
        This definition creates auto-proxy infrastructure based on the given pointcut,
        expressed in AspectJ pointcut language. Here: applying the advice named
        "txAdvice" to all methods on classes named PetStoreImpl.
    -->
        <!-- 指出在 PetStoreFacade 的所有方法都将采用 txAdvice(在紧接着的元素中定义了)事务方针,注意,我们这里虽然指定的是接口 PetStoreFacace, 但其暗示着其所有的实现类也将
        同样具有这种性质,因为本身就是实现类的方法在执行的,接口是没有方法体的。 -->
        <aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>
        
        <!--
            This definition creates auto-proxy infrastructure based on the given pointcut,
            expressed in AspectJ pointcut language. Here: applying the advice named
            "emailAdvice" to insertOrder(Order) method of PetStoreImpl
    -->
        <!-- 当执行 PetStoreFacade.insertOrder方法,该方法最后一个参数为Order类型时(其实我们的例子中只有一个 insertOrder 方法,但这告诉了我们,当我们的接口或类中有重载了的方法,
        并且各个重载的方法可能使用不同的拦截机机制时,我们可以通过方法的参数加以指定),将执行emailAdvice(在最后定义的那个元素)-->
        <aop:advisor pointcut="execution(* *..PetStoreFacade.insertOrder(*..Order))" advice-ref="emailAdvice"/>
        
    </aop:config>
    
    <!--
     
        事务方针声明,用于控制采用什么样的事务策略
        Transaction advice definition, based on method name patterns.
        Defaults to PROPAGATION_REQUIRED for all methods whose name starts with
        "insert" or "update", and to PROPAGATION_REQUIRED with read-only hint
        for all other methods.
    -->
    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="insert*"/>
            <tx:method name="update*"/>
            <tx:method name="*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    

    <!-- 拦截机,用于在适当的时机(通过AOP配置,如上面)在方法执行成功后发送邮件
      AOP advice used to send confirmation email after order has been submitted -->
    <!-- -->
    <bean id="emailAdvice" class="org.springframework.samples.jpetstore.domain.logic.SendOrderConfirmationEmailAdvice">
        <property name="mailSender" ref="mailSender"/>
    </bean>
    
    
    <!-- ========================= 忽略 REMOTE EXPORTER DEFINITIONS ======================== -->

    
</beans>
 
 
这个配置比想象的要简单的多:
Xml代码     
1. <SPAN style="FONT-SIZE: medium"><aop:config>          
2.  <!-- This definition creates auto-proxy infrastructure based on the given pointcut, expressed in AspectJ pointcut language.    
3. Here: applying the advice named        "txAdvice" to all methods on classes named PetStoreImpl. 指出在 PetStoreFacade    
4. 的所有方法都将采用 txAdvice(在紧接着的元素中定义了)事务方针,注意,我们这里虽然指定的是接口 PetStoreFacace,           
5.  但其暗示着其所有的实现类也将同样具有这种性质,因为本身就是实现类的方法在执行的,接口是没有方法体的。    -->      
6.        <aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>                  
7.  <!-- 其它拦截机-->     
8. </aop:config>  
9. </SPAN>  
1. 所有的拦截机配置都放在 <aop:config> 配置元素中.
2. 下面还是需要理解一下几个有关AOP的专用名词,不过,是挺抽象的,最好能会意出其的用意
• pointcut 切入点,比如:updateAccount 方法需要进行事务管理,则这个切入点就是“执行方法体”(execution)。Spring 所有支持的切入点类型在都在 Spring reference: 6.2.3.1. Supported Pointcut Designators 中列出了。 
• advice    要对这个切入点进行什么操作,比如事务控制 
• advisor   Spring 特有的概念,将上两个概念合到一个概念中来,即一个 advisor 包含了一个切入点及对这个切入点所实施的操作。 
因为 方法执行切入点 execution 为最常见的切入点类型,我们着重介绍一下,execution 的完全形式为:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
这是一个正则表达式,其中由 '?' 结尾的部分是可选的。翻译过来就是:
执行(方法访问修饰符? 方法返回类型 声明类型? 方法名(方法参数类型) 抛出异常?)
所有的这些都是用来定义执行切入点,即那些方法应该被侯选为切入点:
• 方法访问修饰符   即 public, private 等等 
• 方法返回类型       即方法返回的类型,如 void, String 等等 
• 声明类型                1.5的语法,现在可以先忽略它 
• 方法名                    方法的名字 
• 方法参数类型       方法的参数类型 
• 抛出异常                方法声明的抛出的异常 


例如,所有dao代码被定义在包 com.xyz.dao 及子包 com.xyz.dao.hibernate, 或者其它,如果还有的话,子包中, 里面定义的是提供DAO功能的接口或类,那么表达式:
execution(* com.xyz.dao..*.*(..))
表示切入点为:执行定义在包 com.xyz.dao 及其子包(因为 .. 所致) 中的任何方法

详细情况可以参见 Spring refernce: 6.2.3.4. Examples


因此这个表达式为执行定义在类 PetStoreFacade 及其实现类中的所有方法,采取的动作定义在 txAdvice 中. 关于该 advice 的定义,(见声明性事务控制)一节
<aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>
 
Spring 自定拦截机
来为了进行事务控制,我们只需简单地配置几下,所有的工作都由 Spring 来做。这样固然很好,但有时我们需要有我们特有的控制逻辑。因为Spring 不可能包含所有人需要的所有拦截机。所以它提供了通过程序的方式加以定制的方式。我们的项目中就有这么一个拦截机,在用户确认付款后,将定单信息通过 email 的方式发送给注册用户的邮箱中。
<aop:config>
  ...

        <!-- 当执行 PetStoreFacade.insertOrder方法,该方法最后一个参数为Order类型时(其实我们的例子中只有一个 insertOrder 方法,但这告诉了我们,当我们的接口或类中有重载了的方法,
        并且各个重载的方法可能使用不同的拦截机机制时,我们可以通过方法的参数加以指定),将执行emailAdvice(在最后定义的那个元素)-->
        <aop:advisor pointcut="execution(* *..PetStoreFacade.insertOrder(*..Order))" advice-ref="emailAdvice"/>
        
    </aop:config>
红色的注释已经说的很清楚这个 Advisor 了,它的切入点(pointcut) 为 PetStoreFacade 的 void insertOrder(Order order) 方法,采取的动作为引用的 emailAdvice, 下面我们就来看看 emailAdvice:
    <bean id="emailAdvice" class="org.springframework.samples.jpetstore.domain.logic.SendOrderConfirmationEmailAdvice">
        <property name="mailSender" ref="mailSender"/>
    </bean>
它给了这个 advice 的实现类为 logic 包中 SendOrderConfirmationEmailAdvice, 该Bean 引用了我们前面定义的邮件发送器(一个 Spring 内置的邮件发送器).

#40


可以从多个角度去考虑这个问题,①:spring是轻量级容器,所谓轻量级就是容器给予的业务逻辑对象多少种服务?spring给用户提供的服务完全有用户
自己决定,spring想用什么服务自己开启使用。但是重量级的都是只要你用就把所有
的服务都给你,不能自己定制。
容器:spring帮我们管理业务逻辑层,里边有很多业务逻辑对象,有对象就有对象的
生命周期的管理(创建,销毁)。

#41


太棒了,向楼上的高手学习了。。

#42


虽然这个贴子结完了.
但是,我也有点想法跟感叹.

如果我是面试的.如果我问了这样的问题..如果你又回答了这样的问题.

我一般是先看你的工作经历..
如果不到2年,你说这些,当然可以..

但是如果超过2年.
你回答这些,我就不能满意了..

这说明什么,??

你看了spring的书,但是没有看代码,没有调试过这个事务的代码..

这是最主要的..
你没有调试过....

#43


不错的回答啊

#44


spring的两个核心,一个是AOP,运用的系统中就是spring的事物处理机制,另个核心就是IOC,spring管理和创建对象。

#45


通过5个事务属性来控制事务.
1.传播行为,主要控制事务的边界
2.隔离等级:主要是并发时对数据同步的影响.
3.回滚规则:主要是对检查数据和运行时数据回滚
4.事务超时.超时会锁定数据表.需要事务回滚
5.只读:优化数据库

#46


了解下动态代理就明白了,其实原理很简单

#1


spring的事务是通过“声明式事务”的方式对事务进行管理,即在配置文件中进行声明,通过AOP将事务切面切入程序。最大的好处是大大减少了代码量,比如:

Transaction tx=session.getTransaction();
session.beginTransaction();
tx.commit();
tx.rollback();

等等这类代码不用在每个方法中重复的去写,简化了程序,提高了工作效率。

#2


AOP 面试时被问到spring是如何控制事务的?你是怎么回答的?

#3


有P惭愧的,用框架/了解框架原理/写框架是一个层面的事吗。

#4


引用 3 楼 forgetsam 的回复:
有P惭愧的,用框架/了解框架原理/写框架是一个层面的事吗。

有道理,如果目前拿4000块钱一个月,那么你不必懂它是怎么实现的。如果我是面试官我也会这样的问题,我觉不期许你都能知道,但如果你刚好都知道那不是太好了么

#5


引用 4 楼 whos2002110 的回复:
Quote: 引用 3 楼 forgetsam 的回复:

有P惭愧的,用框架/了解框架原理/写框架是一个层面的事吗。

有道理,如果目前拿4000块钱一个月,那么你不必懂它是怎么实现的。如果我是面试官我也会这样的问题,我觉不期许你都能知道,但如果你刚好都知道那不是太好了么


确实这样!

#6


1.IOC控制反转:控制权由对象本身转向容器,由容器对bean对象进行控制。
2.AOP面向切面编程:把具体的类创建对应的代理类,通过代理类来对具体类进行操作。
spring是一个容器,通过spring这个容器来对对象进行管理,根据配置文件来实现spring对对象的管理。
就这样理解吧,暂时我也只能这么回答,太深入我也不知道怎么说了

#7


SPRING的事务贯彻始终的

源代码没有读过
但是不管AOP还是IOC都有事务支持的

推测一下
SPRING是一个大的容器,一个大的工厂类
那么当你从SPRING中获取一个对象的时候
在建立对象的时候
先开启了事务,然后将对象给你,让 你去使用
在你方法结束后会交回对象
这个时候提交事务并关闭事务

这些操作都在框架内实现
所以只要使用了SPRING就一定会被事务所包围着

#8


面试时被问到spring是如何控制事务的?你是怎么回答的?

#9


衷心感谢以上几位的回答~!

#10


要明白事务是怎么样的一个概念,自己写事务又如何做

try{
// 业务逻辑
if(成功)
  commit();
}catch(e){
  // 出现异常
  rollback();
}

spring会捕获到你往上抛的异常,然后帮你try catch,如果发现捕获到异常,会就把connection不提交,直接回滚,所以我们在配置声明式事务的时候会有一个参数是什么异常类,默认应该是runtimexcepttion吧...

#11


去看看Java的动态代理就明白原理是怎么回事了。

#12


框架自动给你管理事务!具体是什么实现还真不清楚!

#13


一般我遇上这个问题,我就说 ,配置好了,自动回管理事务,他要是问怎么配置,我就说别人配置的。

#14


我的建议是这样的,首先回答出IOC和AOP,然后简单的简绍这两个东西,说的不需要太多,但是要达到重点,然后,直接offer,

#15


Spring是通过AOP的手段达到事务控制的,具体实现是靠spring-asm.jar和cglib.jar,因为这两个jar都提供了与动态代理有关的功能,实现运行时植入新特性的功能。类似的功能也可以通过我们手工实现,如果对字节码等概念掌握比较好,可以充分利用apache bcel库进行更为细致的功能控制。

以上内容不真实不可靠,仅供面试吹牛使用。你这么回答对方基本也不会深入问了,其实面试的人也不会具体细节的。

#16


1楼正解,温故一下!

#17


帮楼主顶起让更多人看到

#18


引用 6 楼 caochuankui 的回复:
1.IOC控制反转:控制权由对象本身转向容器,由容器对bean对象进行控制。
2.AOP面向切面编程:把具体的类创建对应的代理类,通过代理类来对具体类进行操作。
spring是一个容器,通过spring这个容器来对对象进行管理,根据配置文件来实现spring对对象的管理。
就这样理解吧,暂时我也只能这么回答,太深入我也不知道怎么说了


very  good!

#19


-- 根据上楼几位的回答,我结合了最佳的答案恍然大悟,谢谢各位神

Spring 的事务,可以说是 Spring AOP 的一种实现。

AOP面向切面编程,即在不修改源代码的情况下,对原有功能进行扩展,通过代理类来对具体类进行操作。 

spring是一个容器,通过spring这个容器来对对象进行管理,根据配置文件来实现spring对对象的管理。

spring的事务声明有两种方式,编程式和声明式。spring主要是通过“声明式事务”的方式对事务进行管理,即在配置文件中进行声明,通过AOP将事务切面切入程序,最大的好处是大大减少了代码量。
 

#20


頂 ,面試題目

#21


会用和会制造和知道里面的构造不是一个层次,比如 你知道用手机打电话,如何实现电话的不知道。

#22


This is certainly the  Runescape 3 Gold best advantage, whereby you can understand the strategic practice of a win-win game. Diablo 3 guides will help you to  Old School Runescape Gold conquer the monsters in the game field, whereby you can handle them with all ease.

#23


顶,很常见的面试问题

#24


面试时被问到spring是如何控制事务的?你是怎么回答的?采纳重点

#25


好多大神,顶礼膜拜,我连用还没学会

#26


spring有两种事务配置方式,一种是配置的事务管理器,另一种的是代码控制的事务
配置的事务管理器的方式是我们经常用到的经常会用到在配置文件中。代码控制的事务分为jdbc模板的和事务管理器的,jdbc默认自动提交,事务管理器的和咱们通常的一样会有commit  rollback等操作。闲 的时候看一下开发指南吧

#27


谁能再讲讲AOP的事情

#28


认为26楼是正解

#29


坐等给分,必须给分

#30


顶 一个,常见的面试提呀

#31


Spring 的事务,可以说是 Spring AOP 的一种实现。

AOP面向切面编程,即在不修改源代码的情况下,对原有功能进行扩展,通过代理类来对具体类进行操作。 

spring是一个容器,通过spring这个容器来对对象进行管理,根据配置文件来实现spring对对象的管理。

spring的事务声明有两种方式,编程式和声明式。spring主要是通过“声明式事务”的方式对事务进行管理,即在配置文件中进行声明,通过AOP将事务切面切入程序,最大的好处是大大减少了代码量。

#32


引用 11 楼 Inhibitory 的回复:
去看看Java的动态代理就明白原理是怎么回事了。


说实话  我看了动态代理 面试时被问到spring是如何控制事务的?你是怎么回答的?,,也不是很懂 和spring的  事务 有什么联系,,,看来我还得在修炼修炼。。。

#33


配置完成后,好像是用注解做的,事物都交给容器了,具体怎么实现还真不太了解。

#34


主要是通过配置或注解方式使用AOP扩展原有业务,当捕获到指定异常的时候就会回滚;
关键字:AOP、异常

#35


推荐一个Spring的详细教程呗

#36


spring的AOP是通过IOC来实现的,仔细体会一下,很有趣的

#37


引用 楼主 wsyangzuda 的回复:
几次面试都遇到这样的问题,解释不出来。

就知道如何使用spring这框架,却说不来其原理,惭愧。

小弟诚心求教!



面向切面编程

AOP

Aspect Oriented Program
的首字母缩写)
 
,我们知道,面向对象的
特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中
往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一
个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。
  
      
但是人们也发现,在分散代码的同时,也增加了代码的重复性。什么意思呢?比如说,
我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须
在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设
计让类与类之间无法联系,而不能将这些重复的代码统一起来。
  
    
也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后
再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,
它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入
代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是
面向切面的编程。
   
      
一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些
方法则叫切入点。有了
AOP
,我们就可以把几个类共有的代码,抽取到一个切片中,等到
需要时再切入对象中去,从而改变其原有的行为。
  
这样看来,
AOP
其实只是
OOP
的补充而已。
OOP
从横向上区分出一个个的类来,而
AOP
则从纵向上向对象中加入特定的代码。有了
AOP

OOP
变得立体了。如果加上时间维度, 
AOP
使
OOP
由原来的二维变为三维了,由平面变成立体了。从技术上来说,
AOP
基本上
是通过代理机制实现的。
   
     AOP
在编程历史上可以说是里程碑式的,对
OOP
编程是一种十分有益的补充
  

#38


原理
AOP(Aspect Oriented Programming),也就是面向方面编程的技术。AOP基于IoC基础,是对OOP的有益补充。
  AOP将应用系统分为两部分,核心业务逻辑(Core business concerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,所有大中型应用都要涉及到的持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等。
  AOP正在成为软件开发的下一个光环。使用AOP,你可以将处理aspect的代码注入主程序,通常主程序的主要目的并不在于处理这些aspect。AOP可以防止代码混乱。
  Spring framework是很有前途的AOP技术。作为一种非侵略性的、轻型的AOP framework,你无需使用预编译器或其他的元标签,便可以在Java程序中使用它。这意味着开发团队里只需一人要对付AOP framework,其他人还是像往常一样编程。
  AOP概念
  让我们从定义一些重要的AOP概念开始。
  — 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。
  — 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
  — 通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。
  — 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。
  — 引入(Introduction):添加方法或字段到被通知的类。Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现IsModified接口,来简化缓存。
  — 目标对象(Target Object):包含连接点的对象,也被称作被通知或被代理对象。
  — AOP代理(AOP Proxy):AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
  — 编织(Weaving):组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
  各种通知类型包括:
  —  Around通知:包围一个连接点的通知,如方法调用。这是最强大的通知。Aroud通知在方法调用前后完成自定义的行为,它们负责选择继续执行连接点或通过返回它们自己的返回值或抛出异常来短路执行。
  —  Before通知:在一个连接点之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
  —  Throws通知:在方法抛出异常时执行的通知。Spring提供强制类型的Throws通知,因此你可以书写代码捕获感兴趣的异常(和它的子类),不需要从Throwable或Exception强制类型转换。
  —  After returning通知:在连接点正常完成后执行的通知,例如,一个方法正常返回,没有抛出异常。
  Around通知是最通用的通知类型。大部分基于拦截的AOP框架(如Nanning和Jboss 4)只提供Around通知。
  如同AspectJ,Spring提供所有类型的通知,我们推荐你使用最为合适的通知类型来实现需要的行为。例如,如果只是需要用一个方法的返回值来更新缓存,你最好实现一个after returning通知,而不是around通知,虽然around通知也能完成同样的事情。使用最合适的通知类型使编程模型变得简单,并能减少潜在错误。例如,你不需要调用在around通知中所需使用的MethodInvocation的proceed()方法,因此就调用失败。
  切入点的概念是AOP的关键,它使AOP区别于其他使用拦截的技术。切入点使通知独立于OO的层次选定目标。例如,提供声明式事务管理的around通知可以被应用到跨越多个对象的一组方法上。 因此切入点构成了AOP的结构要素。
 拦截器(也称拦截机)
    拦截机 (Interceptor), 是 AOP (Aspect-Oriented Programming) 的另一种叫法。AOP本身是一门语言,只不过我们使用的是基于JAVA的集成到Spring 中的 SpringAOP。同样,我们将通过我们的例子来理解陌生的概念。

 接口类
Java代码     
1. <SPAN style="FONT-SIZE: medium">package com.test.TestSpring3;   
2.   
3. public interface UserService // 被拦截的接口   
4. ...{   
5.     public void printUser(String user);   
6. }   
7. </SPAN>  
 实现类
Java代码     
1. <SPAN style="FONT-SIZE: medium">package com.test.TestSpring3;   
2.   
3. public class UserServiceImp implements UserService // 实现UserService接口   
4. ...{   
5.     public void printUser(String user) ...{   
6.         System.out.println("printUser user:" + user);// 显示user   
7.     }   
8. }   
9.   
10. </SPAN>  
 AOP拦截器
Java代码     
1. <SPAN style="FONT-SIZE: medium">package com.test.TestSpring3;   
2.   
3. import org.aopalliance.intercept.MethodInterceptor;   
4. import org.aopalliance.intercept.MethodInvocation;   
5.   
6. public class UserInterceptor implements MethodInterceptor   
7. // AOP方法拦截器   
8. ...{   
9.   
10.     public Object invoke(MethodInvocation arg0) throws Throwable ...{   
11.   
12.         try ...{   
13.   
14.             if (arg0.getMethod().getName().equals("printUser"))   
15.             // 拦截方法是否是UserService接口的printUser方法   
16.             ...{   
17.                 Object[] args = arg0.getArguments();// 被拦截的参数   
18.                 System.out.println("user:" + args[0]);   
19.                 arg0.getArguments()[0] = "hello!";// 修改被拦截的参数   
20.   
21.             }   
22.   
23.             System.out.println(arg0.getMethod().getName() + "---!");   
24.             return arg0.proceed();// 运行UserService接口的printUser方法   
25.   
26.         } catch (Exception e) ...{   
27.             throw e;   
28.         }   
29.     }   
30. }   
31. </SPAN><SPAN style="FONT-SIZE: medium">   
32. </SPAN>  
 测试类
Java代码     
1. <SPAN style="FONT-SIZE: medium">package com.test.TestSpring3;   
2.   
3. import org.springframework.beans.factory.BeanFactory;   
4.   
5. import org.springframework.beans.factory.xml.XmlBeanFactory;   
6. import org.springframework.context.ApplicationContext;   
7. import org.springframework.context.support.ClassPathXmlApplicationContext;   
8. import org.springframework.context.support.FileSystemXmlApplicationContext;   
9. import org.springframework.core.io.ClassPathResource;   
10. import org.springframework.core.io.Resource;   
11. import org.springframework.web.context.support.WebApplicationContextUtils;   
12.   
13. public class TestInterceptor ...{   
14.   
15.     public static void main(String[] args) ...{   
16.         ApplicationContext ctx = new FileSystemXmlApplicationContext(   
17.                 "classpath:applicationContext.xml");   
18. //        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");       
19.            
20.         UserService us = (UserService) ctx.getBean("userService");   
21.         us.printUser("shawn");   
22.   
23.     }   
24. }</SPAN><SPAN style="FONT-SIZE: medium">   
25. </SPAN>  
 配置文件
 
   
Xml代码     
1. <SPAN style="FONT-SIZE: medium"><?xml version="1.0" encoding="UTF-8"?>  
2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">  
3. <beans>  
4.     <bean id="userServiceImp"  
5.         class="com.test.TestSpring3.UserServiceImp" />  
6.   
7.     <bean id="userInterceptor" class="com.test.TestSpring3.UserInterceptor" />  
8.   
9.     <bean id="userService"  
10.         class="org.springframework.aop.framework.ProxyFactoryBean">  
11.       <!-- 代理接口 -->  
12.         <property name="proxyInterfaces">  
13.             <value>com.test.TestSpring3.UserService</value>  
14.         </property>  
15.        <!-- 目标实现类 -->  
16.         <property name="target">  
17.             <ref local="userServiceImp" />    
18.       </property>  
19.         <!-- 拦截器 -->  
20.         <property name="interceptorNames">  
21.             <list>  
22.                 <value>userInterceptor</value>  
23.             </list>  
24.         </property>  
25.     </bean>  
26.   
27. </beans>  
28. </SPAN>  
 
 输出:
  user:shawn
   printUser---!
  printUser user:hello!

#39


结论:调用方法的时候 传入的值被拦截修改了.
拦截器中的事务管理(事务拦截机)
 如果不采用拦截机的机制时,在使用JDBC进行数据库访问时,存在两种情况: 
• 自动提交        这是JDBC驱动默认的模式,每次数据库操作(CRUD)成功完成后,都作为一个单独的事务自动提交,如果未成功完成,即抛出了 SQLException 的话,仅最近的一个操作将回滚。 
• 非自动提交    这是想更好的控制事务时需要程序地方式进行控制: 
o 在进行该事务单元的任何操作之前 setAutoCommit(false) 
o 在成功完成事务单元后 commit() 
o 在异常发生后 rollback()
自动提交模式是不被推荐的,因为每个操作都将产生一个事务点,这对于大的应用来说性能将受到影响;再有,对于常见的业务逻辑,这种模式显得无能为力。比如:
转帐,从A帐户取出100元,将其存入B帐户;如果在这两个操作之间发生了错误,那么用户A将损失了100元,而本来应该给帐户B的,却因为失败给了银行。
所以,建议在所有的应用中,如果使用 JDBC 都将不得不采用非自动提交模式(你们要能发现了在我们的 JDBC 那个例子中,我们采用的就是自动提交模式,我们是为了把精力放在JDBC上,而不是事务处理上),即我们不得不在每个方法中:
Java代码     
1. <SPAN style="FONT-SIZE: medium">try {       
2.  // 在获得连接后,立即通过调用 setAutoCommit(false) 将事务处理置为非自动提交模式  // Prepare Query to fetch the user Information          
3.      pst = conn.prepareStatement(findByName);                    
4.        // ...            conn.commit();          
5.  }  catch(Exception ex) {          
6.      conn.rollback();         
7.       throw ex;          
8.  }finally {      
9.          try {       
10.            // Close Result Set and Statement     
11.           if (rset != null) rset.close();                  
12.          if (pst != null) pst.close();                           
13.     } catch (Exception ex) {                  
14.        ex.printStackTrace();                   
15.        throw new Exception("SQL Error while closing objects = " + ex.toString());               
16. }     
17. }   
18. </SPAN>  
 这样代码在AOP的倡导者看来是“肮脏”的代码。他们认为,所有的与事务有关的方法都应当可以集中配置(见声明性事务控制),并自动拦截,程序应当关心他们的主要任务,即商业逻辑,而不应和事务处理的代码搅和在一起。

我先看看 Spring 是怎么做到拦截的:
Spring 内置支持的事务处理拦截机
这里因为要用到JpetStore项目中的代码,我们将 applicationContext.xml 全部内容列出:
<?xml version="1.0" encoding="UTF-8"?>

<!--
  - Application context definition for JPetStore's business layer.
  - Contains bean references to the transaction manager and to the DAOs in
  - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").

    Jpetstore 的应用上下文定义,包含事务管理和引用了在 dataAccessContext-local/jta.xml(具体使用了哪个要看 web.xml 中的 'contextConfigLocation' 的配置)中注册的DAO
-->
<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"
       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.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
    
    <!-- ========================= GENERAL DEFINITIONS ========================= -->

    <!-- Configurer that replaces ${...} placeholders with values from properties files 
         占位符的值将从列出的属性文件中抽取出来
     -->
    <!-- (in this case, mail and JDBC related properties) -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>WEB-INF/mail.properties</value>
                <value>WEB-INF/jdbc.properties</value>
            </list>
        </property>
    </bean>
    
    <!-- MailSender used by EmailAdvice 
         指定用于发送邮件的 javamail 实现者,这里使用了 spring 自带的实现。此 bean 将被 emailAdvice 使用
     -->
    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="${mail.host}"/>
    </bean>
    
    
    
    <!-- ========================= BUSINESS OBJECT DEFINITIONS ======================== -->

    <!-- 不需要,因为被 SpringMVC 的实现使用 Generic validator for Account objects, to be used for example by the Spring web tier -->
    <bean id="accountValidator" class="org.springframework.samples.jpetstore.domain.logic.AccountValidator"/>
    
    <!-- 不需要,因为被 SpringMVC 的实现使用 Generic validator for Order objects, to be used for example by the Spring web tier -->
    <bean id="orderValidator" class="org.springframework.samples.jpetstore.domain.logic.OrderValidator"/>
    
    <!--
        主要的商业逻辑对象,即我们所说的门面对象
        注入了所有的DAO,这些DAO是引用了 dataAccessContext-xxx.xml 中定义的DAO
        门面对象中的所有方法的事务控制将通过下面的 aop:config 来加以控制

      - JPetStore primary business object (default implementation).
      - Transaction advice gets applied through the AOP configuration below.
   -->
    <bean id="petStore" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="categoryDao" ref="categoryDao"/>
        <property name="productDao" ref="productDao"/>
        <property name="itemDao" ref="itemDao"/>
        <property name="orderDao" ref="orderDao"/>
    </bean>
    
    
    <!-- ========================= ASPECT CONFIGURATION ======================== -->
    <!-- AOP配置,用来控制哪些方法将需要进行事务处理,采用了AspectJ 的语法 -->
    <aop:config>
        <!--
        This definition creates auto-proxy infrastructure based on the given pointcut,
        expressed in AspectJ pointcut language. Here: applying the advice named
        "txAdvice" to all methods on classes named PetStoreImpl.
    -->
        <!-- 指出在 PetStoreFacade 的所有方法都将采用 txAdvice(在紧接着的元素中定义了)事务方针,注意,我们这里虽然指定的是接口 PetStoreFacace, 但其暗示着其所有的实现类也将
        同样具有这种性质,因为本身就是实现类的方法在执行的,接口是没有方法体的。 -->
        <aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>
        
        <!--
            This definition creates auto-proxy infrastructure based on the given pointcut,
            expressed in AspectJ pointcut language. Here: applying the advice named
            "emailAdvice" to insertOrder(Order) method of PetStoreImpl
    -->
        <!-- 当执行 PetStoreFacade.insertOrder方法,该方法最后一个参数为Order类型时(其实我们的例子中只有一个 insertOrder 方法,但这告诉了我们,当我们的接口或类中有重载了的方法,
        并且各个重载的方法可能使用不同的拦截机机制时,我们可以通过方法的参数加以指定),将执行emailAdvice(在最后定义的那个元素)-->
        <aop:advisor pointcut="execution(* *..PetStoreFacade.insertOrder(*..Order))" advice-ref="emailAdvice"/>
        
    </aop:config>
    
    <!--
     
        事务方针声明,用于控制采用什么样的事务策略
        Transaction advice definition, based on method name patterns.
        Defaults to PROPAGATION_REQUIRED for all methods whose name starts with
        "insert" or "update", and to PROPAGATION_REQUIRED with read-only hint
        for all other methods.
    -->
    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="insert*"/>
            <tx:method name="update*"/>
            <tx:method name="*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    

    <!-- 拦截机,用于在适当的时机(通过AOP配置,如上面)在方法执行成功后发送邮件
      AOP advice used to send confirmation email after order has been submitted -->
    <!-- -->
    <bean id="emailAdvice" class="org.springframework.samples.jpetstore.domain.logic.SendOrderConfirmationEmailAdvice">
        <property name="mailSender" ref="mailSender"/>
    </bean>
    
    
    <!-- ========================= 忽略 REMOTE EXPORTER DEFINITIONS ======================== -->

    
</beans>
 
 
这个配置比想象的要简单的多:
Xml代码     
1. <SPAN style="FONT-SIZE: medium"><aop:config>          
2.  <!-- This definition creates auto-proxy infrastructure based on the given pointcut, expressed in AspectJ pointcut language.    
3. Here: applying the advice named        "txAdvice" to all methods on classes named PetStoreImpl. 指出在 PetStoreFacade    
4. 的所有方法都将采用 txAdvice(在紧接着的元素中定义了)事务方针,注意,我们这里虽然指定的是接口 PetStoreFacace,           
5.  但其暗示着其所有的实现类也将同样具有这种性质,因为本身就是实现类的方法在执行的,接口是没有方法体的。    -->      
6.        <aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>                  
7.  <!-- 其它拦截机-->     
8. </aop:config>  
9. </SPAN>  
1. 所有的拦截机配置都放在 <aop:config> 配置元素中.
2. 下面还是需要理解一下几个有关AOP的专用名词,不过,是挺抽象的,最好能会意出其的用意
• pointcut 切入点,比如:updateAccount 方法需要进行事务管理,则这个切入点就是“执行方法体”(execution)。Spring 所有支持的切入点类型在都在 Spring reference: 6.2.3.1. Supported Pointcut Designators 中列出了。 
• advice    要对这个切入点进行什么操作,比如事务控制 
• advisor   Spring 特有的概念,将上两个概念合到一个概念中来,即一个 advisor 包含了一个切入点及对这个切入点所实施的操作。 
因为 方法执行切入点 execution 为最常见的切入点类型,我们着重介绍一下,execution 的完全形式为:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
这是一个正则表达式,其中由 '?' 结尾的部分是可选的。翻译过来就是:
执行(方法访问修饰符? 方法返回类型 声明类型? 方法名(方法参数类型) 抛出异常?)
所有的这些都是用来定义执行切入点,即那些方法应该被侯选为切入点:
• 方法访问修饰符   即 public, private 等等 
• 方法返回类型       即方法返回的类型,如 void, String 等等 
• 声明类型                1.5的语法,现在可以先忽略它 
• 方法名                    方法的名字 
• 方法参数类型       方法的参数类型 
• 抛出异常                方法声明的抛出的异常 


例如,所有dao代码被定义在包 com.xyz.dao 及子包 com.xyz.dao.hibernate, 或者其它,如果还有的话,子包中, 里面定义的是提供DAO功能的接口或类,那么表达式:
execution(* com.xyz.dao..*.*(..))
表示切入点为:执行定义在包 com.xyz.dao 及其子包(因为 .. 所致) 中的任何方法

详细情况可以参见 Spring refernce: 6.2.3.4. Examples


因此这个表达式为执行定义在类 PetStoreFacade 及其实现类中的所有方法,采取的动作定义在 txAdvice 中. 关于该 advice 的定义,(见声明性事务控制)一节
<aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>
 
Spring 自定拦截机
来为了进行事务控制,我们只需简单地配置几下,所有的工作都由 Spring 来做。这样固然很好,但有时我们需要有我们特有的控制逻辑。因为Spring 不可能包含所有人需要的所有拦截机。所以它提供了通过程序的方式加以定制的方式。我们的项目中就有这么一个拦截机,在用户确认付款后,将定单信息通过 email 的方式发送给注册用户的邮箱中。
<aop:config>
  ...

        <!-- 当执行 PetStoreFacade.insertOrder方法,该方法最后一个参数为Order类型时(其实我们的例子中只有一个 insertOrder 方法,但这告诉了我们,当我们的接口或类中有重载了的方法,
        并且各个重载的方法可能使用不同的拦截机机制时,我们可以通过方法的参数加以指定),将执行emailAdvice(在最后定义的那个元素)-->
        <aop:advisor pointcut="execution(* *..PetStoreFacade.insertOrder(*..Order))" advice-ref="emailAdvice"/>
        
    </aop:config>
红色的注释已经说的很清楚这个 Advisor 了,它的切入点(pointcut) 为 PetStoreFacade 的 void insertOrder(Order order) 方法,采取的动作为引用的 emailAdvice, 下面我们就来看看 emailAdvice:
    <bean id="emailAdvice" class="org.springframework.samples.jpetstore.domain.logic.SendOrderConfirmationEmailAdvice">
        <property name="mailSender" ref="mailSender"/>
    </bean>
它给了这个 advice 的实现类为 logic 包中 SendOrderConfirmationEmailAdvice, 该Bean 引用了我们前面定义的邮件发送器(一个 Spring 内置的邮件发送器).

#40


可以从多个角度去考虑这个问题,①:spring是轻量级容器,所谓轻量级就是容器给予的业务逻辑对象多少种服务?spring给用户提供的服务完全有用户
自己决定,spring想用什么服务自己开启使用。但是重量级的都是只要你用就把所有
的服务都给你,不能自己定制。
容器:spring帮我们管理业务逻辑层,里边有很多业务逻辑对象,有对象就有对象的
生命周期的管理(创建,销毁)。

#41


太棒了,向楼上的高手学习了。。

#42


虽然这个贴子结完了.
但是,我也有点想法跟感叹.

如果我是面试的.如果我问了这样的问题..如果你又回答了这样的问题.

我一般是先看你的工作经历..
如果不到2年,你说这些,当然可以..

但是如果超过2年.
你回答这些,我就不能满意了..

这说明什么,??

你看了spring的书,但是没有看代码,没有调试过这个事务的代码..

这是最主要的..
你没有调试过....

#43


不错的回答啊

#44


spring的两个核心,一个是AOP,运用的系统中就是spring的事物处理机制,另个核心就是IOC,spring管理和创建对象。

#45


通过5个事务属性来控制事务.
1.传播行为,主要控制事务的边界
2.隔离等级:主要是并发时对数据同步的影响.
3.回滚规则:主要是对检查数据和运行时数据回滚
4.事务超时.超时会锁定数据表.需要事务回滚
5.只读:优化数据库

#46


了解下动态代理就明白了,其实原理很简单