Spring AOP 简介以及简单用法

10 篇文章 0 订阅

Spring AOP 简介以及简单用法

如果你去面试java开发, 那么Spring的AOP和DI几乎是必问的问题。

那么AOP是什么呢?

一. AOP

所谓Aop就是 Aspect-OrientedProgramming, 中文就是面向切面编程。

我们之前听说面向过程编程, 以及面向对象编程, 而这个面向切面编程我们可以视为是面向对象编程的1个补充(增强);

在一般的方法(函数)中, 为了方便,可能只写了业务代码
1. 业务代码

而我们我们可以将其补充成4个部分。

  1. 验证参数
  2. 前置日志
  3. 业务代码
  4. 后置日志

1.1 横切关注点 (Crosscutting Concerns)

大家看上面的方法, 就像用刀子把1个方法横向切成4块, 我们把上面除业务代码外任意一个部分就叫做横切关注点.

1.2 切面 (Aspect)

我们可以把横切关注点进行分组, 其中任意一组就叫做切面

例如上面的例子中, 我们可以分成

  1. 验证切面 (1. 验证参数)
  2. 日志切面 (2. 前置日志, 4.后置日志)

1.3 通知 (Advice)

所谓通知就是切面要完成的工作。

例如对于日志通知来讲, 里面执行日志的方法我们就可以称为1个通知。

1.4 目标 (Target)

所谓目标就是被通知的对象, 也就是指上面例子中的原方法本身啦。

1.5 代理 (Proxy)

当目标被通知后产生的对象就叫做代理, 因为AOP的原理就是利用代理来实现的, 如果想了解动态代理的可以参考这里

1.6 连接点 (Joinpoint)

所谓Joinpoint就是程序执行到的某个位置,

上面例子中, 业务代码方法的执行之前, 执行之后, 抛出异常后 都可以视为某个连接点。

1.7 切点 (PointCut)

每个方法都存在多个连接点, 而Spring AOP利用切点来定位到具体那些连接点。
Joinpoint 和 PointCut 的关系可以作如下比喻,假如Joinpoint的数据里的记录, 那么PointCut就相当于查询条件

1.8 小结

而Spring的AOP 能在不修改具体某个方法的前提下, 利用动态代理技术将通知注入到这个方法的各个连接点中, 令到这个方法得到了必要的补充。

对于上面的例子种, 我们原来的方法只有业务代码, 但是我们可以利用Spring AOP加入 验证参数, 日志等功能!

二. 具体例子

2.1 还没使用AOP的例子

我们首先利用spring创建两个计算类。

1个加法类, 1个减法类。

bean config 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-4.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

    <!-- auto scan -->
    <context:component-scan base-package="com.home.aop"></context:component-scan>
</beans>

注意引入aop命名空间

计算接口 Calculator

package com.home.aop;

public interface Calculator {
    public double getResult(double a, double b);
}

加法类 AddCalculator

package com.home.aop;

import org.springframework.stereotype.Component;

@Component
public class AddCalculator implements Calculator {

    @Override
    public double getResult(double a, double b) {
        return a + b;
    }
}

减法类 SubCalculator

package com.home.aop;

import org.springframework.stereotype.Component;

@Component
public class SubCalculator implements Calculator {

    @Override
    public double getResult(double a, double b) {
        return a - b;
    }
}

Client 代码

package com.home.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopMain {
    public static void f(){
        g();
    }

    public static void g(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-aop.xml");

        Calculator addCal = (Calculator) ctx.getBean("addCalculator");
        Calculator subCal = (Calculator) ctx.getBean("subCalculator");

        System.out.println(addCal.getResult(3, 1));
        System.out.println(subCal.getResult(3, 1));
    }
}

执行结果

Jul 05, 2016 10:10:00 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5d79a4c9: startup date [Tue Jul 05 22:10:00 CST 2016]; root of context hierarchy
Jul 05, 2016 10:10:00 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [bean-aop.xml]
4.0
2.0

