Aop切面编程概念


AOP切面编程一般可以帮助我们在不修改现有代码的情况下,对程序的功能进行拓展,往往用于实现 日志处理,权限控制,性能检测,事务控制等
AOP实现的原理就是动态代理,在有接口的情况下,使用JDK动态代理,在没有接口的情况下使用cglib动态代理

为Dao层所有的add方法添加一个性能记录功能(抽象化横切面)

AOP中的术语辨析

1.连接点 Joint point:
类里面那些可以被增强的方法,这些方法称之为连接点
表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point

2.切入点 Pointcut:
实际被增强的方法,称之为切入点
表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方

3.通知 Advice:
实际增强的逻辑部分称为通知 (增加的功能)
Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
通知类型: 1 前置通知 2 后置通知 3 环绕通知 4 异常通知 5 最终通知

4.目标对象 Target:
被增强功能的对象(被代理的对象)织入 Advice 的目标对象

5.切面Aspect:
表现为功能相关的一些advice方法放在一起声明成的一个Java类
Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。

6.织入 Weaving
创建代理对象并实现功能增强的声明并运行过程
将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

Spring Aop实现

AspectJ本身并不是spring框架中的组成部分, 是一个独立的AOP框架,一般把AspectJ和Spring框架的AOP依赖一起使用,所以要导入一个独立的依赖

实现的两种方式
1.基于注解方式实现 (熟练)
2.基于XML配置方式 (了解)

准备工作
导入依赖

<dependencies><!--spring核心容器包--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.5</version></dependency><!--spring切面包--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.5</version></dependency><!--织入包  spring-aspects 已经导入该包,这里可以不导入--><!--<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency>--><!--aop联盟包--><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><!--Apache Commons日志包--><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><!--德鲁伊连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.22</version></dependency><!--Junit单元测试--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version><scope>test</scope></dependency><!--lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency></dependencies>

切入点表达式

切入点表达式: 通过一个表达式来确定AOP要增强的是哪个或者那些方法
语法结构:execution([权限修饰符][返回值类型][类的全路径名][方法名](参数 列表) )
例子1
execution(* com.msb.dao.UserDaoImpl.add(..))  //指定切点为UserDaoImpl.add方法
execution(* com.msb.dao.UserDaoImpl.*(..))      //指定切点为UserDaoImpl.所有的方法
execution(* com.msb.dao.*.*(..))                         //指定切点为dao包下所有的类中的所有的方法
execution(* com.msb.dao.*.add(..))                     // 指定切点为dao包下所有的类中的add的方法
execution(* com.msb.dao.*.add*(..))                   // 指定切点为dao包下所有的类中的add开头的方法


项目结构

基于注解方式实现

开启注解扫描和AOP切面编程自动生成代理对象配置

<?xml version="1.0" encoding="UTF-8"?>
<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:c="http://www.springframework.org/schema/c"xmlns:util="http://www.springframework.org/schema/util"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.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.xsd
"><!--spring 包扫描  --><context:component-scan base-package="com.msb"/><!--aop autoProxy 自动生成代理对象 --><aop:aspectj-autoproxy/>
</beans>

准备接口
UserDao和EmpDao

package com.msb.dao;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
public interface EmpDao {int addEmp(Integer empno,String ename,String job);
}
package com.msb.dao;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
public interface UserDao {int addUser(Integer userid,String username);
}

接口实现类

