Spring基础知识回顾(2)

本文详细介绍了Spring的AOP(面向切面编程),包括AOP的概念、关键概念如切面、连接点、通知类型等,并展示了AOP的配置过程和注解配置方法。同时,解释了Spring如何通过代理模式实现AOP,分为接口存在时的JDK动态代理和无接口时的CGLib代理。最后,总结了AOP在提高代码可复用性和降低耦合度方面的重要性。
摘要由CSDN通过智能技术生成

前言

上一节我们学习了Spring IOC容器与Bean管理,通过学习我们可以使用Spring进行简单的开发,接下来我们继续学习Spring AOP面向切面编程。

学习内容

什么是AOP?

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。AOP百度百科

AOP关键概念

注解说明
Aspect切面,具体的可插拔组件功能类,通常一个切面只实现一个通用功能
Target Class/Method目标类、目标方法,指真正要执行与业务相关的方法
PointCut切入点,使用execution表达式说明切面要作用在系统的哪些类上
JoinPoint连接点,切面运行过程中是包含了目标类/方法元数据的对象
Advice通知,说明具体的切面执行时机,Spring包含了五种不同类型的通知

AOP配置过程

  1. 依赖AspectJ
  2. 实现切面类/方法
  3. 配置asoect Bean
  4. 定义PointCut
  5. 配置Advice

JoinPoint对象

注解说明
Object getTarget()获取IOC容器类目标对象
Signature getSignature()获取目标方法
Object[] getArgs()获取目标方法参数

请添加图片描述
请添加图片描述

PointCut切点表达式

在这里插入图片描述
请添加图片描述

五种通知类型

前置通知

目标方法运行前执行。

 <aop:before method="printExecutionTime" pointcut-ref="pointcut"/>
返回后通知

目标方法返回数据后执行。

<aop:before method="printExecutionTime" pointcut-ref="pointcut"/>
异常通知

目标方法抛出异常后执行。

<aop:after-throwing method="doAfterThrowing" throwing="th" pointcut-ref="pointcut"/>
后置通知、

目标方法运行后执行。

<aop:after method="doAfter" pointcut-ref="pointcut"></aop:after>
环绕通知

最强大通知,自定义通知执行时间,可决定目标方法是否运行。

 <aop:around method="check" pointcut-ref="pointcut"/>

请添加图片描述
请添加图片描述
请添加图片描述

利用注解配置AOP

请添加图片描述

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="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.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--初始化IoC容器-->
    <context:component-scan base-package="com.imooc"/>
    <!--启用Spring AOP注解模式-->
    <aop:aspectj-autoproxy/>
</beans>

请添加图片描述

package com.imooc.spring.aop.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
@Component //标记当前类为组件
@Aspect //说明当前类是切面类
public class MethodChecker {
    //环绕通知,参数为PointCut切点表达式
    @Around("execution(* com.imooc..*Service.*(..))")
    //ProceedingJoinPoint是JoinPoint的升级版,在原有功能外,还可以控制目标方法是否执行
    public Object check(ProceedingJoinPoint pjp) throws Throwable {
        try {
            long startTime = new Date().getTime();
            Object ret = pjp.proceed();//执行目标方法
            long endTime = new Date().getTime();
            long duration = endTime - startTime; //执行时长
            if(duration >= 1000){
                String className = pjp.getTarget().getClass().getName();
                String methodName = pjp.getSignature().getName();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
                String now = sdf.format(new Date());
                System.out.println("=======" + now + ":" + className + "." + methodName + "(" + duration + "ms)======");
            }
            return ret;
        } catch (Throwable throwable) {
            System.out.println("Exception message:" + throwable.getMessage());
            throw throwable;
        }
    }
}

AOP实现原理

Spring基于代理模式实现功能动态扩展,包含两种形式:

  • 目标类拥有接口,通过JDK动态代理实现功能扩展;
  • 目标类没有接口,通过CGLib组件实现功能扩展;

代理模式通过代理对象对原对象的实现功能扩展;
在这里插入图片描述

目标类拥有接口
静态代理

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

JDK动态代理

基于反射机制实现。

package com.imooc.spring.aop.service;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * InvocationHandler是JDK提供的反射类,用于在JDK动态代理中对目标方法进行增强
 * InvocationHandler实现类与切面类的环绕通知类似
 */
public class ProxyInvocationHandler implements InvocationHandler {
    private Object target;//目标对象
    private ProxyInvocationHandler(Object target){
        this.target = target;
    }
    /**
     * 在invoke()方法对目标方法进行增强
     * @param proxy 代理类对象
     * @param method 目标方法对象
     * @param args 目标方法实参
     * @return 目标方法运行后返回值
     * @throws Throwable 目标方法抛出的异常
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("=====" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()) +"=========");
        Object ret = method.invoke(target, args);//调用目标方法,ProceedingJoinPoint.proceed()
        return ret;
    }

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(userService);
        //动态创建代理类
        UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                invocationHandler);
        userServiceProxy.createUser();

        //动态代理,必须实现接口才可以运行
        EmployeeService employeeService = new EmployeeServiceImpl();
        EmployeeService employeeServiceProxy = (EmployeeService)Proxy.newProxyInstance(employeeService.getClass().getClassLoader(),
                employeeService.getClass().getInterfaces(),
                new ProxyInvocationHandler(employeeService));
        employeeServiceProxy.createEmployee();
    }
}

目标类没有接口

在这里插入图片描述
请添加图片描述

总结

本次主要学习了Spring的AOP,相信大家看完以后基本明白了AOP是个什么,怎么使用,如果你发现文章存在问题,欢迎评论区交流哦~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值