SpringAop与AspectJ的联系与区别____比较分析 Spring AOP 和 AspectJ 之间的差别

SpringAop与AspectJ的联系与区别

区别

AspectJ

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

spring aop

Spring提供了四种类型的Aop支持
* 基于经典的SpringAOP
* 纯POJO切面
* @ASpectJ注解驱动的切面
* 注入式AspectJ切面(其实与Spring并无多大的关系,这个就是使用AspectJ这个框架实现Aop编程)

基于经典的SpringAop

其使用ProxyFactoryBean创建:
增强(通知)的类型有:
前置通知:org.springframework.aop.MethodBeforeAdvice
后置通知:org.springframework.aop.AfterReturningAdvice
环绕通知:org.aopalliance.intercept.MethodInterceptor
异常通知:org.springframework.aop.ThrowsAdvice

public interface IBookDao {public int add()public int delete();
}public class BookDaoImpl implements IBookDao{public int add() {System.out.println("正在添加图书...");return 0;}public int delete() {System.out.println("正在删除图书...");return 0;}
}//实现了MethodInterceptor的环绕增强类
public class MyAdvice implements MethodInterceptor{public Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("Around Advice before method invocation");Object o = invocation.proceed();System.out.println("Around Advice after method invocation");return o;}
}
//将每一个连接点都当做切点(拦截每一个方法)
<bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean><bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean><bean id="bookDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="bookDao"/><property name="proxyInterfaces" value="com.njust.learning.spring.service.IBookDao"/><property name="interceptorNames" value="myadvice"/></bean>12345678910
使用RegexMethodPointcutAdvisor针对某些特定的方法进行拦截增强
<bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean><bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean><bean id="rmpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><!--patterns,如果有多个指定的值的话,可以使用,隔开,例如value=".*add,.*delete"--><property name="patterns" value=".*add"/><property name="advice" ref="myadvice"/></bean>
<!--使用的时候使用这个id,而不是原始的那个id--><bean id="bookDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="bookDao"/><property name="proxyInterfaces" value="com.njust.learning.spring.service.IBookDao"/><property name="interceptorNames" value="rmpAdvisor"/></bean>
注意

像上面这样,每定义一个dao都需要定义一个ProxyFactoryBean,显得很麻烦,所以我们引入自动代理,也就是自动创建代理对象

BeanNameAutoProxyCreator

<bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean><bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean><bean id="rmpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><!--patterns,如果有多个指定的值的话,可以使用,隔开,例如value=".*add,.*delete"--><property name="patterns" value=".*add"/><property name="advice" ref="myadvice"/></bean><bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><property name="beanNames" value="*Dao"></property><property name="interceptorNames" value="rmpAdvisor"></property></bean>

DefaultAdvisorAutoProxyCreator

<bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean><bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean><bean id="rmpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><!--patterns,如果有多个指定的值的话,可以使用,隔开,例如value=".*add,.*delete"--><property name="patterns" value=".*add"/><property name="advice" ref="myadvice"/></bean><!--根据切面中生成信息生成代理--><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>1234567891011

纯POJO切面,需要使用XML进行配置

public interface IBookDao {public int add();public int delete();
}public class BookDaoImpl implements IBookDao{public int add() {int a = 1/0;System.out.println("正在添加图书...");return 0;}public int delete() {System.out.println("正在删除图书...");return 0;}
}
public class PojoAdvice {public void before(){System.out.println("前置通知");}public void after(Object returnval){System.out.println("后置通知"+",处理后的结果为:"+returnval);}public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("环绕前置增强...");Object o = proceedingJoinPoint.proceed();System.out.println("环绕后置增强...");return o;}public void afterThrowing(Throwable e){System.out.println("异常通知:"+e.getMessage());}
}
<bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean><bean id="pojoAdvice" class="com.njust.learning.spring.pojoaop.PojoAdvice"></bean><aop:config><aop:pointcut id="p" expression="execution (* *.add(..))"/><aop:aspect ref="pojoAdvice"><aop:before method="before" pointcut-ref="p"></aop:before><!--通过设置returning来将返回值传递给通知--><aop:after-returning method="after" pointcut-ref="p" returning="returnval"/><aop:around method="around" pointcut-ref="p"/><!--通过设置returning来将异常对象传递给通知--><aop:after-throwing method="afterThrowing" pointcut-ref="p" throwing="e"/></aop:aspect></aop:config>

