AOP:Aspect Oriented Programming 面向切面编程。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。AOP只是一种编程思想,不要想太多。

相信很多朋友在第一次接触AOP的时候是很懵逼的,从到学到尾都不太清楚?我是谁我在哪?笔者初学的时候也是一样,但是对于AOP我们又不得不去深入了解一下,因为热爱(生活所迫)是吧!这篇文章也是我对于SSM深入剖析的开篇,最近事情太多了文章可能做不到源码级别的深度,但是正确认识Aop是没有问题的,告别蒙蔽是没问题的!?

?看了一眼IOC和AOP的源码,得花点时间来整理,?莽着看实在是太头疼了!

下面就由浅入深来剖析一下Aop的特性和原理。

Aop应用场景

  • 事务管理、性能监视、安全检查、缓存 、日志等

Aop术语

1.target:目标类,需要被代理的类。例如:UserService
2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3.PointCut 切入点:已经(我让他加强)被增强的连接点。例如:addUser()
4.advice 通知/增强,增强代码。例如:after、before
5.Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6.proxy 代理类
7. Aspect(切面): 是切入点pointcut(被增强的方法)和通知advice(增强方法)的结合(连线)
一个切入点和一个通知,组成成一个特殊的面。

这张图画的很好直接拿来用了。


这里基本上可以引出一个设计模式:代理模式,不清楚的可以看我以前的博客设计模式—代理模式,代理可以分为动态和静态代理,AOP里面主要使用了cglib的动态代理。具体代理实现我就不在这里多做介绍了!

实现一个AOP

介绍顺序:半自动—全自动—xml方式—注解方式。

