栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

AOP面向切面编程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

AOP面向切面编程

AOP面向切口编程: AOP简介 :

AOP (Aspect Orient Programming)

Aspect : 切面 : 给你的目标类增加的功能 , 就是切面

切面的特点 : 一般都是非业务逻辑 , 都是可以独立使用的 Orient : 面向 , 对着Programming : 编程

意为 : 面向切面编程 , 可通过运行期动态代理实现程序功能的统一维护的一种技术 , AOP是Spring框架中一个重要内容 , 利用AOP可以对业务逻辑的各个部分进行隔离 , 从而使得业务逻辑各部分之间耦合度降低 , 提高程序的可重用性 , 同时提高了开发效率

AOP底层 , 就是采用的动态代理模式实现的 , 采用两种代理 ,JDK动态代理 和 CGLIB动态代理

面向切面编程 , 就是将交叉业务逻辑封装成切面 , 利用AOP容器的功能将切面织入到主业务逻辑中 , 所谓交叉业务逻辑是指 , 通用的 , 与主业务逻辑无关的代码 , 如安全检查 , 事务 , 日志 , 缓存等

如若不使用AOP , 则会出现代码的纠缠 , 级交叉业务逻辑与主业务逻辑混合在一起 , 这样 , 会使主业务逻辑变得混杂不清

AOP就是动态代理的规范化 , 把动态代理的实现步骤 , 方式都定义好了 , 让开发人员用一种统一的方式 , 使用动态代理


怎么理解面向切面编程 :

(1) 需要在分析项目功能时 , 找出切面

(2) 合理的安排切面的执行时间 , (在目标方法前 , 还是目标方法后 )

(3) 合理的安全切面执行的位置 , 在哪个类 , 哪个方法增加


术语 :

(1) Aspect : 切面 表示增强的功能 , 非业务逻辑功能

常见的切面功能有 : 日志 , 事务 , 统计信息 , 参数检查 , 权限验证

(2) JoinPoint : 连接点 , 连接业务方法和切面的位置 , 就是某个类中的业务方法 (一个方法)

(3) Pointcut : 切入点 , 指多个连接点方法的集合 (多个方法)

(4) 目标对象 : 给哪个类的方法增加功能 , 这个类就是目标对象

(5) Advice : 通知 , 通知表示切面功能执行的时间

一个切面有三个关键的要素 :

(1) 切面的功能代码 , 切面干什么

(2) 切面的执行位置 , 使用Pointcut 表示切面执行的位置

(3) 切面的执行时间 , 使用Advice , 在目标方法之前 , 还是目标方法之后


AOP的实现 :

AOP是一个规范 , 是动态的一个规范化 , 一个标准

Spring框架监控切入点方法的执行 , 一旦监控到切入点方法被运行 , 使用代理机制 , 动态代理机制 , 动态创建目标对象的代理对象 , 根据通知类别 , 在代理对象的对应位置 , 将通知对应的功能织入 , 完成完整的代码的逻辑运行

AOP的技术实现框架 :

1.Spring : Spring 在内部实现了aop规范 , 能够做aop的工作

​ Spring主要是在事务处理时使用aop

​ 我们项目开发中很少使用Spring的aop实现 , 因为spring的aop比较笨重

2.aspectJ : 一个开源的专门做aop的框架 , Spring框架中已经集成了aspectJ框架 , 通过Spring 就能使用aspectJ的功能

1.使用xml的配置文件 : 配置全局事务2.使用注解 , 我们在项目中要做AOP功能 , 一般都是用注解


AOP开发明确的事项:

编写核心业务代码(目标类的目标方法)编写切面类 , 切面类中有通知(增强功能方法)在配置文件中 , 配置织入关系 , 即将那些通知与那些连接点进行结合


AOP:基于XML的AOP开发

(1)导入AOP相关坐标


    org.springframework
    spring-context
    5.0.5.RELEASE


    org.aspectj
    aspectjweaver
    1.8.4
 

(2)创建目标接口和目标类 (内部有切点)

(3)创建切面类 , (内部有增强方法)

(4)将目标类和切面类的对象创建权交给Spring

(5)在applicationContext.xml中配置织入关系








	
    
    	
        
    


AspectJ框架: 学习aspectJ框架的使用:

(1) 切面的执行时间 : 这个执行时间在规范中叫做通知 Advice (通知 , 增强)

在AspectJ框架中使用注解来表示的 , 也可以使用XML文件中的标签

@Before@AfterReturning@Around@AfterThrowing@After

(2) 表示切面执行的位置 : 使用的是切入点表达式 ,

 execution(modifiers-pattern? ret-type-pattern
 	declaring-type-pattern?name-pattern(parm-pattern)
 	throws-pattern?)

解释 :

modifiers-pattern : 访问权限类型ret-type-patern : 返回值类型declaring-type-pattern : 包名类名name-pattern(param-pattern) 方法名(参数类型和参数个数)throws-pattern : 抛出异常类型

? 表示可选部分

以上表达式共四个部分

execution(访问权限 方法返回值 方法申明(参数) 异常类型)