联系

我们借助于Spring Aop的命名空间可以将纯POJO转换为切面,实际上这些POJO只是提供了满足切点的条件时所需要调用的方法,但是,这种技术需要XML进行配置,不能支持注解
所以spring借鉴了AspectJ的切面,以提供注解驱动的AOP,本质上它依然是Spring基于代理的AOP,只是编程模型与AspectJ完全一致,这种风格的好处就是不需要使用XML进行配置




比较分析 Spring AOP 和 AspectJ 之间的差别

AOP(Aspect OrientedProgramming, 面向切面/方面编程) 旨在从业务逻辑中分离出来横切逻辑【eg:性能监控、日志记录、权限控制等】,提高模块化,即通过AOP解决代码耦合问题,让职责更加单一。

运用技术:

​ SpringAOP使用了两种代理机制,一种是基于JDK的动态代理,另一种是基于CGLib的动态代理,之所以需要两种代理机制,很大程度上是因为JDK本身只提供基于接口的代理,不支持类的代理。

切面植入的方法:

  1. 编译期织入

  2. 类装载期织入

  3. 动态代理织入---->在运行期为目标类添加增强生成子类的方式,Spring AOP采用动态代理织入切面

流行的框架:

AOP现有两个主要的流行框架,即Spring AOP和Spring+AspectJ

img

二者的区别:

1、 织入的时期不同

Spring Aop采用的动态织入,而Aspectj是静态织入。静态织入:指在编译时期就织入,即:编译出来的class文件,字节码就已经被织入了。动态织入又分静动两种,静则指织入过程只在第一次调用时执行;动则指根据代码动态运行的中间状态来决定如何操作,每次调用Target的时候都执行。有不清楚的同学,可以自己补下基础的代理知识

2、从使用对象不同

Spring AOP的通知是基于该对象是SpringBean对象才可以,而AspectJ可以在任何Java对象上应用通知。

Spring AOP:如果你想要在通过this对象调用的方法上应用通知,那么你必须使用currentProxy对象,并调用其上的相应方法;于此相似,如果你想要在某对象的方法上应用通知,那么你必须使用与该对象相应的Spring bean

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

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

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

明确你在应用横切关注点(cross-cutting concern)时(例如事物管理、日志或性能评估),需要处理的是Spring beans还是POJO。如果正在开发新的应用,则选择Spring AOP就没有什么阻力。但是如果你正在维护一个现有的应用(该应用并没有使用Spring框架),AspectJ就将是一个自然的选择了。为了详细说明这一点,假如你正在使用Spring AOP,当你想将日志功能作为一个通知(advice)加入到你的应用中,用于追踪程序流程,那么该通知(Advice)就只能应用在Spring beans的连接点(Joinpoint)之上

例子:在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 methodApplicationContext beans =newClassPathXmlApplicationContext("appbeans.xml");MyServices myServices = (MyServices) beans.getBean("myServices");myServices.service(); // Logging advice applied here

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

例如:

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

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

// MyServices service methodpublic 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 hereApplicationContext beans =newClassPathXmlApplicationContext("appbeans.xml");MyObject obj =(MyObject) beans.getBean("myObject");obj.performOperation()// Logging advice applied here}

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

另一个需要考虑的因素是,你是希望在编译期间进行织入(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)织入。

因为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 filepublic final classMyServicesImpl {---}

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

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

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

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

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

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

http://www.oschina.net/translate/comparative_analysis_between_spring_aop_and_aspectj?cmp

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/556233.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ssrf漏洞内网渗透_渗透小白看了也能明白的SSRF