package com.msb.dao.impl;
import com.msb.dao.UserDao;
import org.springframework.stereotype.Repository;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
@Repository
public class UserDaoImpl implements UserDao {public int addUser(Integer userid,String username){System.out.println("userdao add ... ...");//int i =1/0;return 1;}
}
package com.msb.dao.impl;
import com.msb.dao.EmpDao;
import com.msb.dao.UserDao;
import org.springframework.stereotype.Repository;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
@Repository
public class EmpDaoImpl implements EmpDao {public int addEmp(Integer empno,String ename,String job){System.out.println("empDao add ... ...");return 1;}
}

准备切面

package com.msb.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
@Component
@Aspect
public class DaoAspect {//定义公共切点@Pointcut("execution(* com.msb.dao.*.add*(..))")public void addPointCut(){}/** 前置通知: 切点方法执行之前先执行的功能* 参数列表可以用JoinPoint接收切点对象* 可以获取方法执行的参数* */@Before("addPointCut()")public void methodBefore(JoinPoint joinPoint){System.out.println("Before invoked");}/** 后置通知:方法执行之后要增强的功能* 无论切点方法是否出现异常都会执行的方法* 参数列表可以用JoinPoint接收切点对象* */@After("addPointCut()")public void methodAfter(JoinPoint joinPoint){System.out.println("After invoked");}/** 返回通知:切点方法正常运行结束后增强的功能* 如果方法运行过程中出现异常,则该功能不运行* 参数列表可以用 JoinPoint joinPoint接收切点对象* 可以用Object res接收方法返回值,需要用returning指定返回值名称* */@AfterReturning( value = "addPointCut()",returning = "res")public void methodAfterReturning(JoinPoint joinPoint,Object res){System.out.println("AfterReturning invoked");}/** 异常通知:切点方法出现异常时运行的增强功能* 如果方法运行没有出现异常,则该功能不运行* 参数列表可以用Exception ex接收异常对象 需要通过throwing指定异常名称* */@AfterThrowing( value = "addPointCut()",throwing = "ex")public void methodAfterThrowing(Exception ex){System.out.println("AfterThrowing invoked");}/*环绕通知:在切点方法之前和之后都进行功能的增强* 需要在通知中定义方法执行的位置,并在执行位置之前和之后自定义增强的功能* 方法列表可以通过ProceedingJoinPoint获取执行的切点* 通过proceedingJoinPoint.proceed()方法控制切点方法的执行位置* proceedingJoinPoint.proceed()方法会将切点方法的返回值获取到,并交给我们,可以做后续处理* 我们在环绕通知的最后需要将切点方法的返回值继续向上返回,否则切点方法在执行时接收不到返回值* */@Around("addPointCut()")public Object methodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("aroundA invoked");Object proceed = proceedingJoinPoint.proceed();System.out.println("aroundB invoked");return proceed;}
}

测试代码

 @Testpublic void test1(){ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");UserDao userDao = context.getBean( UserDao.class);int add = userDao.addUser(10,"晓明");}

JoinPoint对象和ProceedingJoinPoint对象


有多个增强类对同一个方法进行增强,通过@Order注解设置增强类优先级
数字越小,优先级越高
数字越大,其代理位置越靠近注入位置


完全使用注解开发
创建配置类替代applicationContext.xml

package com.msb.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
@Configuration
@ComponentScan(basePackages = "com.msb")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringConfig {}

测试代码

@Testpublic void test2(){ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);UserDao userDao = context.getBean( UserDao.class);int add = userDao.addUser(10,"晓明");}

基于XML配置方式

取消上面配置的切面类注解

package com.msb.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.util.Arrays;//@Aspect
//@Component
//@Order(2)
public class DaoAspect {//定义一个公共切点,通过切点表达式来动态控制需要增强的方法
//    @Pointcut("execution(* com.msb.dao.*.add*(..))")public void addPointCut(){};//    @Before("addPointCut()")public void methodBefore(JoinPoint joinPoint) {System.out.println("前置通知");
//        Object[] args = joinPoint.getArgs();
//        System.out.println("args = " + Arrays.toString(args));}//    @After("addPointCut()")public void methodAfter(JoinPoint joinPoint) {System.out.println("后置通知");}//    @AfterReturning(value = "addPointCut()", returning = "res")public void methodAfterReturning(JoinPoint joinPoint, Object res) {System.out.println("返回通知" + res);}//    @AfterThrowing(value = "addPointCut()", throwing = "exception")public void methodAfterThrowing(Exception exception) {System.out.println("异常通知" + exception);}//    @Around("addPointCut()")public Object methodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("环绕通知A");Object res = proceedingJoinPoint.proceed();System.out.println("环绕通知B");return res;}
}

配置文件配置如下内容

<?xml version="1.0" encoding="UTF-8"?>
<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:c="http://www.springframework.org/schema/c"xmlns:util="http://www.springframework.org/schema/util"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.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.xsd">
<!--    &lt;!&ndash;    spring 包扫描&ndash;&gt;-->
<!--    <context:component-scan base-package="com.msb"/>-->
<!--    &lt;!&ndash;    aop autoProxy 自动生成代理对象&ndash;&gt;-->
<!--    <aop:aspectj-autoproxy/>--><!--创建对象--><bean id="userDao" class="com.msb.dao.impl.UserDaoImplA"></bean><bean id="daoAspect" class="com.msb.aspect.DaoAspect"></bean><!--配置aop增强--><aop:config><!--切入点--><aop:pointcut id="pointCutAdd" expression="execution(* com.msb.dao.*.add*(..))"/><!--配置切面--><aop:aspect ref="daoAspect"><!--增强作用在具体的方法上--><aop:before method="methodBefore" pointcut-ref="pointCutAdd"/><aop:after method="methodAfter" pointcut-ref="pointCutAdd"/><aop:around method="methodAround" pointcut-ref="pointCutAdd"/><aop:after-returning method="methodAfterReturning"  pointcut-ref="pointCutAdd" returning="res"/><aop:after-throwing method="methodAfterThrowing"  pointcut-ref="pointCutAdd" throwing="exception"/></aop:aspect></aop:config>
</beans>

测试代码