2.2 小结

上面例子中, 加法类和减法类中只包含了业务代码, 我们可以将视为两个Target(目标), 下面我们就利用AOP技术为这两个Target加入通知。

2.3 AOP 前置通知

这个任务的需求很简单。

  1. 不能修加法类和减法类
  2. 在加法类和减法类的getResult()方法执行时, 在业务代码执行前输出两个参数(log).

首先maven里要引入这些lib

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

        <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${org.springframework.version}</version>
 </dependency>

 <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.8</version>
    </dependency>

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

然后在bean-config xml里加入下面这个句话, enable spring aop 功能

<!--  enable @Aspect -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

然后新建1个类LoggingAspect

package com.home.aop;

import java.util.Arrays;
import java.util.List;

import org.springframework.stereotype.Component;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
@Component
public class LoggingAspect {

    //@Before("execution(public double com.home.aop.AddCalculator.getResult(double,double))")
    @Before("execution(public * com.home.aop.*.*(..))")
    public void beforeExecute(JoinPoint joinPoint){
        String classname = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("before Execute! --class name: " + classname + ", method name: " + methodName + " " + args );
    }

}

方法beforeExecute的意思就是我们要为目标执行之前 而注入的方法。

上面@Before 注解表示这是1个前置通知。 括号里面的就是PointCut(切点), 上面说过了, 相当于数据库里的查询条件

然后Spring AOP 会根据PointCut 查找出所有符合条件的目标。

内容就很简单了, 无非就是输出被执行的类名方法名和参数…

执行结果:

Jul 06, 2016 12:30:03 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6924181b: startup date [Wed Jul 06 00:30:03 CST 2016]; root of context hierarchy
Jul 06, 2016 12:30:03 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [bean-aop.xml]
before Execute! --class name: AddCalculator, method name: getResult [3.0, 1.0]
4.0
before Execute! --class name: SubCalculator, method name: getResult [3.0, 1.0]
2.0

三 总结

项目中, 如果不用AOP 我们往往要为每个方法添加日志代码, 十分难于维护, 可读性也大大下降, 而AOP的出现, 就能解决这些问题。

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Spring AOP 是一个用于实现面向切面编程的框架。它可以通过配置来实现横切关注点的模块化,并将其应用到程序的不同部分。Spring AOP 使用 AspectJ 切入点指示符来定义切入点表达式,用于匹配方法执行连接点。Spring AOP 支持以下 AspectJ 切入点指示符: 1. execution:用于匹配方法执行连接点。这是使用 Spring AOP 时要使用的主要切入点指示符。 2. within:限制匹配以连接某些类型中的点(使用 Spring AOP 时在匹配类型中声明的方法的执行)。 3. this:限制匹配到连接点(使用 Spring AOP 时方法的执行),其中 Bean 引用(Spring AOP 代理)是给定类型的实例。 4. target:限制匹配到连接点(使用 Spring AOP 时方法的执行),其中目标对象(正在代理的应用程序对象)是给定类型的实例。 5. args:限制匹配到连接点(使用 Spring AOP 时方法的执行),其中参数是给定类型的实例。 6. @target:限制匹配到连接点(使用 Spring AOP 时方法的执行),其中执行对象的类具有给定类型的注释。 7. @args:限制匹配到连接点(使用 Spring AOP 时方法的执行),其中传递的实际参数的运行时类型具有给定类型的注释。 8. @within:限制匹配以连接具有给定注释的类型中的点(使用 Spring AOP 时在具有给定注释的类型中声明的方法的执行)。 9. @annotation:限制匹配到连接点的主题(在 Spring AOP 中运行的方法)具有给定注释的连接点。 在使用 Spring AOP 时,需要引入 Spring AOPSpring Context 相关的包,并在配置文件中进行相应的配置。可以通过 Maven 或其他构建工具来引入相关依赖。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nvd11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值