Spring Aop

AOP

Aspect-Oriented Programming面向切面编程,主要编程对象是切面。
好处:
  1. 每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级
  2. 业务模块更简洁, 只包含核心业务代码.
    举例:让编写一个简单的加减乘除功能,但是写好add()、sub()、mul()、div四个方法之后,需要添加校验参数的功能、开始的时候显示传入参数的日志、结束了结果的日志,如果每个都加的话,代码就比较冗余,当然只有这三个功能还好,如果继续添加别的功能了就不便于维护。

AOP术语

  1. 切面(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象,比如上述提到的校验参数、前置日志、后置日志组合在一起可以成为切面
  2. 通知(Advice):切面必须完成的工作比如上述提到的校验参数、打印前置日志、后置日志这些行为。
  3. 目标(Target):被通知的对象就是上述提到的对应的加减乘除四个方法的类,在动态代理中也可以理解为需要被代理的类
  4. 代理(Proxy):向目标对象应用通知之后创建的对象,在动态代理中为代理类
  5. 连接点(Joinpoint):连接点程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如 计算器类#add() 方法执行前的连接点,执行点为 计算器类#add(); 方位为该方法执行前的位置可以理解为参数校验、前置通知、后置通知的方法
  6. 切点(pointcut):每个类都拥有多个连接点:例如计算器类的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。

AOP XML实现方式

个人理解不是那么到位,如果描述有误,望大佬指点迷津!
  1. 我使用的是maven导入依赖,也可以去Spring官网下载jar包进行使用
<dependencies>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.10.RELEASE</version>
        </dependency>
    </dependencies>

2.目标对象

/**
 * 计算器加减乘除
 */
public interface Calculator {

    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 CalculatorImpl implements Calculator{
    public int add(int i, int j) {
        int result = i + j;
        return result;
    }

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

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

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


  1. 切面类
package com.interview.springxmlaspect.dao;

import org.aspectj.lang.JoinPoint;//跟版本权限有关系
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.Arrays;

/**
 * 切面类
 */
public class LoggingApect {

    /**
     * 前置通知
     */
    public void beforeMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("前置:The method " + methodName + " begins with " + Arrays.asList(args));
    }

    /**
     * 返回通知
     */
    public void afterReturning(JoinPoint joinPoint, Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("返回:The method " + methodName + " ends with " + result);
    }

    /**
     * 后置通知
     */
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("后置:The method " + methodName + " ends");
    }

    /**
     * 异常通知
     */
    public void afterThrowing(JoinPoint joinPoint, Exception e){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("异常:The method " + methodName + " occurs excetion:" + e);
    }

    /**
     * 环绕通知
     */

    public Object aroundMethod(ProceedingJoinPoint pjd){
        Object result = null;
        String methodName = pjd.getSignature().getName();
        try {
            //前置通知
            System.out.println("前置:The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
            //执行目标方法
            result = pjd.proceed();
            //返回通知
            System.out.println("返回:The method " + methodName + " ends with " + result);
        } catch (Throwable e) {
            //异常通知
            System.out.println("异常:The method " + methodName + " occurs exception:" + e);
            throw new RuntimeException(e);
        }
        //后置通知
        System.out.println("后置:The method " + methodName + " ends");
        return result;
    }

}

  1. 配置文件
<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

        <!--配置目标-->
        <bean id="calculator" class="com.interview.springxmlaspect.dao.CalculatorImpl"></bean>
        <!--配置切面bean-->
        <bean id="loggingApect" class="com.interview.springxmlaspect.dao.LoggingApect"></bean>
        <!--配置aop-->
        <aop:config>
            <!--配置切点表达式-->
            <aop:pointcut id="pointcut" expression="execution(* com.interview.springxmlaspect.dao.CalculatorImpl.*(int,int))"/>
            <!--配置切面及通知-->
            <aop:aspect  ref="loggingApect">
                <aop:before method="beforeMethod" pointcut-ref="pointcut"/>
                <aop:after method="afterMethod" pointcut-ref="pointcut"/>
                <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
                <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
                <aop:around method="aroundMethod" pointcut-ref="pointcut"></aop:around>
            </aop:aspect>
        </aop:config>
        <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>
  1. 测试类
 ApplicationContext context = null;

    public ApplicationContext getApplicationContext(){
        if (context == null) {
            context = new ClassPathXmlApplicationContext("applicationContext.xml");
        }
        return context;
    }

    /**
     * aop xml测试
     */
    @Test
    public void tes1(){
        ApplicationContext context = getApplicationContext();
        CalculatorImpl calculatorImpl=  context.getBean("calculator",CalculatorImpl.class);
        System.out.println(calculatorImpl.getClass().getName());
//        calculatorImpl.add(3,5);
        calculatorImpl.div(1,1);

    }

.

  • 前置通知
    方法执行前执行的方法
  • 后置通知
  •  方法执行完后执行的方法,无论是否发生异常都是执行
    
  • 返回通知
    没有发生异常才会执行
  • 异常通知
    发生异常执行的方法
  • 环绕通知
    环绕通知类似于包含有前置通知、返回通知、异常通知、后置通知
public Object aroundMethod(ProceedingJoinPoint pjd){
        Object result = null;
        String methodName = pjd.getSignature().getName();
        try {
            //前置通知
            System.out.println("前置:The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
            //执行目标方法
            result = pjd.proceed();
            //返回通知
            System.out.println("返回:The method " + methodName + " ends with " + result);
        } catch (Throwable e) {
            //异常通知
            System.out.println("异常:The method " + methodName + " occurs exception:" + e);
            throw new RuntimeException(e);
        }
        //后置通知
        System.out.println("后置:The method " + methodName + " ends");
        return result;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值