半自动代理实现
/*** * @author 作者xianglei:* * @version 创建时间:2019年4月3日 下午7:36:33 com.dxl.aspect*  切面类* */public class MyAspect implements MethodInterceptor {public Object invoke(MethodInvocation arg0) throws Throwable {System.out.println("前");// 手动执行目标方法Object obj = arg0.proceed();System.out.println("后");return obj;}}/*** * @author 作者xianglei:* * @version 创建时间:2019年4月3日 下午7:30:40 com.xianglei.service** */public interface PersonService {void add();void update();void delete();
}/*** * @author 作者xianglei:* * @version 创建时间:2019年4月3日 下午7:39:04 com.dxl.test** */public class BanZdTest {public static void main(String[] args) {ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("SpringB.xml");PersonService bean = (PersonService) classPathXmlApplicationContext.getBean("proxyServiceId");bean.add();bean.delete();bean.update();}
}

配置文件

<!-- 1 被增强的目标类 --><bean id="userServiceId" class="com.quanzidong.service.impl.PersonServiceImpl"></bean>  <!-- bean 注入只能是类 --><!-- 2 创建切面类 设定通知类型 --><bean id="myAspectId" class="com.dxl.aspect.MyAspect"></bean><!-- 3 代理类处理 链接(织入)过程 --><bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="interfaces" value="com.dxl.service.PersonService"></property>   <!--必须是一个接口 --><property name="target" ref="userServiceId"></property><property name="interceptorNames" value="myAspectId"></property></bean>

ProxyFactoryBean类是隶属Spring框架下的一个代理类。使用Spring提供的类ProxyFactoryBean是创建AOP的最基本的方式。用的不多了解就行

这里的配置文件里面注入了目标类和切面类对着上面那个图片来看 org.springframework.aop.framework.ProxyFactoryBean 这个类就是实现了了一个(代理)织入的过程。你只需要给他注入 interfaces,target,interceptorNames便可以实现对目标类的方法的增强。

全自动实现Aop
public class MyAspect implements MethodInterceptor {public Object invoke(MethodInvocation arg0) throws Throwable {System.out.println("前");// 手动执行目标方法Object obj = arg0.proceed();System.out.println("后");return obj;}}public interface PersonService {void add();void update();void delete();
}public class PersonServiceImpl implements PersonService {public void add() {System.out.println("添加");}public void update() {System.out.println("更新");}public void delete() {System.out.println("删除");}}
public class c {public static void main(String[] args) {ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("SpringQ.xml");PersonService bean = (PersonService) classPathXmlApplicationContext.getBean("userServiceId");bean.add();bean.delete();bean.update();}
}

配置文件

 <!-- 1 被增强的目标类 --><bean id="userServiceId" class="com.quanzidong.service.impl.PersonServiceImpl"></bean>  <!-- bean 注入只能是类 --><!-- 2 创建切面类 设定通知类型 --><bean id="myAspectId" class="com.quanzidong.aspect.MyAspect"></bean><!-- true 使用cglib --><aop:config proxy-target-class="true"><!-- aop:pointcut 我想要增强的点 --><aop:pointcut expression="execution(* com.quanzidong.service.*.*(..))"id="myPointCut" /><!-- 拿哪些内容增强到哪些方法 --><aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut" /></aop:config>

这个和前面那个半自动的比起来有什么区别呢?咋就成了全自动了?全自动体现在:**不需要通过id获取代理类了(getBean(“class”)),直接在执行被增强的方法时执行增强(注意两处代理的getbean的区别)。**也就是你拿你要用的对象,调用需要调用的方法,其他的交给天意。?


AOP的基础的使用,上面的方法其实就已经可以实现了,但懒惰是永无止境的,于是有了用注解的方式来将各种bean的管理通过扫包交给Spring框架管理。

AspectJ注解技术实现AOP

@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面。新版本Spring框架,建议使用AspectJ方式来开发AOP。
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

先来个代码尝尝咸淡?

  • Xml方式实现

      * 配置切面类 (重复执行代码形成的类)* aop配置拦截哪些方法 / 拦截到方法后应用通知代码
    
package com.xml.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;/*** * @author 作者xianglei:* * @version 创建时间:2019年4月3日 下午8:10:27 com.xml.aspect* * */public class MyAspect {public void myBefore(JoinPoint joinPoint) {System.out.println("前置通知 : " + joinPoint.getSignature().getName());}public void myAfterReturning(JoinPoint joinPoint, Object ret) {System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);}public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("环绕:前");// 手动执行目标方法Object obj = joinPoint.proceed();System.out.println("环绕:后");return obj;}public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {System.out.println("抛出异常通知 : " + e.getMessage());}public void myAfter(JoinPoint joinPoint) {System.out.println("最终通知");}}package com.xml.service;/*** * @author 作者xianglei:* * @version 创建时间:2019年4月3日 下午7:30:40 com.xianglei.service** */public interface PersonService {void add();void update();void delete();
}/*** * @author 作者xianglei:* * @version 创建时间:2019年4月3日 下午7:30:40 com.xianglei.service** */public class PersonServiceimpl implements com.xml.service.PersonService {public void add() {System.out.println("添加");}public void update() {// TODO Auto-generated method stubSystem.out.println("更新");}public void delete() {// TODO Auto-generated method stubSystem.out.println("删除");}}
public class test {public static void main(String[] args) {ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("Springxml.xml");PersonService bean = (PersonService) classPathXmlApplicationContext.getBean("userServiceId");bean.add();bean.delete();bean.update();}
}
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 1 被增强的目标类 --><bean id="userServiceId" class="com.xml.service.impl.PersonServiceimpl"></bean>  <!-- bean 注入只能是类 --><!-- 2 创建切面类 设定通知类型 --><bean id="myAspectId" class="com.xml.aspect.MyAspect"></bean><!-- 不使用cglib proxy-target-class="false"--><aop:config ><aop:aspect ref="myAspectId"><aop:pointcut expression="execution(* com.xml.service.*.*(..))" id="myPointCut"/><!-- 3.1 前置通知 <aop:before method="" pointcut="" pointcut-ref=""/>method : 通知,及方法名pointcut :切入点表达式,此表达式只能当前通知使用。pointcut-ref : 切入点引用,可以与其他通知共享切入点。通知方法格式:public void myBefore(JoinPoint joinPoint){参数1:org.aspectj.lang.JoinPoint  用于描述连接点(目标方法),获得目标方法名等例如:--><aop:before method="myBefore" pointcut-ref="myPointCut"/><!-- 3.2后置通知  ,目标方法后执行,获得返回值<aop:after-returning method="" pointcut-ref="" returning=""/>returning 通知方法第二个参数的名称通知方法格式:public void myAfterReturning(JoinPoint joinPoint,Object ret){参数1:连接点描述参数2:类型Object,参数名 returning="ret" 配置的例如:--><aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" /><!-- 3.3 环绕通知 <aop:around method="" pointcut-ref=""/>通知方法格式:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{返回值类型:Object方法名:任意参数:org.aspectj.lang.ProceedingJoinPoint抛出异常执行目标方法:Object obj = joinPoint.proceed();例如:--><aop:around method="myAround" pointcut-ref="myPointCut"/><!-- 3.4 抛出异常<aop:after-throwing method="" pointcut-ref="" throwing=""/>throwing :通知方法的第二个参数名称通知方法格式:public void myAfterThrowing(JoinPoint joinPoint,Throwable e){参数1:连接点描述对象参数2:获得异常信息,类型Throwable ,参数名由throwing="e" 配置例如:--><aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/><!-- 3.5 最终通知 -->         <aop:after method="myAfter" pointcut-ref="myPointCut"/></aop:aspect></aop:config></beans>

xml方式实现的你就的先关注xml配置文件,看不懂?没关系补充几个知识点。

AspectJ 通知类型
  • before:前置通知(应用:各种校验)
    在方法执行前执行,如果通知抛出异常,阻止方法运行
  • afterReturning:后置通知(应用:常规数据处理)
    方法正常返回后执行,如果方法中抛出异常,通知无法执行
    必须在方法执行后才执行,所以可以获得方法的返回值。
  • around:环绕通知(应用:十分强大,可以做任何事情)
    方法执行前后分别执行,可以阻止方法的执行
    必须手动执行目标方法
  • afterThrowing:抛出异常通知(应用:包装异常信息)
    方法抛出异常后执行,如果方法没有抛出异常,无法执行
  • after:最终通知(应用:清理现场)
    方法执行完毕后执行,无论方法中是否出现异常
表达式语言
语法:execution(修饰符  返回值  包.类.方法名(参数) throws异常)修饰符,一般省略public     公共方法*           任意返回值,不能省略void           返回没有值String     返回值字符串*             任意包,[省略]com.xianglei.crm         固定包com.xianglei.crm.*.service   crm包下面子包任意 (例如:com.xianglei.crm.staff.service)com.xianglei.crm..           crm包下面的所有子包(含自己)com.xianglei.crm.*.service..  crm包下面任意子包,固定目录service,service目录任意包类,[省略]UserServiceImpl           指定类*Impl                    以Impl结尾User*                    以User开头*                        任意方法名,不能省略addUser                    固定方法add*                        以add开头*Do                       以Do结尾*                      任意(参数)()                        无参(int)                     一个整型(int ,int)                  两个(..)                      参数任意
  • 注解方式实现
@Component   // 在此处声明一个Component 是因为Spring扫描注解并不能识别AspectJ 因此在此处声明
@Aspect
public class MyAspect {@Before("execution(* com.anno.service.impl.*(..))")//@Before("execution(* com.anno.service.impl.*(..))")public void myBefore(JoinPoint joinPoint) {System.out.println("前置通知 : " + joinPoint.getSignature().getName());}/*    // 可以声明公共切入点 然后通过value设定切入点@Pointcut("execution(*com.anno.service.impl.*(..))")private void myPointCut() {}@AfterReturning(value="myPointCut()" ,returning="ret")public void myAfterReturning(JoinPoint joinPoint, Object ret) {System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);}*/public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("环绕:前");// 手动执行目标方法Object obj = joinPoint.proceed();System.out.println("环绕:后");return obj;}public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {System.out.println("抛出异常通知 : " + e.getMessage());}public void myAfter(JoinPoint joinPoint) {System.out.println("最终通知");}}

这里你可以设置一个公共切入点,其他通知就可以通过设置value来联系这个切入点,不用也行。二选一。

@Service
public class PersonServiceImpl implements PersonService {public void add() {System.out.println("添加");}public void update() {// TODO Auto-generated method stubSystem.out.println("更新");}public void delete() {// TODO Auto-generated method stubSystem.out.println("删除");}}public class Test {public static void main(String[] args) {ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("Springanno.xml");PersonService bean = (PersonService) classPathXmlApplicationContext.getBean("personServiceImpl");bean.add();bean.delete();bean.update();}
}

配置文件

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 1.扫描 注解类 --><context:component-scan base-package="com.anno"></context:component-scan><!-- 2.确定 aop注解生效 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy><!--<bean  id="aspectBean" class="com.anno.aspect.MyAspect"></bean> 手动注入切面类-->
</beans>

配置文件看起来简洁了许多,但是注解方式有一个缺点就是对源码的侵入性比起xml方式要大一些,毕竟xml方式在不需要AOP的时候不使用就行了。
这里就两点,一个是包扫描:让Spring知道哪些组件分别对应了哪些类。一个是开启Aspect的注解,使@Aspect注解生效。

官方关于开启AspectJ支持可以使用一下两种方法。

抛俩问题?
  • SpringAOP 和AspectJ有什么关系
    Spring是借助AspectJ的语法来实现自己的Aop Spring自己的那一套用起来很很蛋疼。+
  • SpringAop和Aop有什么区别
    前者只是实现Aop的一种手段,后者是AOP思想的最终目标。

总结

回看这篇文章你应该知道了 1.AOP实现原理,2. AOP的xml和注解使用方式。3.清楚了AOP的基本术语。

Spring Aop: 从醉生梦死到豁然开朗相关推荐

  1. Spring AOP介绍及源码分析

    2019独角兽企业重金招聘Python工程师标准>>> 软件开发经历了从汇编语言到高级语言和从过程化编程到面向对象编程:前者是为了提高开发效率,而后者则使用了归纳法,把具有共性的东西 ...

  2. 手撸Spring系列8:Spring AOP(理论篇)

    说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...

  3. Spring AOP + Redis解决重复提交的问题

    Spring AOP + Redis解决重复提交的问题 用户在点击操作的时候,可能会连续点击多次,虽然前端可以通过设置按钮的disable的属性来控制按钮不可连续点击,但是如果别人拿到请求进行模拟,依 ...

  4. 利用Spring AOP与JAVA注解为系统增加日志功能

    Spring AOP一直是Spring的一个比较有特色的功能,利用它可以在现有的代码的任何地方,嵌入我们所想的逻辑功能,并且不需要改变我们现有的代码结构. 鉴于此,现在的系统已经完成了所有的功能的开发 ...

  5. Spring AOP的一些概念

            切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象.事务管理是J2EE应用中一个关于横切关注点的很好的例子. 在Spring AOP中,切面可以使用通用类(基于模 ...

  6. Spring AOP与IOC

    Spring AOP实现日志服务 pom.xml需要的jar <dependency><groupId>org.apache.commons</groupId>&l ...

  7. Spring AOP与IOC以及自定义注解

    Spring AOP实现日志服务 pom.xml需要的jar <dependency><groupId>org.apache.commons</groupId>&l ...

  8. Spring Aop的应用

    2019独角兽企业重金招聘Python工程师标准>>> AOP的基本概念 连接点( Jointpoint) : 表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化.方法执行 ...

  9. Spring AOP详解(转载)所需要的包

    上一篇文章中,<Spring Aop详解(转载)>里的代码都可以运行,只是包比较多,中间缺少了几个相应的包,根据报错,几经百度搜索,终于补全了所有包. 截图如下: 在主测试类里面,有人怀疑 ...

最新文章

  1. Xamarin.Forms的相对布局RelativeLayout
  2. 自学python需要下载什么软件-一篇告诉你为什么人人都应该学点Python?
  3. vivo 2019:关于企业文化如何影响手机企业发展的三个追问
  4. Service生命周期
  5. 企业应用“数据优先”革命的下一个主战场:安全与运营
  6. 理科卷math·english·chinese·biology·chemistry·physics
  7. CPU 是如何执行任务的?
  8. 用python批量下载网络图片_python批量下载图片的三种方法
  9. 如何设计一个优秀基表结构
  10. 区块链应用如何实现资金盘分红
  11. cad 打开硬件加速卡_CAD:“你的图纸缺少shx字体!”“不存在的!”
  12. python中pandas库的作用_python之pandas库详解
  13. 自动驾驶常见英文缩写
  14. 笔记本电脑禁用自带键盘
  15. 蚁群算法画图java_[转载]简单蚁群算法 + JAVA实现蚁群算法
  16. 网络基础笔记(三)二层交换机工作原理、单点故障与链路聚合、DHCP
  17. 计算机函数vlookup套用,vlookup函数应用实例(一)
  18. 传统推荐算法Facebook的GBDT+LR模型深入理解
  19. 1.初识JAVA概念、配置开发环境
  20. 齐次Markov链的遍历性判定

热门文章

  1. mac使用Sourcetree托管代码流程
  2. 找不到文件direct12.h
  3. 磨人小问题-偶遇神奇解决方法(3)——关于win10专业版勒索软件防护感叹号且忽略点不了和提示设置onedrive
  4. 图片转换工具类 base64、Uri转String
  5. 字体“XX”不支持样式“Regular”。
  6. 媒:克里米亚被俄军控制 48小时内决定走势
  7. TP4056锂电池充电IC
  8. 9 Django 的模型层2
  9. 【第12章】网络安全审计技术原理与应用 (信息安全工程师)
  10. 百度地图离线开发demo-测距(vue+百度地图3.0+百度瓦片)