SpringAOP入门

Spring的AOP

aop概述

Aspect Oriented Programing 面向切面(方面)编程,

aop:扩展功能不修改源代码实现

aop采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)

aop原理

  1. 横向抽取机制

    扩展功能:

    添加数据之后,添加日志功能,添加之后,记录在什么时间添加哪个用户

    传统方式:

    public class User{
    	//添加新用户的方法
        public void add(){
            //添加逻辑
            //传统方式:在此修改源代码,添加日志逻辑
        }
    }
    

    ------》解决方案:纵向抽取机制

    缺陷:父类方法名字发生变化,在子类调用的方法也需要变化

    public class BaseUser{
    //创建添加日志的方法
        public void weitelog(){
            //添加日志逻辑
            
        }
    }
    public class User extends BaseUser{
    	//添加新用户的方法
        public void add(){
            //添加逻辑
            //功能扩展,添加日志的功能
            //调用父类方法实现日志功能
            super.writelog();
        }
    }
    

    ——》横向抽取机制

    aop:横向抽取机制

    底层使用 动态代理方式实现

    第一种情况

    ​ 使用动态代理方式,创建接口实现类代理对象

    ​ 创建一个和DaoImpl平级对象

    ​ 这个对象不是真的对象,代理对象

    ​ 实现DaoImpl相同的功能

    public interface Dao{
        public void add();
    }
    public class DaoImpl implements Dao{
    	public void add(){
    		//添加逻辑
        }
    }
    

    第二种情况 没有接口的情况

    使用cglib代理,没有借口情况

    public class User{
        public void add(){
            
        }
    }
    /*动态代理实现
    *创建Uesr类的子类的对象
    *在子类里面调用父类方法完成增强
    */
    

aop操作相关术语

pointcut(切入点)

在类里面可以有很多方法被增强,比如实际操作中,只是增强了类里面add的方法和update方法,实际增强的方法被称为切入点

Advice(增强)

实际增强的逻辑,称为增强,比如扩展日志功能,这个日志功能称为增强

增强(通知)有以下的分类

名称 介绍
前置通知 在方法之前执行
后置通知 在方法之后执行
异常通知 方法出现异常后执行
最终通知 在后置之后执行
环绕通知 在方法之前和之后执行

Aspect(切面)

在增强应用到具体的方法上面,过程称为切面,

切面是切入点和通知(引介)的结合

以下不常用,了解即可

Joinpoint:连接点:类里面那些方法可以被增强,这些方法被称为连接点

Introduction(引介):在不修改类代码的前提上,动态添加属性和方法

Target(目标对象):要增强的类

Weaving(织入):把增强应用到目标的过程

Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

public class User{
	public void add(){}
	public void update(){}
	public void delete(){
	}
	public void findAll(){}
}

基于aspectj的AOP

基于aspectj的xml准备工作

@AspectJ简介

在Spring里面进行aop操作,使用aspectj实现
  1. AspectJ不是Spring的一部分,和是Spring一起使用进行AOP操作
  2. Spring2.0以后增加了对AspectJ的支持
  3. 新版本Spring建议使用AspectJ进行AOP操作
使用AspectJ实现AOP有两种方式
  1. 基于AspectJ的xml配置
  2. 基于AspectJ的注解方式

AOP操作的准备

  • 需要导入aop相关的jar包:aspects aop。

    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
    
  • 创建spring核心配置文件,引入aop的相关约束:the aop schema

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
    
</beans>

使用表达式配置切入点

  1. 切入点:实际增强的方法

  2. 常用的表达式

    execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>) 作用对象
    execution(* aop.Book.add(…)) 某个方法
    execution(* aop.Book.*(…)) 某个类的所有方法
    execution(* *.*.*(..)) 所有
    execution(* save*(…)) 匹配所以save开头的方法

    前后置通知基本相同

    <bean id="book" class="aop.Book"></bean>
        <bean id="mybook" class="aop.MyBokk"></bean>
        <!-- 配置aop操作-->
        <aop:config>
    <!--        配置切入点-->
            <aop:pointcut id="pointcut1" expression="execution(* aop.Book.add(..))"/>
            <aop:aspect ref="mybook">
    <!--            配置增强的类型
                    method:增强类里面使用哪个方法作为前置
                    pointcut-ref:作用于哪一个切入点
    -->
                <aop:before method="before1" pointcut-ref="pointcut1"></aop:before>
            </aop:aspect>
        </aop:config>
    

    环绕通知

    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            //方法之前
            System.out.println("方法之前。。。。。。。");
            //抛出异常
            proceedingJoinPoint.proceed();
            //方法之后
            System.out.println("方法之后........");
        }
    
     <aop:around method="around" pointcut-ref="pointcut1"></aop:around>
    

    基于Aspect实现AOP(注解)

首先在配置文件中开启aop自动代理

<aop:aspectj-autoproxy/>

然后在增强类中编写注解

@Aspect
public class MyBook {    
    @Before(value = "execution(* aop.Book.*(..))")    
    public void before1(){        
        System.out.println("前置增强.......");    
    }    
    /**
    *
    * @param proceedingJoinPoint 用此调用被环绕的对象     
    */    
    @Around(value = "execution(* aop.Book.*(..))")    
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {        
        //方法之前        
        System.out.println("方法之前。。。。。。。");        
        //抛出异常        
        proceedingJoinPoint.proceed();        
        //方法之后        
        System.out.println("方法之后........");    
    }
}

@AspectJ提供不同的通知类型

  • @Before前置通知,相当于BeforeAdvice
  • @AfterReturning后置通知,相当于AfterReturningAdvice
  • @Around 环绕通知,相当于MethodIntercepetor
  • @AfterThrowing抛出通知,相当于ThrowAdvice
  • @After 最终final通知,不管是否异常,该通知都会执行
发布了53 篇原创文章 · 获赞 5 · 访问量 8291

猜你喜欢

转载自blog.csdn.net/weixin_44494373/article/details/102874878