`
thaIm
  • 浏览: 90201 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Spring --- AOP II

阅读更多
一)Spring AOP---schema-based approach
  Spring AOP的配置方式,我强烈推荐这篇博客http://pandonix.iteye.com/blog/336873。作者对AOP的概念和Spring AOP的xml配置实现都做了清晰的介绍。我想我是不可能做更好的介绍了...这里就再作几点补充说明吧~~

二)动态代理
  要说动态代理,就得先说静态代理。动静都是比较出来的嘛~~
  静态代理:
public interface UserDAO {
  public void saveUser(User user);
}
public class UserDAOImp implements UserDAO{
  public void saveUser(User user) {
    ……
  }
}
//静态代理。代理了接口UserDAO下的所有实现类,例如UserDAOImp
public class UserDAOProxy implements UserDAO {
  private UserDAO userDAO;
  public UserDAOProxy(UserDAO userDAO) {
    this.userDAO = userDAO;
  }
  public void saveUser(User user) {
    UserTransaction tx = null;
    try {
      tx = (UserTransaction) (new InitialContext().lookup("java/tx"));
      userDAO.saveUser(user);
      tx.commit();
    } catch (Exception ex) {
      if (null!=tx){
        try {
          tx.rollback();
        }catch(Exception e) {
        }
      }
    }
  }
}

    UserDAOProxy和UserDAOImp一样,同样是UserDAO接口的实现,对于调用者而言,saveUser方法的使用完全相同,不同的是内部实现机制已经发生了一些变化――我们在UserDAOProxy中为UserDAO.saveUser方法套上了一个JTA事务管理的外壳。
    很显然这样的结构设计,代理类只能代理某一个特定的接口(例子中是UserDAO接口)。现在假设系统中有20个类似的接口,针对每个接口实现一个Proxy,实在是个繁琐无味的苦力工程。所以我们需要一种设计能将接口也作为参数动态的传入,以实现对任意接口的动态代理!
    动态代理
public class AOPFactory {
  private static Log logger = LogFactory.getLog(AOPFactory.class);

  public static Object getClassInstance(String clzName){
    Class cls;
    try {
      cls = Class.forName(clzName);
      return (Object)cls.newInstance();
    } catch (Exception e) {
      logger.debug(e);
      throw new AOPRuntimeException(e);
    } 
  }
  
  public static Object getAOPProxyedObject(String clzName){
    AOPHandler txHandler = new AOPHandler();
    Object obj = getClassInstance(clzName);
    return txHandler.bind(obj);//返回动态代理类!!
  }
}

  AOPFactory就是Spring最后实现动态代理的一个精简示意。getClassInstance()首先通过反射机制将配置文件中的String转换成响应的Object。而后txHandler.bind()将根据obj生成响应的动态代理返回。显然,动态代理的核心逻辑就在AOPHandler类中。下面让我们看看,它到底是如何实现的:
public class AOPHandler implements InvocationHandler {
  private static Log logger = LogFactory.getLog(AOPHandler.class);
  private List interceptors = null;
  private Object originalObject;

  public Object bind(Object obj) {
    this.originalObject = obj;
    return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), this);
  }

  /**
  * 在Invoke方法中,加载对应的Interceptor,并进行
  * 预处理(before)、后处理(after)以及异常处理(exceptionThrow)过程
  */
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object result = null;
    Throwable ex = null;
    InvocationInfo invInfo = new InvocationInfo(proxy, method, args,result, ex);
    logger.debug("Invoking Before Intercetpors!");
    invokeInterceptorsBefore(invInfo);
    try {
      logger.debug("Invoking Proxy Method!");
      result = method.invoke(originalObject, args);
      invInfo.setResult(result);
      logger.debug("Invoking After Method!");
      invokeInterceptorsAfter(invInfo);
    } catch (Throwable tr) {
      invInfo.setException(tr);
      logger.debug("Invoking exceptionThrow Method!");
      invokeInterceptorsExceptionThrow(invInfo);
      throw new AOPRuntimeException(tr);
    }
    return result;
  }

  private synchronized List getIntercetors() {
    if (null == interceptors) {
      interceptors = new ArrayList();
      //Todo:读取配置,加载Interceptor实例
       //interceptors.add(new MyInterceptor());
    }
    return interceptors;
  }

  private void invokeInterceptorsBefore(InvocationInfo invInfo) {
    List interceptors = getIntercetors();
    int len = interceptors.size();
    for (int i = 0; i < len; i++) {
      ((Interceptor) interceptors.get(i)).before(invInfo);
    }
  }

  private void invokeInterceptorsAfter(InvocationInfo invInfo) {
    List interceptors = getIntercetors();
    int len = interceptors.size();
    for (int i = len - 1; i >= 0; i--) {
      ((Interceptor) interceptors.get(i)).after(invInfo);
    }
  }

  private void invokeInterceptorsExceptionThrow(InvocationInfo invInfo) {
    List interceptors = getIntercetors();
    int len = interceptors.size();
    for (int i = len - 1; i >= 0; i--) {
      ((Interceptor)interceptors.get(i)).exceptionThrow(invInfo);
    }
  }
}

    1'首先说说public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
    注意:例子中InvocationHandler h传的是this。所以当获得动态代理后调用userDAO.saveUser时(假设我们的动态代理要代理的是userDAO接口),代理会调用AOPHandler.invoke来处理相应的逻辑。
    此外newProxyInstance生产的动态代理类是无需我们手动编码参与的,程序会自动生成于内存中。这个自动生成的类就相当于上例静态代理中的UserDAOProxy,只是因为它在内存中我们看不见其源码罢了。
    2'再说说,getIntercetors()。它严格来说和动态代理没什么关系。只是因为动态代理是接口名、接口内需要实现的方法名都不确定,所以在代理的前后处理时也不可避免的需要一些“动态”逻辑,需要采用反射机制。所以这里专门做了一些处理。和InvocationInfo 一样,具体的细节可以不关注。重点应该在AOPHandler本身。
    3'介绍完了动态代理,我们可以发现一个结论:虽然动态代理的设计大大增加了代理的灵活型,但它仍然对被代理的类有一个限制:此类必须继承一个接口以供动态代理实现生成代理类!而CGLIB则进一步去除了这个限制

三)CGLIB
    Spring中,引入了CGLib作为无接口情况下的动态代理实现。
    CGLib与Dynamic Proxy的代理机制基本类似,只是其动态生成的代理对象并非某个接口的实现,而是针对目标类扩展的子类。

    与Dynamic Proxy中的Proxy和InvocationHandler相对应,Enhancer和MethodInterceptor在CGLib中负责完成代理对象创建和方法截获处理。下面是通过CGLib进行动态代理的示例代码:
public class AOPInstrumenter implements MethodInterceptor {
  private static Log logger = LogFactory.getLog(AOPInstrumenter.class);
  private Enhancer enhancer = new Enhancer();
  public Object getInstrumentedClass(Class clz) {
    enhancer.setSuperclass(clz);
    enhancer.setCallback(this);
    return enhancer.create();
  }
  public Object intercept(Object o, Method method,Object[] methodParameters,MethodProxy methodProxy)throws Throwable {
    logger.debug("Before Method =>"+method.getName());
    Object result = methodProxy.invokeSuper(o, methodParameters);
    logger.debug("After Method =>"+method.getName());
    return result;
  }
}

测试代码:
AOPInstrumenter aopInst = new AOPInstrumenter();
UserDAOImp userDAO = (UserDAOImp) aopInst.getInstrumentedClass(UserDAOImp.class);
User user = new User();
user.setName("Erica");
userDAO.saveUser(user);

四)写好pointcut
    对于pointcut的表达式,spring是参照AspectJ pointcut designators (PCD)的标准来做的。当然,由于AOP方面spring并没有AspectJ来得这么强大(spring只支持针对方法method的切面编程),所以在pointcut表达式上实际上也是取了PCD的一个子集而已。下面先说说PCD语法的几个关键字:
  execution:(对符合条件的方法)执行AOP
  within:在(满足条件的类型)内执行AOP (由于spring只支持方法层的AOP,所以spring中的within可以进一步解释为:对满足条件的类的方法执行AOP)
  this:指动态代理类本身
  target:指被动态代理类代理的对象(还是由于spring只支持方法层的AOP,而代理和被代理类的方法名肯定是一样的,所以spring中的this和target关键字几乎可以混用。)
  args:对满足此参数条件的方法执行AOP

    execution是spring最常用的表达式,下面我们详加说明:
    此表达式的格式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?) 

modifiers-pattern:修饰符类型(public protect private)
ret-type-pattern:返回值类型
declaring-type-pattern:对象类型
name-pattern:方法名
parm-pattern:参数名
throws-pattern:异常

    其中,除ret-type-pattern,name-pattern和parameters-pattern之外,其他都是可选的。比如:
    execution(public * *(..)) 表示所有public的方法
    execution(* set*(..))  表示所有方法名以set开头的方法
    execution(* com.xyz.service.AccountService.*(..))  表示接口AccountService内的所有方法
    execution(* com.spring.service.*.*(..)) 表示com.spring.service包下,返回值为任意类型;方法名任意;参数不作限制的所有方法。
    execution(* com.xyz.service..*.*(..))  表示com.xyz.service包及其子包下,返回值为任意类型;方法名任意;参数不作限制的所有方法。

    再来说说within:
    within(com.xyz.service.*)  表示com.xyz.service包下所有的joint point(spring的话就是指com.xyz.service包下所有的方法了)
   within(com.xyz.service..*)  表示com.xyz.service包及其子包下所有的joint point(spring的话就是指com.xyz.service包及其子包下所有的方法了)

    下面是this:
    this(com.xyz.service.AccountService) 表示代理了接口com.xyz.service.AccountService的动态代理下的所有joint point
   
    target:
     target(com.xyz.service.AccountService)  表示接口com.xyz.service.AccountService下的所有joint point

    args:
    args(java.io.Serializable)表示对所有传入参数是java.io.Serializable的方法执行AOP

注:1'最后说一种spring特有的,唯一不在PCD范围内的表达式:bean(idOrNameOfBean)
       bean(*Service) 对以Service结尾的bean执行AOP
    2'Spring AOP所有的pointcut都是针对public方法的。对应proctect private的方法无法使用AOP. 如果需要对protect和private的方法进行AOP,可以使用Spring-driven native AspectJ weaving。
   
  • 大小: 25.6 KB
分享到:
评论

相关推荐

    spring-aop.jar各个版本

    spring-aop-1.1.1.jar spring-aop-1.2.6.jar spring-aop-1.2.9.jar spring-aop-2.0.2.jar spring-aop-2.0.6.jar spring-aop-2.0.7.jar spring-aop-2.0.8.jar spring-aop-2.0.jar spring-aop-2.5.1.jar spring-aop-...

    开发工具 spring-aop-4.3.6.RELEASE

    开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE...

    spring-aop-5.2.0.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-5.2.0.RELEASE.jar; 赠送原API文档:spring-aop-5.2.0.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.2.0.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.2.0.RELEASE.pom;...

    spring-aop-5.0.8.RELEASE-API文档-中英对照版.zip

    赠送jar包:spring-aop-5.0.8.RELEASE.jar; 赠送原API文档:spring-aop-5.0.8.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.0.8.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.0.8.RELEASE.pom;...

    spring-aop-5.3.10-API文档-中文版.zip

    赠送jar包:spring-aop-5.3.10.jar; 赠送原API文档:spring-aop-5.3.10-javadoc.jar; 赠送源代码:spring-aop-5.3.10-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.3.10.pom; 包含翻译后的API文档:spring...

    spring-aop-jar

    aopalliance.jar、spring-aop-4.1.6.RELEASE.jar、spring-aspects-4.1.6.RELEASE.jar

    spring-aop-5.0.10.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-5.0.10.RELEASE.jar; 赠送原API文档:spring-aop-5.0.10.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.0.10.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.0.10.RELEASE....

    spring-aop-5.3.12-API文档-中英对照版.zip

    赠送jar包:spring-aop-5.3.12.jar; 赠送原API文档:spring-aop-5.3.12-javadoc.jar; 赠送源代码:spring-aop-5.3.12-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.3.12.pom; 包含翻译后的API文档:spring...

    spring-aop-3.2.5.RELEASE.jar ;spring-aop-3.2.5.jar

    spring-aop-3.2.5.RELEASE.jar

    spring-aop-5.1.3.RELEASE-API文档-中英对照版.zip

    赠送jar包:spring-aop-5.1.3.RELEASE.jar; 赠送原API文档:spring-aop-5.1.3.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.1.3.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.1.3.RELEASE.pom;...

    spring-aop-4.0.4.RELEASE

    spring-aop-4.0.4.RELEASE 的jar包,亲测可用。。。。

    spring-aop-5.1.0.RELEASE.jar

    spring-**core**-4.3.6.RELEASE.jar :包含spring框架基本的核心工具类,spring其他组件都要用到这个包里的类,其他组件的基本核心 spring-**beans**-4.3.6.RELEASE.jar:所有应用都要用到的jar包,它包含访问配置...

    spring-aop-5.0.4.RELEASE.jar

    spring-aop-5.0.4.RELEASE.jar。

    spring-aop-4.3.20.RELEASE-API文档-中英对照版.zip

    赠送jar包:spring-aop-4.3.20.RELEASE.jar 赠送原API文档:spring-aop-4.3.20.RELEASE-javadoc.jar 赠送源代码:spring-aop-4.3.20.RELEASE-sources.jar 包含翻译后的API文档:spring-aop-4.3.20.RELEASE-...

    spring-aop-3.2.0.RELEASE.jar

    spring-aop-3.2.0.RELEASE.jar,一个Spring中AOP的jar包

    spring-aop-2.0.8.jar

    spring-aop-2.0.8.jar

    spring-aop-4.2.2.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-4.2.2.RELEASE.jar; 赠送原API文档:spring-aop-4.2.2.RELEASE-javadoc.jar; 赠送源代码:spring-aop-4.2.2.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-4.2.2.RELEASE.pom;...

    Spring5 框架 ---- AOP ---- 代码

    Spring5 框架 ---- AOP ---- 代码 Spring5 框架 ---- AOP ---- 代码 Spring5 框架 ---- AOP ---- 代码 Spring5 框架 ---- AOP ---- 代码 Spring5 框架 ---- AOP ---- 代码 Spring5 框架 ---- AOP ---- 代码 Spring5 ...

    spring-aop-5.2.15.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-5.2.15.RELEASE.jar; 赠送原API文档:spring-aop-5.2.15.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.2.15.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.2.15.RELEASE....

    spring-aop-5.0.1.RELEASE.jar

    spring-aop-5.0.1.RELEASE.jar

Global site tag (gtag.js) - Google Analytics