Spring——初识AOP

一、AOP概述

AOP(Aspect-Oriented Programming,面向切面编程)。

指的是在程序运行期间,将某段代码动态的切入到指定方法的指定位置进行运行

这个已经很形象的将AOP的思想解读出来,白话一点,就是在原本的方法执行前后,可以插入新的方法,不破坏原先代码,但是又能更改或者增加我们想要的功能。说到这里,就不得不提java的一个技术:代理机制

关于代理机制的详解可以看这篇文章。

主要用于:日志记录,性能统计,安全控制,事务处理,异常处理等等。

二、详细解释面向切面的思想

我们假设我们现在有一个计算器的类,他实现了一个接口

public interface Calculate {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

public class MyCalculate implements Calculate {
    public int add(int i, int j) {
        return i + j;
    }

    public int sub(int i, int j) {
        return i - j;
    }

    public int mul(int i, int j) {
        return i * j;
    }

    public int div(int i, int j) {
        return i / j;
    }
}

平常我们在使用的时候,没有什么问题,但有一天有新需求了,比如在加减乘除的时候需要进行日志输出,如果我们直接在MyCalculate类中直接增加日志输出功能,先不说耦合性变差,就是一个一个敲,遇到错误还得一个个的改,这是一件很麻烦的事。拥有人类的天性的我,肯定是不干的。这里就可以请代理兄隆重登场。

public class JDKProxy {
    public static MyCalculate getProxy(final Calculate calculate) {
        ClassLoader classLoader = calculate.getClass().getClassLoader();
        Class[] interfaces = calculate.getClass().getInterfaces();

        return (MyCalculate) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //方法执行前
                Object result = method.invoke(calculate, args);
                //方法执行后
                return result;
            }
        });
    }
}

我们创建JDKProxy后,可以在两个注释那块进行我们所需要的的操作。这不就实现了,不改变原先的代码,但是动态的增加了功能。

三、AOP专业术语

我们就使用上面的Calculate类进行说明。

在这里插入图片描述

Calculate共有四个方法,每一个方法都存在方法执行前,方法返回,方法异常,方法结束这四个位置。

我们横向的与这些方法进行交叉,这些点就叫做**横切关注点,使用的方法就称为通知方法,这些通知方法写在一个类中,这个类就叫做切面类**。

单独的每一个方法的每一个位置就叫做**连接点,但是我们真正使用的过程中,可能只需要在其中的一个连接点上面搞事情,那么这个连接点现在就被叫做切入点**。

而**切入点表达式**就是在众多连接点中选出我们搞事情的地方。

四、AOP的简单配置

1.导包

在进行AOP的使用之前,我们需要导入这些包

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.9.1</version>
    </dependency>
    <dependency>
        <groupId>aopalliance</groupId>
        <artifactId>aopalliance</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.0.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.2.11</version>
    </dependency>
</dependencies>

2.配置

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

    	<context:component-scan base-package="com.shang"></context:component-scan>
		<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

1).将目标类和切面类导入bean的工作空间

@Service
public class MyCalculate implements Calculate {
    public int add(int i, int j) {
        return i + j;
    }

    public int sub(int i, int j) {
        return i - j;
    }

    public int mul(int i, int j) {
        return i * j;
    }

    public int div(int i, int j) {
        return i / j;
    }
}

@Aspect//标注是切面类
@Component
public class LogUtils {
    public static void logBefore() {
        System.out.println("方法执行前");
    }

    public static void logReturn() {
        System.out.println("方法返回");
    }

    public static void logException() {
        System.out.println("方法执行异常");
    }

    public static void logAfter() {
        System.out.println("方法执行结束");
    }
}

@Aspect切面类的标识,添加这个注解,Spring就会识别当前的这个类就是切面类

2)、切面类的方法,何时何地运行

AspectJ 支持 5 种类型的通知注解:

@Before:前置通知,在方法执行之前执行

@After:后置通知,在方法执行之后执行

@AfterRunning:返回通知,在方法返回结果之后执行

@AfterThrowing:异常通知,在方法抛出异常之后执行

@Around:环绕通知,围绕着方法执行

在这里插入图片描述

3)、切入点表达式

execution([权限修饰符] [返回值类型] [简单类名/全类名 ] [方法名] ([参数列表]) )

例如:@Before(“execution(public int com.shang.impl.MyCalculate.*(int, int))”)

.*代表无论名称,只要参数匹配,就都是切入点。

@Aspect
@Component
public class LogUtils {

    @Before("execution(public int com.shang.impl.MyCalculate.*(int, int))")
    public static void logBefore() {
        System.out.println("方法执行前");
    }

    @AfterReturning("execution(public int com.shang.impl.MyCalculate.*(int, int))")
    public static void logReturn() {
        System.out.println("方法返回");
    }

    @AfterThrowing("execution(public int com.shang.impl.MyCalculate.*(int, int))")
    public static void logException() {
        System.out.println("方法执行异常");
    }

    @After("execution(public int com.shang.impl.MyCalculate.*(int, int))")
    public static void logAfter() {
        System.out.println("方法执行结束");
    }

}

3、测试

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");

@Test
public void test01(){
    Calculate calculate = applicationContext.getBean(Calculate.class);
    calculate.add(1,1);
}

执行结果

方法执行前
方法执行结束
方法返回

可以看见,切入完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值