什么是SSRF含义服务器端请求伪造&#xff08;SSRF&#xff09;是指攻击者能够从易受攻击的Web应用程序发送精心设计的请求的对其他网站进行攻击。(利用一个可发起网络请求的服务当作跳板来攻击其他服务)攻击者能够利用目标帮助攻击者访问其他想要攻击的目标攻击者要求服务器为他…

高并发之服务降级和服务熔断____服务降级、熔断、限流的区别

高并发之服务降级和服务熔断 服务降级&#xff1a; 服务压力剧增的时候根据当前的业务情况及流量对一些服务和页面有策略的降级&#xff0c;以此环节服务器的压力&#xff0c;以保证核心任务的进行。 同时保证部分甚至大部分任务客户能得到正确的相应。也就是当前的请求处理…

Controller数据导出Excel 详细教程——easypoi-base,easypoi-web,easypoi-annotation

Controller获取数据导出Excel&#xff0c;详细教程 1&#xff1a;导入对应依赖 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>4.1.3</version></dependency><dependency&g…

01 - java 开始

Java 的优势 java适合做web后台 java配置环境的时候 java的安装目录&#xff1a;JAVA_HOMEjdk的安装目录&#xff1a;%JAVA_HOME%\bin java的执行机制 先将.java的文件用 javac 编译成 .class的字节码文件再将这些 .class 的字节码文件用 java 执行&#xff08;执行的是文…

15 - java 继承

java继承 This > Son Super > Father Object 类是所有类的顶级父类 只要创建一个类默认都会继承这个顶级父类 – Object 在子类继承父类里面 构造器必须先构造一个父类&#xff08;先有爸爸&#xff0c;才有儿子&#xff09;&#xff0c;必须首先构造父类&#xff0…

easyPOI基本用法详解

文章目录easyPOI基本用法1.Excel文件的简单导入和导出1.1准备工作1.2导入1.3导出1.4图片的导出1.5图片的导入1.6excel模板导出文件1.7excel转html2.Word文件导出2.1使用word模板导出2.2使用word模板导出多页3.excel导入时验证3.1环境准备3.2实战演练3.3注意事项easyPOI基本用法…

16 - java 类加载顺序

类的加载顺序 类对象、静态变量是存在元空间的方法区&#xff0c;实例对象是new出来的&#xff0c;放在堆里面的 一个类加载到内存的完整过程 加载父类 --> 加载子类 --> 构造父类 --> 构造子类 class文件要从磁盘加载到内存形成对象 内存靠地址去取寻址 – 随机存…

360全景倒车影像怎么看_别克关怀-后视镜和倒车影像 倒车时到底看哪个

很多人在考驾照的时候&#xff0c;倒车倒的都很熟练&#xff0c;但是一上路就不行了。一方面&#xff0c;这是因为道路上的状况多变&#xff0c;时常有行人经过&#xff0c;另一方面&#xff0c;上路之后&#xff0c;遇见的停车位千奇百怪&#xff0c;什么样子的都有&#xff0…

17 - 引用类型比较内容

引用数据类型比较 引用数据类型直接比较一定是 false --> 比较的是它俩的地址 Animail a1 new Animal(); Animail a2 new Animal(); System.out.println(a1 a2); //false特殊的 String String s1 "a"; String s2 "a"; System.out.println(s1 s…

springboot使用jxls导出excel___(万能通用模板)--- SpringBoot导入、导出Excel文件___SpringBoot整合EasyExcel模板导出Excel

springboot使用jxls导出excel 实现思路&#xff1a; 首先在springBoot(或者SpringCloud)项目的默认templates目录放入提前定义好的Excel模板&#xff0c;然后在具体的导出接口业务代码里通过IO流加载到这个Excel模板文件&#xff0c;读取指定的工作薄(也就是excel左下角的Shee…

idea(mac) 使用收集

其实 idea 后面的 webstorm phpstorm pycharm… 都大同小异 idea 使用积累1. 设置代码区字体大小2. command​ 滚轮改变字体大小3. 去掉代码区中间的白线4. 查看项目配置5. 自动删除类中无用包、自动导入包6. 显示行号和方法分隔符7. 提示的时候忽略大小写8. 统一显示 utf - 8…

