AOP

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP相关概念

  • Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。

  • Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。

  • Advice(通知/增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

  • Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方
    法或 Field。

  • Target(目标对象):代理的目标对象。

  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。

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

  • Aspect(切面):是切入点和通知(引介)的结合。

maven依赖

  • 添加dependency

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.5</version>
    </dependency>

基于xml

  • 配置约束文件

    <?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.xsd">
  • 使用aop:config标签表明开始AOP的配置

  • 使用aop:aspect标签表明配置切面

    • id属性:给切面提供唯一标识
    • ref属性:制定通知类的beanId
  • aop:aspect标签内部使用对应标签来配置通知的类型

    • aop:brfore:表示前置通知
    • aop:after:表示最终通知
    • aop:after-running:表示后置通知
    • aop:after-throwing:表示异常通知
    • pointcut属性:用于指定切入点表达式,只对业务层哪些方法增强
    • method属性:用于指定哪个方法对应的相应的通知
    • 异常通知后后置通知只会执行一个
  • aop:pointcut标签:用来配置切入点表达式,id属性为唯一标志,expressiong为表达式内容,与pointcut-ref属性一起使用

  • 环绕通知:aop:around

    • 使用接口ProceddingJoinPointproceed方法明确调用切入点的方法
    • 最灵活的一种通知,可以自定义什么时候执行切入点方法

如下示例:

<?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.xsd">

    <bean id="accountService" class="com.oylong.service.impl.AccountServiceImpl"></bean>

    <bean id="logger" class="com.oylong.utils.Logger"></bean>

    <aop:config>
        <aop:aspect id="logAdvice" ref="logger">
            <aop:before method="printLog" pointcut="execution(public void com.oylong.service.impl.AccountServiceImpl.saveAccount())"></aop:before>
        </aop:aspect>
    </aop:config>
</beans>

之后即会在运行saveAccount方法前,调用printLog方法

  • 切入点表达式:execution(public void com.oylong.service.impl.AccountServiceImpl.saveAccount())

    • 全通配写法: * *..*.*(..)

      • 一般不用这个,而是切到业务层实现类的所有方法,如* com.oylong.service.impl.*.*(..)

    • 访问修饰符可以省略:execution(void com.oylong.service.impl.AccountServiceImpl.saveAccount())

    • 返回值可以使用通配符,表示任意返回值:execution(* com.oylong.service.impl.AccountServiceImpl.saveAccount())

    • 包名可以使用通配符,标识任意包,有几级包就要使用几个*.execution(* *.*.*.*.AccountServiceImpl.saveAccount())

    • 包名可以使用..表示当前包及其子包:execution(* *..AccountServiceImpl.saveAccount())

    • 类名和方法名都可以使用*来通配:execution(* *..AccountServiceImpl.*())

    • 参数类型:基本类型直接写数据类型,引用类型为包名.类名

    • 参数类型可以使用通配符*表示匹配任意类型但是必须有参数

    • 参数类型可以使用通配符..表示有无参数均可匹配

基于注解

  • 首先配置xml

    <?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"
           xmlns:context="http://www.springframework.org/schema/context"
           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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="com.oylong"></context:component-scan>
    
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>
  • 之后使用注解配置AOP

    package com.oylong.utils;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    
    @Component("logger")
    @Aspect
    public class Logger {
        @Before("pt()")
        public void printLog() {
            System.out.println("this is a logger");
        }
    
        @Pointcut("execution(* com.oylong.service.impl.*.*(..))")
        private void pt(){}
    }

    需要配置bean的,加上@Bean注解即可

    • 在配置类上使用@EnableAspectJAutoProxy这个注解就可以实现不适xml文件的方式使用AOP
最后修改:2020 年 03 月 28 日
如果觉得我的文章对你有用,请随意赞赏