切入点表达式要匹配的对象就是目标方法的方法名 , 所以 execution 表达式中明显就是方法的签名 , 注意 , 表达式中黑色文字表示可以省略部分 , 各部分间用空格分开 , 在其中可以使用以下符号

举例 :

execution ( public(权限修饰符) ***** (返回值) *(…) (方法声明) )

指定切入点为 : 任意公共方法 *execution( *** (返回值) set(…) (方法声明) )

指定切入点为 : 任意一个以set开头的方法 execution ( *** (返回值) com.xyz.service. . * (…) (方法声明))*

指定切入点为 : service包中的任意类 , 类中的任意方法 ,第一个*表示包下的所有类第二个*表示类下的所有方法 **execution( *** (返回值) com.xyz.service… . (…) (方法声明) )

指定切入点为 : 定义在service包或者子包里的任意类的任意方法 ," … " 出现在类名中时 , 后面必须跟 " * " , 表示包 , 子包下所有的类1 execution( * (返回值) * …service.* . *(…) (方法声明))

指定切入点为 : 所有包下的service子包下所有类(接口)中所有方法为切入点


aspectJ的使用 :

(1) 新建maven项目

(2) 加入依赖 :

spring依赖aspectJ依赖

    
      org.springframework
      spring-context
      5.3.14
    
    
    
      org.springframework
      spring-aspects
      5.3.14
    

(3) 创建目标类 : 接口和实现类

要做的就是给类中的方法增加功能

(4) 创建切面类 : 普通类

在类的上面要加入 @Aspect

  

在类中定义方法 , 方法就是切面要执行的功能代码

在方法的上面要加入aspectJ中的通知注解 , 例如@before还需要指定切入点表达式 execution()

@Aspect
public class MyAspect {
    @Before(value="execution(public void com.sichen.DI01.impl.SomeServiceImpl.dosome(String,Integer))")
    public void myBefore(){
        System.out.println("前置通知 , 方法执行的时间..."+ new Date());
    }
}

(5) 创建spring的配置文件 , 声明对象 , 把对象交给容器同一管理

声明对象可以使用注解或者是xml配置文件

声明目标对象声明切面类对象声明aspectJ框架中的自动代理生成器标签

自动代理生成器 : 用来完成代理对象的自动创建功能的

    

    
    

    
    

注解中的参数 : (JoinPoint)
    @Before(value="execution(public void com.sichen.DI01.impl.SomeServiceImpl.dosome(String,Integer))")
    public void myBefore(JoinPoint jp){
        //获取方法的完整定义
        System.out.println("方法的签名 (定义)=" + jp.getSignature());
        System.out.println("方法的名字="+ jp.getSignature().getName());
        //获取方法的实参
        Object[] args = jp.getArgs();
        for (Object arg : args) {
            System.out.println("方法的参数是 : " +arg);
        }
        System.out.println("前置通知 , 方法执行的时间..."+ new Date());
    }

aspectJ中的五种注解的详解: @Before : 前置通知

@Before 前置通知注解
方法的定义要求 :
     1.公共方法 public
     2.方法
     3.方法名称自定义
     4.方法可以有参数 , 也可以没有参数
如果有参数 , 参数(不是自定义的) , 有几个参数类型可以选择

属性 : value

是切入点表达式 ,表示切面功能执行的位置

位置 :

在方法的上面

特点 :

 1.在目标方法之前先执行的
 2.不会改变目标方法的执行结果
 3.不会影响目标方法的执行

指定通知方法中的参数 : JoinPoint

作用是 :

可以在通知方法中获取方法执行时的信息 , 例如方法名称 , 方法的实参如果你的切面功能中需要用到这个方法的信息 , 使用JoinPoint即可 要求 :

这个JoinPoint参数的值是由框架赋予的 , 必须是第一个位置的参数

@Before(value="execution(public void com.sichen.DI01.impl.SomeServiceImpl.dosome(String,Integer))")
    public void myBefore(JoinPoint jp){
    //获取方法的完整定义
    System.out.println("方法的签名 (定义)=" + jp.getSignature());
    System.out.println("方法的名字="+ jp.getSignature().getName());
    //获取方法的实参
    Object[] args = jp.getArgs();
    for (Object arg : args) {
        System.out.println("方法的参数是 : " +arg);
    }
    System.out.println("前置通知 , 方法执行的时间..."+ new Date());
}

@AfterReturning : 后置通知

@AfterReturning : 后置通知
方法的定义要求 :
	1.公共方法 public
	2.方法
	3.方法名称自定义
	4.方法可以有参数 , 推荐使用Object ,参数是自定义的

参数的作用:

1.在目标方法执行之后执行的2.它能够获取目标方法的返回值Object res = doSome();3.可以修改返回值

属性 :

1.value , 切入点表达式2.returning : 自定义的变量 , 表示目标方法的返回值的

自定义的变量名必须和通知方法的形参名一样

@AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",
            returning = "res")
    public void myAfterReturning(Object res) {
        //Object res : 是目标方法执行之后的返回值 , 根据返回值做你的切面的功能处理
        System.out.println("后置通知 : 目标方法的返回值是 = " + res);
    }

@Around :环绕通知