epp是什么意思_什么是1K/2K/3K注塑?

ABC小词条的出现是因为公众号后台大家留言提问的名词很多&#xff0c;我们每周挑一个成本分析相关的小知识点&#xff0c;可能是工艺&#xff0c;成本方法&#xff0c;产品方面等话题&#xff0c;来做一个简短的ABC解释&#xff0c;如有错误欢迎指出。文末会提出一个问题&#…

facebook对话链接_Facebook已开源其最新的聊天机器人Blender

它是一种更具人性化的聊天机器人&#xff0c;并击败了Google成为世界上最好的聊天机器人> Photo by Alex Haney on Unsplash4月29日&#xff0c;Facebook AI Research(FAIR)宣布已构建并开源了一个新的聊天机器人Blender。最先进的开源聊天机器人Facebook AI拥有开源的Blend…

基于easypoi实现自定义模板导出excel

项目中需要做一个统计报表功能&#xff0c;实现各种Excel报表数据导出。要求表头能够动态配置&#xff0c;表数据通过存储过程实现&#xff0c;也要求能够动态配置。 技术选型&#xff1a; 由于之前在项目中使用过easypoi&#xff0c;相对于原生apache poi&#xff0c;能够用很…

vb6 datagrid表格垂直居中_老板不喜欢看你的Excel表格,学完这些美化技巧,早日升职加薪...

Excel报表是工作中经常要制作的&#xff0c;给老板看的表格越是简单明了越好&#xff0c;工作得到认可&#xff0c;给你升职加薪&#xff0c;如果你发给你老板的表格是这样的&#xff1a;对齐方式各种各样&#xff0c;数据看起来也很枯燥&#xff0c;仅需简单4点&#xff0c;轻…

Java接口修饰符详解

接口就是提供一种统一的”协议”&#xff0c;而接口中的属性也属于“协议”中的成员。它们是公共的&#xff0c;静态的&#xff0c;最终的常量。相当于全局常量。抽象类是不“完全”的类&#xff0c;相当于是接口和具体类的一个中间层。即满足接口的抽象&#xff0c;也满足具体…

查看论坛隐藏链接_软连接与硬链接的区别

点击上方蓝色“后端开发杂谈”关注我们, 专注于后端日常开发技术分享硬链接与软连接的联系与区别文件都有文件名和数据, 这在Linux上被分为两部分: 用户数据(user data) 与 元数据(metadata). 用户数据, 即文件数据块( data block), 数据块是记录文件真实内容的地方; 元数据是文…

java日志框架JUL、JCL、Slf4j、Log4j、Log4j2、Logback 一网打尽

为什么程序需要记录日志 我们不可能实时的24小时对系统进行人工监控&#xff0c;那么如果程序出现异常错误时要如何排查呢&#xff1f;并且系统在运行时做了哪些事情我们又从何得知呢&#xff1f;这个时候日志这个概念就出现了&#xff0c;日志的出现对系统监控和异常分析起着…

如何从一张图片里取出其中一部分_如何鉴别坑人的锌合金龙头

01.对大部分人而言&#xff0c;锌合金龙头是一个熟悉又陌生的词儿。当我们提起锌合金龙头时&#xff0c;很多人会一脸茫然的回答&#xff1a;啥&#xff1f;锌合金龙头&#xff1f;没听过&#xff01;不认识&#xff01;但在日常生活中锌合金龙头的出现率可不低&#xff01;不信…

SpringBoot框架中各层(DTO、DAO、Service、Controller)理解

粗略理解 View层→Controller层&#xff08;响应用户请求&#xff09;→Service层&#xff08;接口→接口实现类&#xff09;→DAO层&#xff0c;即Mapper层&#xff08;抽象类&#xff1a;xxxMapper.java文件&#xff0c;具体实现在xxxMapper.xml&#xff09;→Model层&#…