Spring事务处理及其AOP框架的内幕

     Spring框架中成功吸引人的一点就是 容器事务的管理,提供了一个轻量级的容器事务处理, 针对的对象是普通的java类,使用Spring事务管理的话 ,你可以按照自己的业务把一些相关的方法纳入其事务管理里面,这就避免了程序员在处理事务的过程中繁琐的工作.同时这些也是ejb2.X规范里 面吸引人的一点,这在spring里面都很好的提供. 虽然在跨容器的事务管理,spring里面并没有提供,但是对于一般的web程序来说,也不需要仅仅 为了那些功能而不得不使用ejb.不过,最近jboss的嵌入式的ejb容器也可以做的更小了,也是开源中的选择之一.无论技术是怎样发展的,当前,我 们先来研究其中AOP实现的方法.
  
  事实上,Spring中的事务处理是通过AOP思想来实现的,Spring AOP与Aspect J和JBoss具有很 大的不同,首先,使用Spring AOP框架的用户要记住的一点是, Spring AOP针对的是方法层次上的实现,而其他两者对字段也提供了支持.

说到 Spring AOP的内幕,其实也不难 :

对于有接口的类,使用的是Java内部类提供的Proxy;

而对于那些不实现接口的类,使用的是cglib库,动态创建一个子类来实现.

  在Spring AOP中提供了4种处理切入类型:around,before,after,introduction.顾名思义,
  
    1)around是针对具体的某个切入点的方法(比如,现在有个OrderBook方法,around的切入类型是就这个方法的内部调用,是通过java 的元数据,在 运行时通过Method.invoke来调用,具有返回值,当发生意外的时候会终止.记住的一点是,返回值.);
  
  2)before是在方法调用前 调用(在OrderBook方法前调用,但是没有返回值,同时在通常意外情况下,会继续运行下一步方法.记住的一点是没有返回值);
  
   3)after和before刚好相反,没有什么特别的地方.
  
   4)introduction是一个更加特殊的,但功能更加强大的切入类型.比如(你现 在有Book对象,Computer对象,还有几十个这种业务对象,现在你希望在每个这样的对象中都加入一个记录最后修改的时间.但是你又不希望对每 个类都进行修改,因为太麻烦了,同时更重要的一点,破坏了对象的完整性,说不定你以后又不需要这个时间数据了呢...这时怎么办呢?Spring AOP就为你专门实现这种思想提供了一个切入处理,那就是introduction.introduction可以为你动态加入某些方法,这样可以在运行 时,强制转换 这些对象,进行插入时间数据的动作,更深的内幕就是C++虚函数中的vtable思想).不过这种动态是以性能作为代价的,使用之前要慎重考虑,这里 我们谈的是技术,所以就认为他是必需的.
  
  好,现在我们就拿第四种来进行举例说明Spring AOP的强大之处:
  
   1)假设创建了一个BookService接口及其实现方法(你自己的业务对象):
  
   package  com.osiris.springaop;
  
 
public   interface  BookService  {
      
public String OrderComputerMagazine(String userName,String bookName);
      
public String OrderBook(String userName,String bookName);
  }

  
   package  com.osiris.springaop;
   
  
public   class  BookServiceImpl  implements  BookService {
      
public String OrderBook(String name,String bookName) {
          String result
=null;
          result
="订购"+bookName+"成功";
          
return result;
      }

      
      
public String OrderComputerMagazine(String userName, String bookName) {
          String result
=null;
          result
="订购"+bookName+"成功";
          
return result;
      }

  }

  
 2)事实上你还有很多这样的对象,现在我们希望在每个对象中添加我们的功能最后修改的时间,功能如下:
  
   package  com.osiris.springaop.advices.intruduction;
  
  
import  java.util.Date;
  
  
public   interface  IAuditable  {
      
void setLastModifiedDate(Date date);
      Date getLastModifiedDate();
  }

  
  3)因为我们使用的切入类型是introduction,Spring AOP为我们提供了一个描述这种类型的接口IntroductionInterceptor,所以我们的切入实现处理,也需要实现这个接口:
  
     package  com.osiris.springaop.advices.intruduction;
  
  
import  java.util.Date;
  
  
import  org.aopalliance.intercept.MethodInvocation;
  
