AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。

  一 AOP的基本概念

  (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知

  (2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用

  (3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

  (4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

  (5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

  如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

  二 Spring AOP

  Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。

  三 基于注解的AOP配置方式

  1.启用@AsjectJ支持

  在applicationContext.xml中配置下面一句:

  

  2.通知类型介绍

  (1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可

  (2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值

  (3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名

  来访问目标方法中所抛出的异常对象

  (4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式

  (5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint

  3.例子:

  spring框架 AOP核心详解

  (1)Operator.java -- 切面类

  @Componentbr/@Aspect

  public class Operator {

  @Pointcut(execution( com.aijava.springcode.service...*(..)))

  public void pointCut(){}

  @Before(pointCut())

  public void doBefore(JoinPoint joinPoint){

  System.out.println(AOP Before Advice...);

  }

  @After(pointCut())

  public void doAfter(JoinPoint joinPoint){

  System.out.println(AOP After Advice...);

  }

  @AfterReturning(pointcut=pointCut(),returning=returnVal)

  public void afterReturn(JoinPoint joinPoint,Object returnVal){

  System.out.println(AOP AfterReturning Advice: + returnVal);

  }

  @AfterThrowing(pointcut=pointCut(),throwing=error)

  public void afterThrowing(JoinPoint joinPoint,Throwable error){

  System.out.println(AOP AfterThrowing Advice... + error);

  System.out.println(AfterThrowing...);

  }

  @Around(pointCut())

  public void around(ProceedingJoinPoint pjp){

  System.out.println(AOP Aronud before...);

  try {

  pjp.proceed();

  } catch (Throwable e) {

  e.printStackTrace();

  }

  System.out.println(AOP Aronud after...);

  }

  }

  (2)UserService.java -- 定义一些目标方法

  @Service

  public class UserService {

  public void add(){

  System.out.println(UserService add());

  }

  public boolean delete(){

  System.out.println(UserService delete());

  return true;

  }

  public void edit(){

  System.out.println(UserService edit());

  int i = 5/0;

  }

  }

  (3).applicationContext.xml

  

  

  (4).Test.java

  public class Test {

  public static void main(String[] args) {

  ApplicationContext ctx = new ClassPathXmlApplicationContext(classpath:applicationContext.xml);

  UserService userService = (UserService) ctx.getBean(userService);

  userService.add();

  }

  }

  上面是一个比较简单的测试,基本涵盖了各种增强定义。注意:做环绕通知的时候,调用ProceedingJoinPoint的proceed()方法才会执行目标方法。

  4.通知执行的优先级

  进入目标方法时,先织入Around,再织入Before,退出目标方法时,先织入Around,再织入AfterReturning,最后才织入After。

  注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用!同时使用也没啥意义。

  如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

  5.切入点的定义和表达式

  切入点表达式的定义算是整个AOP中的核心,有一套自己的规范

  Spring AOP支持的切入点指示符:

  (1)execution:用来匹配执行方法的连接点

  A:@Pointcut(execution( com.aijava.springcode.service...*(..)))

  第一个表示匹配任意的方法返回值,..(两个点)表示零个或多个,上面的第一个..表示service包及其子包,第二个表示所有类,第三个*表示所有方法,第二个..表示

  方法的任意参数个数

  B:@Pointcut(within(com.aijava.springcode.service.*))

  within限定匹配方法的连接点,上面的就是表示匹配service包下的任意连接点

  C:@Pointcut(this(com.aijava.springcode.service.UserService))

  this用来限定AOP代理必须是指定类型的实例,如上,指定了一个特定的实例,就是UserService

  D:@Pointcut(bean(userService))

  bean也是非常常用的,bean可以指定IOC容器中的bean的名称

  后言: spring 的环绕通知和前置通知,后置通知有着很大的区别,主要有两个重要的区别:

  1) 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知 是不能决定的,他们只是在方法的调用前后执行通知而已,即目标方法肯定是要执行的。

  2) 环绕通知可以控制返回对象,即你可以返回一个与目标对象完全不同的返回值,虽然这很危险,但是你却可以办到。而后置方法是无法办到的,因为他是在目标方法返回值后调用

  6.基于XML形式的配置方式

  开发中如果选用XML配置方式,通常就是POJO+XML来开发AOP,大同小异,无非就是在XML文件中写切入点表达式和通知类型

  例子:

  (1)Log.java

  public class Log {

  private Integer id;

  //操作名称,方法名

  private String operName;

  //操作人

  private String operator;

  //操作参数

  private String operParams;

  //操作结果 成功/失败

  private String operResult;

  //结果消息

  private String resultMsg;

  //操作时间

  private Date operTime = new Date();

  setter,getter

  }

  (2).Logger.java

  /**

  日志记录器 (AOP日志通知)

  */

  public class Logger {

  @Resource

  private LogService logService;

  public Object record(ProceedingJoinPoint pjp){

  Log log = new Log();

  try {

  log.setOperator(admin);

  String mname = pjp.getSignature().getName();

  log.setOperName(mname);

  //方法参数,本例中是User user

  Object[] args = pjp.getArgs();

  log.setOperParams(Arrays.toString(args));

  //执行目标方法,返回的是目标方法的返回值,本例中 void

  Object obj = pjp.proceed();

  if(obj != null){

  log.setResultMsg(obj.toString());

  }else{

  log.setResultMsg(null);

  }

  log.setOperResult(success);

  log.setOperTime(new Date());

  return obj;

  } catch (Throwable e) {

  log.setOperResult(failure);

  log.setResultMsg(e.getMessage());

  } finally{

  logService.saveLog(log);

  }

  return null;

  }

  }

  (3).applicationContext.xml

  

  

  

  

  

  注意切入点表达式,!bean(logService) 做日志通知的时候,不要给日志本身做日志,否则会造成无限循环!

  如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

  有关更详细的Spring AOP知识,可以查看Spring官方文档第9章Aspect Oriented Programming with Spring

  7.JDK动态代理介绍

  例子:

  (1)UserService.java

  public interface UserService {

  public void add();

  }

  (2)UserServiceImpl.java

  public class UserServiceImpl implements UserService{

  public void add() {

  System.out.println(User add()...);

  }

  }

  (3)ProxyUtils.java

  public class ProxyUtils implements InvocationHandler{

  private Object target;

  public ProxyUtils(Object target){

  this.target = target;

  }

  public Object getTarget() {

  return target;

  }

  public void setTarget(Object target) {

  this.target = target;

  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

  System.out.println(do sth before...);

  method.invoke(target, args);

  System.out.println(do sth after...);

  return null;

  }

  }

  (4)Test.java

  public class Test {

  public static void main(String[] args) {

  UserService userService = new UserServiceImpl();

  ProxyUtils proxyUtils = new ProxyUtils(userService);

  UserService proxyObject = (UserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),UserServiceImpl.class.getInterfaces(), proxyUtils);

  proxyObject.add();

  }

  }

  JDK动态代理核心还是一个InvocationHandler,记住这个就行了。

spring框架 AOP核心详解的更多相关文章

  1. Spring框架学习-Spring的AOP概念详解

    一.SpringAOP的概述. AOP(Aspect Oriented Programming),面向切面编程,通过预编译方式和运行期间动态代理实现程序的功能的统一维护的技术.AOP是OOP(面向对象 ...

  2. Spring框架系列(6) - Spring IOC实现原理详解之IOC体系结构设计

    在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解.本文将帮助你站在设计者的角度去看IOC最顶层的结构设计.@pdai Spring框架系列(6) - Spring IOC实现原理详解 ...

  3. Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程

    上文,我们看了IOC设计要点和设计结构:紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的. ...

  4. Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

    上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...

  5. Spring框架的核心功能之AOP技术

     技术分析之Spring框架的核心功能之AOP技术 AOP的概述        1. 什么是AOP的技术?        * 在软件业,AOP为Aspect Oriented Programming的 ...

  6. Spring各个jar包详解

    Spring各jar包详解 spring.jar 是包含有完整发布模块的单个jar 包.但是不包括mock.jar,aspects.jar, spring-portlet.jar, and sprin ...

  7. Spring Batch(4): Job详解

    Spring Batch(4): Job详解 2016-03-26 18:46 870人阅读 评论(1) 收藏 举报  分类: Spring(6)  版权声明:本文为博主原创文章,未经博主允许不得转载 ...

  8. 跟着刚哥学习Spring框架--AOP(五)

    AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入 ...

  9. RPC框架调用过程详解

    RPC框架调用过程详解 2017年09月16日 21:14:08 荷叶清泉 阅读数 6275   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. ...

随机推荐

  1. PyTorch 常用方法总结1:生成随机数Tensor的方法汇总(标准分布、正态分布……)

    在使用PyTorch做实验时经常会用到生成随机数Tensor的方法,比如: torch.rand() torch.randn() torch.normal() torch.linespace() 在很 ...

  2. php 常用代码片断

    参考: https://www.jianshu.com/p/f5303225ef92 http://www.phpxs.com/code/php/

  3. adb驱动安装和使用报错笔记

    adb驱动安装 adb驱动下载地址:https://adb.clockworkmod.com/ 安装时候选择一个容易记住的路径,这个很重要,因为adb驱动没有自动配置环境变量,所以实验时候将adb安装 ...

  4. 学习Struts2的个人疑惑及问题解决

    刚开始学习SSH框架中Struts2时,个人疑惑以及一些问题总结一下. 1.package节点namespace属性值决定访问路径问题       namespace不写或写namespace=&qu ...

  5. Oracle 11g 导出数据报 “ORA-01455: 转换列溢出整数数据类型”的问题

    最近发现云服务器上的Oracle 11g在导出时报错,如下: ... . 正在导出后期表活动. 正在导出实体化视图. 正在导出快照日志EXP-00008: 遇到 ORACLE 错误 1455ORA-0 ...

  6. CSS的进一步深入(更新中···)

    在之前我们学了6种选择器和三种CSS样式的引入,学习选择器就是为了更好的选择文本,学习CSS的引入是为了使文本增加各种样式和属性, 下面我们简单来学习一下为文本加样式和一些属性和属性值: 1.文本的样 ...

  7. Python3 tkinter基础 Listbox height 显示行数的上限

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  8. Linux lvm 分区知识笔记

    盘面上可以细分出扇区(Sector)与柱面(Cylinder)两种单位,其中扇区每个为512bytes那么大. 通常所说的"硬盘分区"就是指修改磁盘分区表,它定义了"第n ...

  9. 今日头条 CEO 张一鸣:面试了 2000 个年轻人,混得好的都有这 5 种特质

    https://blog.csdn.net/qq_35246620/article/details/72801285 博主说:多了解了解总是好的. 正文 张一鸣算是 80 后中绝对的佼佼者.1983 ...

  10. .net Core 依赖注入 Add********说明

    AddTransient瞬时模式:每次请求,都获取一个新的实例.即使同一个请求获取多次也会是不同的实例 AddScoped:每次请求,都获取一个新的实例.同一个请求获取多次会得到相同的实例 AddSi ...