   @Testpublic void getBean() {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserDao userDao = context.getBean(UserDao.class);int res = userDao.addUser("aaa", "张三");System.out.println("res = " + res);}配置成功,打印如下前置通知
环绕通知A
UserDaoImplA add ...
返回通知1
环绕通知B
后置通知
res = 1

Aop切面编程原理和Spring实现相关推荐

  1. Spring中的AOP切面编程的三种实现方式

    文章目录 Spring中的AOP切面编程的三种实现方式 1.最基本AOP的实现 a.引入jar包 b.编写通知类,这里以后置通知和环绕通知类为例子进行说明 c.在SpringIOC容器中配置 d.测试 ...

  2. java切面类整合_SpringBoot2.x【五】整合AOP切面编程

    SpringBoot2.x[五]整合AOP切面编程 面向方面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP). OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面. ...

  3. SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务

    本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.AOP切面编程 1.什么是AOP编程 在软件业,AOP为Asp ...

  4. Spring 框架基础(04):AOP切面编程概念,几种实现方式演示

    本文源码:GitHub·点这里 || GitEE·点这里 一.AOP基础简介 1.切面编程简介 AOP全称:Aspect Oriented Programming,面向切面编程.通过预编译方式和运行期 ...

  5. 武林秘籍之Spring AOP 切面编程的简单应用

    年轻人,我观你骨骼精奇,定是万里无一的练武奇才,老夫这里有一本失传已久的武林秘籍,现赠于你,望你勤加苦练,早日修成正果... AOP(面向切面编程):Aspect Oriented Programmi ...

  6. java 切面_实用|AOP切面编程手段大汇总

    点击上方"欧学长的架构成长之路" 关注我 前言 首先说一下什么是AOP? AOP就是面向切面编程,它是一个思想,通过切面,我们可以将那些反复出现的代码抽取出来,放在一个地方统一处理 ...

  7. springboot实现AOP切面编程

    概述 AOP(Aspect Oriented Programming) 即面向切面编程.面向切面是面向对象中的一种方式而已.在代码执行过程中,动态嵌入其他代码,叫做面向切面编程(将交叉业务逻辑封装成成 ...

  8. springBoot AOP切面编程

    AOP 为 Aspect Oriented Programming 的缩写,意为 面向切面编程.AOP 为spring 中的一个重要内容,它是通过对既有程序定义一个切入点,然后在其前后切入不同的执行内 ...

  9. Swoft AOP 切面编程

    本篇概要: 1. AOP 基础原理与传统代理模式代码: 2. 动态代理模式.简易 AOP 雏形: 3. 动态代理模式实现 AOP 切入点.切面,模拟方法"注解": 4. Swoft ...

最新文章

  1. RichTextBox实现关键字自定义颜色显示(C#)
  2. vectorPoint points未声明的标识符
  3. DL之YoloV3:Yolo V3算法的简介(论文介绍)、各种DL框架代码复现、架构详解、案例应用等配图集合之详细攻略
  4. AIR工程中发生This application cannot be run. (Error: invalid application identifier) 错误
  5. ios uiwindow弹窗_iOS 你需要的弹窗大全
  6. react hooks使用_如何开始使用React Hooks:受控表格
  7. 编程是一门实践性的科学
  8. 学习:Web安装项目创建桌面快捷方式及重写安装类(转)
  9. Spring Cloud微服务之子模块的创建(二)
  10. 桌面时钟代码_被遗忘的手机桌面小部件
  11. TIOBE 3 月编程语言:Swift 一路低走,Java 份额大跌
  12. Adobe 再次发布带外更新,修复影响10款产品的漏洞
  13. MYSQL语句和多表查询
  14. 毫米波雷达的点云形式与分辨能力详解!
  15. 富爸爸系列:富爸爸穷爸爸实践
  16. Word模板生成C#源码
  17. POI Word 模板 文字 图片 替换
  18. 编程珠玑微信公众号-算法位运算
  19. Previous writer likely failed to write hdfs://hadoop001:8020/tmp/hive/root/_tez...... Failing becaus
  20. 转载一篇加盟骗局的文章

热门文章

  1. vue 使用高德地图标记坐标,去除高德水印logo
  2. 3点钟无眠区块链:96小时聊天内容精华全记录
  3. 哪一层提供了数据加密的功能?
  4. TXT文件编码格式解析
  5. 【MATLAB】输入命令(matlab实用小技巧)
  6. 学习记录:七大测试原则笔记
  7. 【Python自动化测试14】Python自动化测试基础与进阶练习题
  8. java autoconf_「Autoconf」- 安装 @20210202
  9. 虚拟化技术-Qemu-KVM
  10. KVM虚拟化之(1):CPU技术