单例模式 maven namespace printing datatable pip vue架构 java并发编程视频 网盘源码 java三维数组 hadoop特点 kb转mb kafka消费不到数据 时间戳java mysql汉化包 js数组截取前5个 python环境安装教程 python参数 python函数参数 java入门编程 java特性 java游戏开发 php语言入门 python下载教程 脚本之家 m4a转mp3格式转换器 id解锁大师 js删除节点 unix系统下载 易语言多线程 小工具 tar解压 deallocate asp编程 系统激活 大势至usb控制系统 ps蒙版抠图 齐论工具箱 删除mysql服务 任务栏跑到右侧怎么办
当前位置: 首页 > 学习教程  > 编程语言

java进阶之:AOP切入点和切面的使用

2020/7/24 11:34:36 文章标签: 测试文章如有侵权请发送至邮箱809451989@qq.com投诉后文章立即删除

AOP

基本概念

AOP = Aspect Oriented Programming面向切面编程,通过预编译方式和运行期【动态代理】实现【在不修改源代码】的情况下给程序动态统一添加功能的一种技术,主要用于【日志记录】、【性能统计】、【安全控制】、【事务处理】、【异常处理】等等。

编程思想

OOP关注将需求功能划分为不同的并且相对独立、封装良好的类,并让它们有属于自己的行为,依靠继承和多态等来定义彼此的关系;而
AOP则希望能够将从各个不相关的类中【分离出通用需求功能】,使很多类共享一个行为(方法);这个行为(方法)一旦变化,不必修改很多类,只需修改这个行为(方法)即可。

一些必要术语

&& Aspect 切面:可以看做一个类,其中包含【pointCut切点】 和【Advice暂且叫消息通知】
&& Joint point 连接点:简单理解为类中的全部方法
&& Cut point 切点:简单理解为需要被加强的方法(需要被代理的方法)
&& Advice 消息通知:加强的行为,可以发生在方法执行前、正常执行后、执行异常【相当于catch中】、最终一定执行的位置【相当于finally中】

——基于注解的spring AOP使用

resources中的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
            http://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="aop"></context:component-scan>

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

项目配置的pom.xml依赖

    <dependencies>
    
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.1_3</version>
        </dependency>

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

    </dependencies>

切面类(就是动态代理可以提供加强方法的类)

package aop.utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 用于记录日志的工具类,提供了公共的代码
 * 配置Logger类   可以用于代理加强某些类的公共类
 */

@Component("logger")
@Aspect//表示当前类是一个切面类
public class Logger {

//        @Pointcut("execution(* aop.service.*.*(..))")
//        @Pointcut("execution(public void aop.service.AccountServiceImpl.saveAccount())")  //加强具体的某个类的某个函数
//        @Pointcut("execution(* aop.service.AccountServiceImpl.saveAccount())")//方法返回值可以通配符,表示任意返回值
//        @Pointcut("execution(* *.*.AccountServiceImpl.saveAccount())")//包名可以通配符,多少级包就多少个*
//        @Pointcut("execution(* *..*.saveAccount())")//类名可以通配符——哪个类名有指定方法,都可以得到加强,“*..”表示通配包,再来一个“*.”表示通配任意类
//        @Pointcut("execution(* *..*.*())")//方法名可以通配符
          @Pointcut("execution(* *..*.*(..))")//传参可以通配符,表示任意类型参数都可以
//=======================以上通过通配符的方式,声明需要加强的方法,用 @Pointcut 注解=================================
        private void pointCut(){}

    //前置通知
//    @Before("pointCut()")
    public void beforePrintLog(){
        System.out.println("前置通知:Logger类中的beforePrintLog方法开始记录日志了!");
    }

    //后置通知
//    @AfterReturning("pointCut()")
    public void afterReturningPrintLog(){
        System.out.println("后置通知:Logger类中的afterReturningPrintLog方法开始记录日志了!");
    }

    //异常通知
//    @AfterThrowing("pointCut()")
    public void afterThrowingPrintLog(){
        System.out.println("异常通知:Logger类中的afterThrowingPrintLog方法开始记录日志了!");
    }

    //最终通知
//    @After("pointCut()")
    public void afterPrintLog(){
        System.out.println("最终通知:Logger类中的afterPrintLog方法开始记录日志了!");
    }

    // 环绕通知:指定增强方法需要的额外操作,相对于原方法的执行位置【前置、后置、异常、最终:分别是
    // 原方法执行前(对应proceedingJoinPoint.proceed(args)之前)、
    // 原方法正常执行后(对应proceedingJoinPoint.proceed(args)之后)、
    // 原方法无法正常执行报异常(对应catch)、
    // 原方法执行后最终一定会执行(对应finally) 】

    @Around("pointCut()")
    public Object aroundPrintLog(ProceedingJoinPoint proceedingJoinPoint){
        Object returnValue;
        try {
            Object[] args = proceedingJoinPoint.getArgs();//获得需要加强的方法执行所需的参数

            System.out.println("环绕通知:Logger类中的aroundPrintLog方法开始记录日志了!——前置");

            returnValue = proceedingJoinPoint.proceed(args);//明确调用切入点方法,也就是需要加强的方法

            System.out.println("环绕通知:Logger类中的aroundPrintLog方法开始记录日志了!——后置");

            return returnValue;
        } catch (Throwable throwable) {
            System.out.println("环绕通知:Logger类中的aroundPrintLog方法开始记录日志了!——异常");
            //必须throw出来,只是throwable.printStackTrace()无法打断程序
            throw new RuntimeException(throwable);
        } finally {
            System.out.println("环绕通知:Logger类中的aroundPrintLog方法开始记录日志了!——最终");
        }
    }
}

切面类的注解说明

&& @Aspect:注解在类上,声明这是一个切面类
&& @Pointcut:固定写法,主要是注解内需要声明需要被加强代理的方法,可以通过【通配】、【正则表达式】等方式集中声明
&& @Before(“pointCut()”)、@AfterReturning(“pointCut()”)、@AfterThrowing(“pointCut()”)、@After(“pointCut()”)分别注解在“前置、后置、异常、最终”位置,但是实际执行时貌似没有完全按照我们需要的先后顺序执行,所以【推荐以下方式】
&& 用@Around(“pointCut()”)注解一个方法,接受(ProceedingJoinPoint proceedingJoinPoint)作为参数,详见代码说明


本文链接: http://www.dtmao.cc/news_show_50433.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?