天天看点

spring实现aop的两种方式前言一、XML实现AOP方式二、注解实现AOP方式(AspectJ)总结

文章目录

  • 前言
  • 一、XML实现AOP方式
    • 1.XML配置
    • 2.切面通知类的实现
    • 3.目标类的实现
    • 4.测试实现类
    • 5.实现结果
    • 6.业务实现
  • 二、注解实现AOP方式(AspectJ)
    • 1.通知实现类(advice)
    • 2.通知实现类,附带请求参数的获取
    • 3.目标类
    • 4.测试类
    • 5.打印结果
  • 总结

前言

提示:实现AOP的方式分为XML方式和注解(AspectJ)实现方式。

一、XML实现AOP方式

1.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">

    <!-- 声明一个目标类 -->
    <bean id="TmplController" class="org.example.aop.controller.IndexController"/>  
    
    <!-- 声明通知类 -->
    <bean id="aspectBean" class="org.example.aop.config.AopAspect" />
    <!-- AOP配置 -->
    <aop:config>
        <!-- 切入点 -->
        <aop:pointcut id="pointcut" expression="execution(* org.example.aop.controller..*(..))"/>
        <!--定义通知-->
        <aop:aspect ref="aspectBean">
            <aop:before method="beforeAspect" pointcut-ref="pointcut"/>
            <aop:after-returning method="afterReturnAspect"  pointcut-ref="pointcut" />
            <aop:after method="afterAspect" pointcut-ref="pointcut" />
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"  />
        </aop:aspect>
    </aop:config>
</beans>
           

2.切面通知类的实现

代码如下(示例):

package org.example.aop.config;
import org.aopalliance.intercept.Joinpoint;
/**
 * @author mr.monster
 * @version 1.0
 * @Description
 * @date 2021/5/3 23:02
 */
public class AopAspect {
    //前置操作
    public void beforeAspect(){
        System.out.println("===前置操纵方法执行===");
    }
    //后置操作
    public void afterAspect(){
        System.out.println("===后置操纵方法执行===");
    }
    //后置最终执行方法
    public void afterReturnAspect(){
        System.out.println("===后置最终方法执行===");
    }
    //异常通知:目标方法抛出异常时执行的代码
    public void afterThrowing(){
        System.out.println("===========执行异常通知============");
    }
}

           

3.目标类的实现

代码如下(示例):

package org.example.aop.controller;

/**
 * @author mr.monster
 * @version 1.0
 * @Description
 * @date 2021/5/3 22:57
 */
public class IndexController {
    public void index(){
        System.out.println("index");
    }

}

           

4.测试实现类

代码如下(示例):

package org.example.aop;
import org.example.aop.controller.IndexController;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author mr.monster
 * @version 1.0
 * @Description
 * @date 2021/5/3 23:49
 */
public class TestAop {
    @Test
    public void index(){
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("aop-config.xml");
        IndexController bean = app.getBean(IndexController.class);
        bean.index();
    }
}

           

5.实现结果

代码如下(示例):

===前置操纵方法执行===
index
===后置最终方法执行===
===后置操纵方法执行===
           

6.业务实现

AOP实现token验证登陆信息?

xml配置多个目标类

测试类中增加调用多个目标类的方法:

ArticleController bean2 = app.getBean(ArticleController.class);
        bean2.test();
           

结果:

===前置操纵方法执行===
index
===后置最终方法执行===
===后置操纵方法执行===
===前置操纵方法执行===
===article test=
===后置最终方法执行===
===后置操纵方法执行===
           

二、注解实现AOP方式(AspectJ)

1.通知实现类(advice)

代码如下(示例):

package org.example.aop.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * AOP配置类,替代XML文件配置方式,开启AOP以及注入需要的bean(类)
 * @author mr.monster
 * @version 1.0
 * @Description
 * @date 2021/5/3 22:58
 */