环绕通知 : 经常做事务 , 在目标方法之前开启事务 , 执行目标方法 , 在目标方法之后提交事务

环绕通知方法的定义格式
 1.公共方法 public
 2. , 推荐使用Object
 3.方法名称自定义
 4.方法 , 固定的参数 ProceedingJoinPoint
@Around :环绕通知
属性 : value : 切入点表达式
特点 :
     1.它是的通知
     2.在目标方法的
     3.它能
     4.原来的的 , 
环绕通知 , 等同于JDK中的invoke()方法
参数 :
     ProceedingJoinPoint :等同于动态代理中的Method
作用 : 执行目标方法的
     它继承的是JoinPoint , 所以可以直接使用JoinPoint中的方法
返回值 : 是目标方法的执行结果 , 可以被修改

它相当于是把目标方法替换为了切面方法 , 这样就可以对该方法进行各种修改 , 
@Around(value = "execution( *  *..SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pj) throws Throwable {
        String name = "";
        Object[] args = pj.getArgs();
        if (args != null && args.length > 1) {
            Object arg = args[0];
            name = (String) arg;
        }
        //实现环绕通知 :
        System.out.println("环绕通知 : 在目标方法之前输出时间" + new Date());
        Object result = null;
        //1.目标方法的调用
        if ("思尘".equals(name)) {
            result = pj.proceed();
            //等同于Method中的invoke()方法 ; 
            //Object result = doFirst();
        }
        System.out.println("环绕通知 : 在目标方法之后 , 提交事务");
        //2.在目标方法的前后加入功能

        //修改目标方法的执行结果 , 影响方法最后的调用结果
        if (result != null) {
            result = "hello AspectJ AOP";
        }
        //返回目标方法的返回值
        return result;
    }

@AfterThrowing : 异常通知

在目标方法抛出异常后执行 , 该注解的 throwing 属性用于指定所发生的异常类对象 , 当然 , 被注解为异常通知的方法 , 可以包含一个参数 Throwable , 参数名称为 throwing 指定的名称 , 表示发生的异常对象

异常通知方法的定义格式
	  1.公共方法 public
      2.
      3.方法名称自定义
      4.方法
		   如果还有 , 就是JoinPoint
  @AfterThrowing : 异常通知
  属性 : 1.value 切入点表达式
        2.throwing 自定义的变量 , 表示目标方法抛出的异常对象
              
  特点 :
      1.
      2.可以做异常的监控程序 , 监控目标方法执行时是不是有异常
      如果有异常 , 可以发送邮件 , 短信进行通知

          
    @AfterThrowing(value = "execution(* *..SomeServiceImpl.doSecond(..))" , throwing = "ex")
    public void myAfterThrowing(Exception ex){
        System.out.println("方法在异常时执行"+ex.getMessage());
        //发送邮件或短信通知开发人员
    }

@After : 最终通知

无论目标方法是否抛出异常 , 该增强就会被执行 ,

最终通知的定义 : 
	1. 公共方法 public 
	2. 
	3. 方法名称自定义
	4. 方法, 可以有 JoinPoint 
@After : 最终通知
	属性 : value : 切入点表达式
    位置 : 在方法上边
特点 : 
	1.总是会执行
	2.在最后执行的 
	
 一般是做资源清除工作的   	

@Pointcut : 定义和管理切入点的 (代替重复的切入点表达式)

如果你的项目中有多个切入点表达式是重复的,可以复用的,可以使用@Pointcut

属性 : value 切入点表达式

位置 : 自定义的方法上面

特点 :

当使用@Pointcut定义在一个方法上边 , 此时这个方法的名称就是切入点表达式的别名其他通知中 , value属性就可以使用这个方法名称(记得方法名后边要加括号) , 代替切入点表达式了


有接口和没接口使用的代理方式 :

有接口使用的是JDK的动态代理

没有接口使用的是cglib动态代理 (内部实现是 : 使用继承的方法生成目标类的子类 , 继承之后 重写方法)

在aspectJ框架中指定 , 即使有接口 也可以使用cglib的方式进行代理 :

在主配置文件中的自动代理生成器中设置一个属性

告诉框架要使用cglib动态

源清除工作的

---

#### @Pointcut : 定义和管理切入点的 (代替重复的切入点表达式)

如果你的项目中有多个切入点表达式是重复的,可以复用的,可以使用@Pointcut

属性 : value 切入点表达式

位置 : 自定义的方法上面

特点 : 

- 当使用@Pointcut定义在一个方法上边 , 此时这个方法的名称就是切入点表达式的别名 
- 其他通知中 , value属性就可以使用这个方法名称(**记得方法名后边要加括号**) , 代替切入点表达式了

---

### 有接口和没接口使用的代理方式 : 

有接口使用的是JDK的动态代理

没有接口使用的是cglib动态代理 (内部实现是 : 使用继承的方法生成目标类的子类 , 继承之后 重写方法)

**在aspectJ框架中指定 , 即使有接口 也可以使用cglib的方式进行代理 :**

```xml
在主配置文件中的自动代理生成器中设置一个属性

告诉框架要使用cglib动态

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/782580.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号