SSM之SpringAOP配置实现

介绍

AOP被称为面向切面编程,是将横切出来的逻辑代码融合到业务逻辑中,来实现和没横切之前的一样的功能。

SpringAOP是将相同逻辑的重复代码横向抽取出来,使用动态代理技术将这些重复代码织入到目标对象方法中,实现和原来一样的功能。

相关概念

1、JoinPoint(连接点):能够被拦截到的点,在spring中,这些点指的是方法,每一个成员方法为一个连接点

2、Pointcut(切点):具体定位的连接点,具体定位到某一个方法成为切点

3、Advice(通知):添加到切点的一段逻辑代码,Spring中定义了五类通知

  • 前置通知
  • 后置通知
  • 返回通知
  • 异常通知
  • 环绕通知

4、Weave(织入):将Advice(通知)添加到目标类的具体连接点的过程

5、Aspect(切面):由Pointcut(切点)和Advice(通知)组成,包括横切逻辑和连接点定义

6、Target(目标对象):被代理的目标对象,已经存在的原对象

注解配置

1、创建xml配置文件进行包扫描和切面类

2、切入点pointcut属性配置:execution(返回值类型 包名.类名.方法名(形参类型))

3、前置通知@Before和最终通知@After的属性中配置的是切入点的方法

4、返回通知@AfterReturning和异常通知@AfterThrowing

  • pointcut配置的是切入点的方法
  • 返回通知的returning配置的是返回值对象的名称,名称必须与形参一致,形参必须是Object
  • 异常通知的throwing配置的是异常方法名称,名称必须与形参一直,形参为Exception

5、每个通知方法中的JoinPoint为接入点,即方法,可以通过属性获取到相关信息

  • jp.getSignature().getName():获取到执行对象的方法名
  • jp.getTarget():获取到接口的实现类
  • jp.getArgs():获取方法传入的形参

6、使用环绕通知,方法的返回值必须是Object,形参必须是ProceedingJoinPoint

在xml配置头中需要引入spring-aop的配置地址

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="io.jtxyh"></context:component-scan>
    <!-- 
    开启aop注解识别 , 
    属性 proxy-target-class:
    默认false:创建代理对象,有接口的话用Proxy,没接口用cglib
    true:全部用cglib创建代理对象 
    -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
// 两个注解加其他是切面bean对象
@Component // 实现被包扫描扫描到
@Aspect // 日志切面aspect
public class MyAop {

    // 切入点pointcut(joinPoint的集合)
    // execution(返回值类型 包名.类名.方法名(形参类型))
    @Pointcut("execution(* io.jtxyh.service.*.*(..))")
    public void servicePointcut() {};

    // 前置通知
    @Before("servicePointcut()")
    public void write(JoinPoint jp) {
        Object target = jp.getTarget();
        System.out.println("通知方法:"+target);
    }

    // 返回通知
    @AfterReturning(pointcut = "servicePointcut()",returning = "obj")
    public void afterReturn(JoinPoint jp,Object obj) {
        String methedName = jp.getSignature().getName();
        System.out.println("返回通知:"+methedName+"-------返回信息:"+obj);
    }

    // 异常通知
    @AfterThrowing(pointcut = "servicePointcut()",throwing = "ex")
    public void afterThrow(JoinPoint jp,Exception ex) {
        String methedName = jp.getSignature().getName();
        System.out.println("异常通知:"+methedName+"-------异常信息:"+ex.getMessage());
    }

    // 最终通知
    @After("servicePointcut()")
    public void after(JoinPoint jp) {
        String methedName = jp.getSignature().getName();
        System.out.println("最终通知:"+methedName);
    }
}
// 切面bean对象
@Component // 实现被包扫描扫描到
@Aspect // 日志切面aspect
public class MyAop2 {
    @Pointcut("execution(* io.jtxyh.service.*.*(..))")
    public void myAop() {};

    // 环绕通知,方法的返回值必须是Object,形参必须是ProceedingJoinPoint
    @Around("myAop()")
    public Object around(ProceedingJoinPoint jp) {
        Object target = jp.getTarget(); "impl对象"
        String methodName = jp.getSignature().getName(); "方法名"
        Object[] args = jp.getArgs(); "调用方法传入的形参"
        Object result = null;
        System.out.println("impl对象:"+target+"----方法名:"+methodName+"----方法的形参:"+Arrays.toString(args));
        try {
            System.out.println("环绕前置通知。。。。。");

            result = jp.proceed();

            System.out.println("环绕后置通知");
        } catch (Throwable e) {
            System.out.println("环绕异常通知。。。。。");
            e.printStackTrace();
        }finally {
            System.out.println("环绕结束通知");
        }
        return result; "返回调用方法的返回值"
    }
}

 

XML配置

定义一个普通的类,里面写上需要的方法,在xml文件中配置相关标签

public class MyXmlAop {

    // 设置前置通知
    public void before(JoinPoint jp) {
        System.out.println("前置通知========="+jp.getSignature().getName());
    }

    // 设置返回通知方法
    public void afterRu(JoinPoint jp) {
        System.out.println("后置通知========="+jp.getSignature().getName());
    }

    // 设置异常通知方法
    public void afterThrowing(JoinPoint jp) {
        System.out.println("异常通知=========");
    }

    // 设置最终通知
    public void after(JoinPoint jp) {
        System.out.println("最终通知========="+jp.getSignature().getName());
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="io.jtxyh"></context:component-scan>

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

    <!-- 将文件加载到bean中 -->
    <bean id="myXmlAop" class="io.jtxyh.aop.MyXmlAop"></bean>

    <aop:config>
        <!-- 通过bean找到文件 -->
        <aop:aspect ref="myXmlAop">
            <!-- 指定切入点 -->
            <aop:pointcut expression="execution(* io.jtxyh.service.*.*(..))" id="myXmlPon"/>
            <!-- 指定前置方法 -->
            <aop:before method="before" pointcut-ref="myXmlPon"/>
            <!-- 指定后置通知 -->
            <aop:after-returning method="afterRu" pointcut-ref="myXmlPon"/>
            <!-- 指定异常通知 -->
            <aop:after-throwing method="afterThrowing" pointcut-ref="myXmlPon"/>
            <!-- 指定最终通知方法 -->
            <aop:after method="after" pointcut-ref="myXmlPon"/>
        </aop:aspect>
    </aop:config>
</beans>

注解配置和XML配置只需要使用其中一种,多配会报错

public static void main(String[] args) {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 必须调用的是接口,不能是impl
    UserService us = ac.getBean(UserService.class);
    UserInfo user = us.getUser();
    System.out.println("打印的返回值:"+user.toString());
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值