//用于定义配置类,替换xml配置文件
@Configuration 
//包扫描,根据需求实现路径处理 将此路径下包含注解的类实现bean注入
@ComponentScan(value = "org.example.aop")
//aop开启
@EnableAspectJAutoProxy 
public class AspectConfig {


}

           

2.通知实现类,附带请求参数的获取

代码如下(示例):

package org.example.aop.config;

import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 通知实现类
 * @author mr.monster
 * @version 1.0
 * @Description
 * @date 2021/5/3 23:02
 */
@Aspect  //定义切面类
@Component
public class AspectAdvice {
    public static  final String EXE= "execution(public * org.example.aop.controller..*(..))";
    //前置操作
    @Before(value = EXE)
    public void beforeAspect(JoinPoint joinPoint){
        System.out.println("===前置操纵方法执行===");
        //处理请求参数
        Map<String, Object> param = new HashMap<>();
        Object[] paramValues = joinPoint.getArgs();
        String[] paramNames = ((CodeSignature)joinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < paramValues.length; i++) {
            param.put(paramNames[i], paramValues[i]);
        }
        System.out.println(param);
    }

    //后置操作
    @After(value = EXE)
    public void afterAspect(){
        System.out.println("===后置操纵方法执行===");
    }
    //后置最终执行方法
    @AfterReturning(value = EXE, returning = "result")
    public void afterReturnAspect(){
        System.out.println("===后置最终方法执行===");
    }



    //异常通知:目标方法抛出异常时执行的代码
    @AfterThrowing(value = EXE,throwing = "th")
    public void afterThrowing(JoinPoint joinPoint , Exception th){
        System.out.println("===========执行异常通知============");
    }


}

           

3.目标类

代码如下(示例):

package org.example.aop.controller;

import org.springframework.stereotype.Controller;

/**
 * 业务实现类(目标类)
 * @author mr.monster
 * @version 1.0
 * @Description
 * @date 2021/5/3 22:57
 */
@Controller
public class IndexController   {
    public Object index(Object data){
        System.out.println("index");
        return data;
    }
}

           

4.测试类

代码如下(示例):

package org.example.aop;

import org.example.aop.config.AspectConfig;
import org.example.aop.controller.ArticleController;
import org.example.aop.controller.IndexController;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author mr.monster
 * @version 1.0
 * @Description
 * @date 2021/5/4 15:20
 */
public class ConfigAopTest {

    public class  Data{
        String a="1";
        String b="2";
        Integer c =3;

        public String getA() {
            return a;
        }

        public void setA(String a) {
            this.a = a;
        }

        public String getB() {
            return b;
        }

        public void setB(String b) {
            this.b = b;
        }

        public Integer getC() {
            return c;
        }

        public void setC(Integer c) {
            this.c = c;
        }

        @Override
        public String toString() {
            return "Data{" +
                    "a='" + a + '\'' +
                    ", b='" + b + '\'' +
                    ", c=" + c +
                    '}';
        }
    }

    @Test
    public void index(){

        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AspectConfig.class);

        IndexController bean = app.getBean(IndexController.class);
        Data d = new Data();

        bean.index(d);
        ArticleController bean1 = app.getBean(ArticleController.class);
        bean1.test();

    }
}

           

5.打印结果

代码如下(示例):

===前置操纵方法执行===
{data=Data{a='1', b='2', c=3}}
index
===后置最终方法执行===
===后置操纵方法执行===
===前置操纵方法执行===
{}
===article test=
===后置最终方法执行===
===后置操纵方法执行===
           

总结

在学习其他大佬的文章或者视频是会发现使用了接口类的继承,我在编码时直接抛弃接口类的实现是因为,个人认为若通过接口类实现完全失去了AOP解耦的作用,所以我在测试跑代码时出现了比较多的异常,特别是切入点的路径问题,差点放弃了~~~~还好各种尝试解决嘞

类似这样子的异常