import  org.springframework.aop.IntroductionInterceptor;
  
  
public   class  AuditableMixin  implements  IAuditable,IntroductionInterceptor {
      
private Date lastModifiedDate;
      
      
public Object invoke(MethodInvocation m) throws Throwable {
          
// TODO Add your codes here
          if(implementsInterface(m.getMethod().getDeclaringClass())){
              
return m.getMethod().invoke(this,m.getArguments());
              
//invoke introduced mthod,here is IAuditable
          }
else{
              
return m.proceed(); //delegate other method
          }

      }

      
      
public Date getLastModifiedDate() {
          
// TODO Add your codes here
          return lastModifiedDate;
      }

      
      
public void setLastModifiedDate(Date date) {
          
// TODO Add your codes here
          lastModifiedDate=date;
      }

      
      
public boolean implementsInterface(Class cls) {
          
// TODO Add your codes here
          return cls.isAssignableFrom(IAuditable.class);
      }

  }

  4)ok,现在业务对象BookService类有了,自己希望添加的处理也有了IAuditable,那就剩下使用Spring AOP框架的问题了,配置bean.xml文件:
  
   <? xml version = " 1.0 "  encoding = " UTF-8 " ?>
  
<! DOCTYPE beans PUBLIC  " -//SPRING//DTD BEAN//EN "   " http://www.springframework.org/dtd/spring-beans.dtd " >
  
< beans >
      
<!--  Beans  -->
      
< bean id = " BookServiceTarget "   class = " com.osiris.springaop.BookServiceImpl "  singleton = " false " />
      
      
<!--  introduction advice  -->
      
< bean id = " AuditableMixin "   class = " com.osiris.springaop.advices.intruduction.AuditableMixin "  singleton = " false " />
      
      
<!--  Introduction advisor  -->
      
< bean id = " AuditableAdvisor "   class = " org.springframework.aop.support.DefaultIntroductionAdvisor "   singleton = " false " >
          
< constructor - arg >
              
< ref bean = " AuditableMixin " />
          
</ constructor - arg >
      
</ bean >
      
      
< bean id = " BookService "   class = " org.springframework.aop.framework.ProxyFactoryBean " >
          
< property name = " target " >
              
< ref bean = " BookServiceTarget " />
          
</ property >
          
          
< property name = " singleton " >
              
< value > false </ value >
          
</ property >
          
          
<!--  force to use cglib  -->
          
< property name = " proxyTargetClass " >
              
< value > true </ value >
          
</ property >
          
          
<!--  introduction methods  -->
          
< property name = " proxyInterfaces " >
              
< value > com.osiris.springaop.advices.intruduction.IAuditable </ value >
          
</ property >
          
          
< property name = " interceptorNames " >
              
< list >
                  
< value > AuditableAdvisor </ value >
              
</ list >
          
</ property >
      
</ bean >
  
</ beans >

  以上就是配置文件,现在我们假设使用业务对象如下,这里是一个简单测试类:
  
   package  com.osiris.springaop;
  
  
import  java.util.Date;
  
  
import  org.springframework.beans.factory.BeanFactory;
  
import  org.springframework.beans.factory.xml.XmlBeanFactory;
  
import  org.springframework.core.io.FileSystemResource;
  
  
import  com.osiris.springaop.advices.intruduction.IAuditable;
  
  
public   class  MainApp  {
  
/**
  * 
@param args
  * 
@author Kerluse Benn
  
*/

  
public static void main(String[] args) throws Exception{
  
// TODO Add your codes here
  BeanFactory factory=new XmlBeanFactory(new FileSystemResource("bean.xml"));

  BookService bookService
=(BookService)factory.getBean("BookService");
  IAuditable auditable
=(IAuditable)bookService;

  System.out.print(bookService.OrderBook(
"Kerluse Benn","Professional C#"));
  auditable.setLastModifiedDate(
new Date());
  System.out.println(
" 订购时间为"+auditable.getLastModifiedDate());
  Thread.sleep(
10000);

  System.out.print(bookService.OrderBook(
"Kerluse Benn","Expert j2ee one-on-one"));
  auditable.setLastModifiedDate(
new Date());
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值