zoukankan      html  css  js  c++  java
  • 比较分析 Spring AOP 和 AspectJ 之间的差别

    面向方面的编程(AOP) 是一种编程范式,旨在通过允许横切关注点的分离,提高模块化。AOP提供方面来将跨越对象关注点模块化。虽然现在可以获得许多AOP框架,但在这里我们要区分的只有两个流行的框架:Spring AOP和AspectJ。这里将会帮助你基于一些关键信息,为你的项目选择正确的技术。

    Spring AOP不同于大多数其他AOP框架。Spring AOP的目的并不是为了提供最完整的AOP实现(虽然Spring AOP具有相当的能力);而是为了要帮助解决企业应用中的常见问题,提供一个AOP实现与Spring IOC之间的紧密集成。由于Spring AOP是容易实现的,如果你计划在Spring Beans之上将横切关注点模块化,Spring的这一目标将是要点之一。但同样的目标也可能成为一个限制,如果你用的是普通的Java对象而不是Spring beans,并基于此将横切关注点模块化的话。另一方面,AspectJ可用于基于普通Java对象的模块化,但在实施之前需要良好的关于这个主题的知识。

    super0555
    super0555
    翻译于 3年前
    3人顶
     翻译得不错哦!
     

    在决定使用哪种框架实现你的项目之前,有几个要点可以帮助你做出合适的选择(同样适用于其他框架)。

    Spring AOP致力于提供一种能够与Spring IoC紧密集成的面向方面框架的实现,以便于解决在开发企业级项目时面临的常见问题。明确你在应用横切关注点(cross-cutting concern)时(例如事物管理、日志或性能评估),需要处理的是Spring beans还是POJO。如果正在开发新的应用,则选择Spring AOP就没有什么阻力。但是如果你正在维护一个现有的应用(该应用并没有使用Spring框架),AspectJ就将是一个自然的选择了。为了详细说明这一点,假如你正在使用Spring AOP,当你想将日志功能作为一个通知(advice)加入到你的应用中,用于追踪程序流程,那么该通知(Advice)就只能应用在Spring beans的连接点(Joinpoint)之上。

    bearkidult
    bearkidult
    翻译于 3年前
    4人顶
     翻译得不错哦!
     

    例子:在appbeans.xml中配置如下的切入点(pointcut),那么当调用myServices bean的service方法时就将应用日志通知(advice)。

    <!—Configuration snippet in appbeans.xml -->
    
      <bean id="myServices" class="com.ashutosh.MyServicesImpl " />
    
      <aop:config>
    
        <aop:aspect id="loggingAspect" ref="logging">
    
           <aop:around method="log" pointcut="execution(public * *(..))"/>
    
       </aop:aspect>
    
     </aop:config --> 
    
    // Java file calling service method
    
    ApplicationContext beans =newClassPathXmlApplicationContext("appbeans.xml");
    
    MyServices myServices = (MyServices) beans.getBean("myServices");
    
    myServices.service(); // Logging advice applied here

    看一下日志通知将要被应用处的注释,在这里应用程序将记录被调用方法的详细信息。但是,当你在service()方法中调用同一个类中的其他方法时,如果你没有使用代理对象,那么日志通知就不会被应用到这个方法调用上。

    例如:

    // MyServices service method
    
    public void service() {
    
      performOperation();// Logging advice not going to apply here
    
    }

    如果你想要在通过this对象调用的方法上应用通知,那么你必须使用currentProxy对象,并调用其上的相应方法。

    // MyServices service method
    
    public void service() {
    
      // Logging advice going to apply here
    
      ((MyServices) AopContext.currentProxy()).performOperation();
    
    }

    于此相似,如果你想要在某对象的方法上应用通知,那么你必须使用与该对象相应的Spring bean。

    public void service() {
    
      MyObject obj = new MyObject();
    
      Obj.performOperation();// Logging advice not going to apply here
    
    }

    如果你想要应用该通知,那么上述代码必须修改为如下形式。

    public void service() {
    
      MyObject obj = new MyObject();
    
     Obj.performOperation();// Logging advice not going to apply here
    
     ApplicationContext beans =newClassPathXmlApplicationContext("appbeans.xml");
    
     MyObject obj =(MyObject) beans.getBean("myObject");
    
     obj.performOperation()// Logging advice applied here
    
    }

    于此不同,使用“AspectJ”你可以在任何Java对象上应用通知,而不需要在任何文件中创建或配置任何bean。

    bearkidult
    bearkidult
    翻译于 3年前
    3人顶
     翻译得不错哦!
     

    另一个需要考虑的因素是,你是希望在编译期间进行织入(weaving),还是编译后(post-compile)或是运行时(run-time)。Spring只支持运行时织入。如果你有多个团队分别开发多个使用Spring编写的模块(导致生成多个jar文件,例如每个模块一个jar文件),并且其中一个团队想要在整个项目中的所有Spring bean(例如,包括已经被其他团队打包了的jar文件)上应用日志通知(在这里日志只是用于加入横切关注点的举例),那么通过配置该团队自己的Spring配置文件就可以轻松做到这一点。之所以可以这样做,就是因为Spring使用的是运行时织入。

    <!—Configuration -->
    
    <bean id="myServices" class="com.ashutosh.MyServicesImpl " />
    
     <aop:config>
    
      <aop:aspect id="loggingAspect" ref="logging">
    
          <aop:around method="log" pointcut="execution(public * *(..))"/>
    
      </aop:aspect>
    
    </aop:config -->

    如果你使用AspectJ想要做到同样的事情,你也许就需要使用acj(AspectJ编译器)重新编译所有的代码并且进行重新打包。否则,你也可以选择使用AspectJ编译后(post-compile)或载入时(load-time)织入。

    bearkidult
    bearkidult
    翻译于 3年前
    3人顶
     翻译得不错哦!
     

    因为Spring基于代理模式(使用CGLIB),它有一个使用限制,即无法在使用final修饰的bean上应用横切关注点。因为代理需要对Java类进行继承,一旦使用了关键字final,这将是无法做到的。

    例如,在Spring bean MyServicesImpl上使用关键字final,并配置一个“execution(public * *(..))”这样的切入点,将导致运行时异常(exception),因为Spring不能为MyServicesImpl生成代理。

    // Configuration file
    
    <bean id="myServices" class="com.ashutosh.MyServicesImpl" />
    
    //Java file
    
    public final classMyServicesImpl {
    
      ---
    
    }

    在这种情况下,你也许会考虑使用AspectJ,其支持编译期织入且不需要生成代理。

    于此相似,在static和final方法上应用横切关注点也是无法做到的。因为Spring基于代理模式。如果你在这些方法上配置通知,将导致运行时异常,因为static和final方法是不能被覆盖的。在这种情况下,你也会考虑使用AspectJ,因为其支持编译期织入且不需要生成代理。

    bearkidult
    bearkidult
    翻译于 3年前
    2人顶
     翻译得不错哦!
     

    你一定希望使用一种易于实现的方式。因为Spring AOP支持注解,在使用@Aspect注解创建和配置方面时将更加方便。而使用AspectJ,你就需要通过.aj文件来创建方面,并且需要使用ajc(Aspect编译器)来编译代码。所以如果你确定之前提到的限制不会成为你的项目的障碍时,使用Spring AOP。

    使用AspectJ的一个间接局限是,因为AspectJ通知可以应用于POJO之上,它有可能将通知应用于一个已配置的通知之上。对于一个你没有注意到这方面问题的大范围应用的通知,这有可能导致一个无限循环。

    bearkidult
    bearkidult
    翻译于 3年前
    2人顶
     翻译得不错哦!
     

    例如,创建一个包含如下切入点的方面。

    public aspectLogging {
    
      Object around() : execution(public * * (..))
    
      Sysytem.out.println(thisJoinPoint.getSignature());
    
      return proceed();
    
    }

    在这种情况下,当proceed即将被调用时,日志通知会被再次应用,这样就导致了嵌套循环。

    所以,如果你希望在Spring bean上采取比较简单的方式应用横切关注点时,并且这些bean没有被标以final修饰符,同时相似的方法也没有标以static或final修饰符时,就使用Spring AOP吧。相比之下,如果你需要在所提到的限制之上应用横切关注点,或者要在POJO上应用关注点,那么就使用AspectJ。你也可能选择同时使用两种方法,因为Spring支持这样。

    参考链接:http://docs.spring.io/spring/docs/3.0.x/reference/aop.html

  • 相关阅读:
    背水一战 Windows 10 (26)
    背水一战 Windows 10 (25)
    背水一战 Windows 10 (24)
    背水一战 Windows 10 (23)
    背水一战 Windows 10 (22)
    背水一战 Windows 10 (21)
    背水一战 Windows 10 (20)
    背水一战 Windows 10 (19)
    背水一战 Windows 10 (18)
    背水一战 Windows 10 (17)
  • 原文地址:https://www.cnblogs.com/soundcode/p/6493156.html
Copyright © 2011-2022 走看看