Spring 框架(Spring Framework)之 AOP(面向切面编程)详解

简介: Spring 框架(Spring Framework)之 AOP(面向切面编程)详解

AOP(面向切面编程)

概念

AOP((Aspect Oriented Programming)面向切面编程

  • 是一种思想,目的是在不修改源代码的基础上,对原有功能进行增强
  • 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
  • AOP是一种编程范式,是OOP的延续,在OOP基础之上进行横向开发。
  • AOP研究的不是每层内部如何开发,而是同一层面上各个模块之间的共性功能。比如:事务、日志、统计


Spring AOP 是对 AOP 思想的一种实现,将那些与业务无关,却为业务模块所共用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP还能解决一些系统层面上的问题,比如日志、事务、权限等。

Spring 底层是通过动态代理的方式实现的 AOP。同时支持 jdk 和 cglib 动态代理,Spring会根据被代理的类是否有接口自动选择代理方式:

  • 如果有接口,就采用 JDK 动态代理(也可以强制使用 CGLIB 动态代理)
  • 没有接口就采用用 CGLIB 动态代理的方式


Spring AOP工作流程

开发阶段分别开发,运行阶段组装运行

  • 开发阶段(开发者完成)

    • 开发共性功能,制作成增强
    • 开发非共性功能,制作成切点
    • 在配置文件中,声明切点与增强之间的关系,即切面
  • 运行阶段/容器启动阶段(AOP完成)

    1. Spring读取配置文件中的切面信息,根据切面中的描述,将 增强功能 增加在 目标对象 的 切点方法 上,动态创建代理对象
    2. 最后将经过代理之后对象放入容器中(注意:存入容器的是动态代理对象!)


术语及说明

  • 目标对象(target ):需要被增强的对象,即切入点方法所在对象
  • 连接点(jointPoint):被代理对象中的方法
  • 切点(pointCut):按照 AOP 的规则去切(匹配)连接点,匹配出来的就叫切点,即 需要被增强的方法

    切点表达式的:定义一组规则,用于在连接点(所有方法)中挑选切入点(被增强方法)

    常用方式切点表达式:execution(方法的修饰符 返回值类型 包名.类名.方法名(参数))

  • 增强(通知)(advice):一个具体的增强功能。增强方法在切点方法的什么位置上执行

    Spring AOP 通知(增强)分为5种类型:

    • 前置通知(before):在切点运行之前执行
    • 后置通知(after-returning):在切点正常运行结束之后执行
    • 异常通知(after-throwing):在切点发生异常的时候执行
    • 最终通知(after):在切点的最终执行
    • 环绕通知(around):一种特殊的通知,在一个方法中定义多个增强逻辑(和手动定义动态代理类似)

      环绕通知的自定义方法:

      1. 参数 ProceedingJoinPoint:被代理对象的方法
      2. 返回值:被增强方法的返回值
  • 代理对象(proxy ):目标对象被增强后成为代理对象
  • 切面(aspect):是一个设计概念,包含了Advice 和 Pointcut。切面 = 切入点 + 增强

    Advice定义了Aspect的任务和什么时候执行,Pointcut定义在哪里切入

    即 Aspect定义了一个什么样的增强功能,切入到哪个核心方法的哪个位置

  • 织入(Weaving):一个动作。将增强代码加入到核心代码的过程就叫织入


切点标志符(表达式)

在定义 SpringAOP 的切点时候,比如使用 @Pointcut 注解标记切点时,需要填写切入通知的连接点的特征,即连接点的匹配规则或表达式,这些表达式是通过被称之为切点指示符的符号进行编写的。

通配符

在使用切点指示符进行匹配表达式编写时,几乎都需要使用到通配符进行模糊匹配,常用的通配符有三个:..+*

  • ..:表示匹配方法中的任意数量和类型的参数,或者匹配类的任意包路径
  • +:表示匹配给定类的任意子类
  • *:表示匹配一个或多个数量的字符

注:

  • 方法修饰符可以省略
  • 方法返回值可以通过 * 标识任意返回值类型
  • 包名可以通过 * 标识任意包,一般会指定到一个具体的包路径
  • 类名可以通过 * 标识任意类
  • 方法名可以通过 * 标识任意方法
  • 参数可以通过 .. 标识任意参数


类型指示符(within)

within 指示符用于匹配类型(包括:接口、类和包),其语法格式如下:

within(<type name>)

示例:

// 匹配 com.example.dao 包下的所有类的所有方法,但不包括子包的类
@Pointcut("within(com.example.dao.*)")

// 匹配 com.example.dao 包及其子包中所有类中的所有方法
@Pointcut("within(com.example.dao..*)")

// 匹配 包路径前缀为com.example + 任意包路径 + dao 包及其子包中所有类中的所有方法
@Pointcut("within(com.example..dao..*)")

// 匹配 com.example.dao 包下的 UserDaoImpl 类的所有方法
@Pointcut("within(com.example.dao.UserDaoImpl)")

// 匹配当前包下的 UserDaoImpl 类的所有方法
@Pointcut("within(UserDaoImpl)")

// 匹配所有实现 com.example.dao 包下的 UserDao 接口的类的所有方法
@Pointcut("within(com.example.dao.UserDao+)")

注: 示例中的 UserDao 为接口,UserDaoImpl 为其一个实现类。


方法指示符(execution)

execution 指示符根据方法签名进行匹配,其语法格式如下:

execution(<scope> <return-type> <fully-qualified-class-name>.*(parameters))

其中:

  • scope 表示方法作用域(如 public、private)
  • return-type 表示返回值类型
  • fully-qualified-class-name 表示方法所在类的完全限定名称
  • parameter 表示方法参数

示例:

// 匹配 com.example.dao 包中所有类中的所有方法(常用)
@Pointcut("execution(* com.example.dao.*.*(..))")

// 匹配 UserDaoImpl 类中的所有方法
@Pointcut("execution(* com.example.dao.UserDaoImpl.*(..))")
 
// 匹配 UserDaoImpl 类中的所有公共方法
@Pointcut("execution(public * com.example.dao.UserDaoImpl.*(..))")
 
// 匹配 UserDaoImpl 类中的所有返回值为 int 类型的公共方法
@Pointcut("execution(public int com.example.dao.UserDaoImpl.*(..))")
 
// 匹配 UserDaoImpl 类中第一个参数为 int 类型的所有公共方法
@Pointcut("execution(public * com.example.dao.UserDaoImpl.*(int , ..))")


名称指示符(bean)

bean 指示符用于匹配特定名称的 Bean 对象的方法,是 SpringAOP 扩展的指示符,AspectJ 中,我有对应的指示符。

示例如下:

// 匹配名称中带有后缀 Service 的 Bean 的所有方法
@Pointcut("bean(*Service)")


对象指示符(this 、target)

对象指示符共有两个 this 和 target,两者的区别如下:

  • this:用于匹配当前 AOP 代理对象类型的方法;
  • target:用于匹配当前目标对象类型的方法。

示例如下:

// 匹配任意实现了 UserDao 接口的代理对象的方法
@Pointcut("this(com.example.springAop.dao.UserDao)")

// 匹配任意实现了 UserDao 接口的目标对象的方法
@Pointcut("target(com.example.springAop.dao.UserDao)")


注解指示符(@within、@annotation)

注解指示符用于匹配使用了特定注解的类或方法,包括@within和 @annotation:

  • @within:表示匹配使用了特定注解的类的所有方法(注意和 within 的区别)
  • @annotation:表示匹配使用了特定注解的方法

示例如下:

// 匹配使用了 MyAnnotation 注解的类(注意是类)的所有方法
@Pointcut("@within(com.example.annotation.MyAnnotation)")

// 匹配使用了 MyAnnotation 注解的方法(注意是方法)
@Pointcut("@annotation(com.example.annotation.MyAnnotation)")


切点指示符的组合使用

所有的切点指示符都可以通过逻辑运算符进行组合使用,比如 &&||!,示例如下:

// 匹配了任意实现了 UserDao 接口的目标对象的方法并且该对象不在 com.zejian.dao 包及其子包下
@Pointcut("target(com.example.dao.UserDao) !within(com.example.dao..*)")

// 匹配名字以 Service 结尾, 并且在 com.example.service 包中的 bean
@Pointcut("bean(*Service) && within(com.example.service.*)")

注: 在组合指示符中,第一个指示符为主匹配表达式,而第二个指示符只是对第一个指示符的匹配结果进行过滤。


配置 Spring AOP(xml)

xml文件 配置切入点

  • <aop:pointcut

    • id:当前切点的唯一标志
    • expression:切入点表达式

xml文件 配置切面

  • <aop:aspect :配置一个切面

    • id:当前切面的唯一标志
    • ref:指定当前切面使用哪个通知

xml文件 配置通知类型

  • <aop:before :指定通知在切入点方法中执行的位置

    • method : 切面类中的增强方法名
    • pointcut-ref:切入点的id

xml文件 配置AOP示例

    <!--声明AOP配置-->
    <aop:config>
        <!-- 配置切入点(被增强的方法) -->
        <aop:pointcut id="pt" expression="execution(* cn.test.dao.impl.*.*(..))"/>

        <!--配置切面-->
        <aop:aspect ref="logger">
            <!-- 配置通知类型 -->
            <!-- 前置通知 -->
            <aop:before method="before" pointcut-ref="pt"></aop:before>
            <!-- 后置通知 -->
            <aop:after-returning method="afterReturning" pointcut-ref="pt"></aop:after-returning>
            <!-- 异常通知 -->
            <aop:after-throwing method="afterThrowing" pointcut-ref="pt"></aop:after-throwing>
            <!-- 最终通知 -->
            <aop:after method="after" pointcut-ref="pt"></aop:after>-->
            <!-- 环绕通知 -->
            <aop:around method="around" pointcut-ref="pt"></aop:around>
        </aop:aspect>
    </aop:config>
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 切面类:此类中具有所有的增强代码逻辑
 */
public class Logger {

    /**
     * 前置通知:执行被代理对象方法之前执行
     * 方法:无参数,无返回值
     */
    public void before() {
        System.out.println("执行前置通知");
    }

    /**
     * 后置后置:正常执行被代理对象方法获取返回值之后执行
     */
    public void afterReturning() {
        System.out.println("执行后置通知");
    }

    /**
     * 异常通知:执行代码抛出异常的时候执行
     */
    public void afterThrowing() {
        System.out.println("执行异常通知");
    }


    /**
     * 最终通知:finally代码块中执行的逻辑
     */
    public void after() {
        System.out.println("执行最终通知");
    }

    /**
     * 环绕通知:在一个方法中定义多个增强逻辑
     */
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object obj = null;

        try {
            System.out.println("执行前置通知");
            //执行被代理对象方法
            obj = pjp.proceed();
            System.out.println("执行后置通知");
        }catch (Exception e){
            System.out.println("执行异常通知");
        }finally {
            System.out.println("执行最终通知");
        }
        return obj;
    }


配置 Spring AOP(注解)

AOP注解版有两种:

  • 基于 XML 结合注解的配置方式
  • 基于纯注解的配置方式


开启 AOP 注解支持(xml 方式)

xml配置文件

  • 开启IOC注解的支持,包扫描

    • 自定义的对象,通过IOC注解进行对象创建和依赖注入
    • 第三方的对象,通过XML配置对象创建和依赖注入
  • 开启AOP注解的支持,自动代理
<?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/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">

    <!--开启包扫描-->
    <context:component-scan base-package="cn.test"></context:component-scan>

    <!--开启对AOP注解的支持-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    <!--在切面类中通过注解完成AOP配置-->
</beans>


开启 AOP 注解支持(配置类方式)

  • @EnableAspectJAutoProxy:标注在配置类上,开启 aop 注解支持
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * 配置类
 */
@Configuration
@ComponentScan(basePackages = "cn.test")
@EnableAspectJAutoProxy
public class SpringConfig {
}


切面类(注解)

  • @Aspect:标注在自定义类上,声明切面类

    注意:该切面类同时需要标注 IOC注解(@Component),交给 Spring 容器管理

  • 在切面类中的通知(增强)方法上通过注解配置通知类型:

    • @Before:前置通知

      • @AfterReturning: 后置通知
      • @AfterThrowing:异常通知
      • @After:最终通知
      • @Around:环绕通知

    通知注解的属性:

    • value / argNames 属性:切入点表达式 或 被 @Pointcut 标注的方法名()

          @Around("pt()")
          public Object around(ProceedingJoinPoint pjp)
  • @Pointcut:标注在切面类中的空的方法上,抽取公共的切入点表达式

    • value / argNames 属性:切入点表达式
    • 通知注解配置 方法名() 即可引入公共的切入点表达式

          @Pointcut(value="execution(* cn.test.service.impl.*.*(..))")
          public void pt() {}

切面类示例

/**
 * 切面类:此类中具有所有的增强代码逻辑
 */
@Component
@Aspect
public class Logger {

    /**
     * 前置通知:执行被代理对象方法之前执行
     * 方法:无参数,无返回值
     */
    //@Before(value="execution( * cn.test.dao.impl.*.*(..) )")
    public void before() {
        System.out.println("执行前置通知");
    }

    /**
     * 后置通知:正常执行被代理对象方法获取返回值之后执行
     */
    //@AfterReturning(value="execution( * cn.test.dao.impl.*.*(..) )")
    public void afterReturning() {
        System.out.println("执行后置通知");
    }

    /**
     * 异常通知:执行代码抛出异常的时候执行
     */
   // @AfterThrowing("execution( * cn.test.dao.impl.*.*(..) )")
    public void afterThrowing() {
        System.out.println("执行异常通知");
    }

    /**
     * 最终通知:finally代码块中执行的逻辑
     */
    //@After("execution( * cn.test.dao.impl.*.*(..) )")
    public void after() {
        System.out.println("执行最终通知");
    }
    
    // @Pointcut:抽取公共的切入点表达式
    @Pointcut(value="execution(* cn.test.service.impl.*.*(..))")
    public void pt() {}

    /**
     * 环绕通知:在一个方法中定义多个增强逻辑
     */
    //@Around("execution( * cn.test.dao.impl.*.*(..) )")
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object obj = null;
        try {
            System.out.println("1执行前置通知");
            //执行被代理对象方法
            obj = pjp.proceed();
            System.out.println("2执行后置通知");
        }catch (Exception e){
            System.out.println("3执行异常通知");
        }finally {
            System.out.println("4执行最终通知");
        }
        return obj;
    }
}


四大通知的执行顺序问题

参考:https://blog.csdn.net/qq_45193304/article/details/109430545

SpringAOP四大通知(前置、后置、异常、最终通知)的执行顺序非常复杂,跟Spring版本、配置先后顺序、配置方式(xml | 注解)都有关,故建议使用环绕通知

xml方式正确顺序配置aop的执行顺序:

try {
    // 前置通知(before) : 在切点运行之前执行
   
    // 切点执行,被代理对象方法调用
       
    // 后置通知(after-returning): 在切点正常运行结束之后执行
}catch (Exception e){
    // 异常通知(after-throwing): 在切点发生异常的时候执行
}finally {
    // 最终通知(after): 在切点的最终执行
}

注解方式正确顺序配置aop的执行顺序:

try{
    try{
        //@Before  -- 首先执行前置通知
        method.invoke(..); -- 然后执行切入点方法
    }finally{
        //@After  -- 再而肯定会执行最终通知 --- 注解配置的注意点
    }
    //@AfterReturning  -- 如果没有异常,则继续执行后置通知
    return;  -- 返回结果
}catch(){
    //@AfterThrowing  -- 如果有异常,则执行异常通知
}


切面方法的可传参数

JoinPoint 对象

JoinPoint 对象封装了 SpringAop 中切面方法的信息,在切面方法中添加 JoinPoint 参数,就可以获取到封装了该方法信息的JoinPoint 对象。

常用 API:

  • Signature getSignature() :获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的 Class 等信息

    joinPoint.getSignature().getName()) :目标方法名

    joinPoint.getSignature().getDeclaringType().getSimpleName()) :目标方法所属类的简单类名

    joinPoint.getSignature().getDeclaringTypeName()) :目标方法所属类的类名

    Modifier.toString(joinPoint.getSignature().getModifiers())) :目标方法声明类型

  • Object[] getArgs() :获取传入目标方法的参数对象
  • Object getTarget() :获取被代理的对象
  • Object getThis() :获取代理对象

使用示例:

@Component
@Aspect
@Slf4j
public class Logger {

    @Before(value="execution( * cn.test.dao.impl.*.*(..) )")
    public void before(JoinPoint joinPoint) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        StringBuffer uri = request.getRequestURL();

        Object[] args = joinPoint.getArgs();
        if (Objects.nonNull(args) && args.length > 0 && args[0] instanceof WebDataBinder){
            // 不打印initBinder方法的请求入参,否则会报错
            return;
        }
        List<Object> logArgs = Arrays.stream(args)
            .filter(arg -> (!(arg instanceof ServletRequest)
                && !(arg instanceof ServletResponse)
                && !(arg instanceof MultipartFile)
                && !(arg instanceof HttpSession)))
            .collect(Collectors.toList());
        log.info("执行前置通知, uri: {}, args: {}", uri, logArgs);
    }
}


ProceedingJoinPoint 对象

ProceedingJoinPoint 对象是 JoinPoint 的子接口,该对象只用在 @Around 的切面方法中

添加了 两个方法

  • Object proceed() throws Throwable :执行目标方法
  • Object proceed(Object[] var1) throws Throwable :传入的新的参数去执行目标方法

使用示例详解案例 MethodAnnotationLogAspect


案例

HttpLogAspect

打印 controller 方法日志的请求和返回的切面类

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Aspect
@Component
public class HttpLogAspect {

    @Pointcut("execution(* com.test.ssmtest..controller..*(..))")
    public void pt() {}

    @Before(value = "pt()")
    public void testBefore(JoinPoint joinPoint) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        StringBuffer uri = request.getRequestURL();

        Object[] args = joinPoint.getArgs();
        if (Objects.nonNull(args) && args.length > 0 && args[0] instanceof WebDataBinder){
            // 不打印initBinder方法的请求入参,否则会报错
            return;
        }
        List<Object> logArgs = Arrays.stream(args)
            .filter(arg -> (!(arg instanceof ServletRequest)
                && !(arg instanceof ServletResponse)
                && !(arg instanceof MultipartFile)
                && !(arg instanceof HttpSession)))
            .collect(Collectors.toList());
        log.info("request, uri: {}, args: {}", uri, JSON.toJSONString(logArgs));
    }

    @AfterReturning(value = "pt()", returning = "rt")
    public void afterReturning(Object rt) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        StringBuffer uri = request.getRequestURL();
        log.info("response, uri: {}, return: {}", uri, JSON.toJSONString(rt));
    }
}


MethodAnnotationLogAspect

打印使用了自定义注解的方法的调用时间

自定义注解

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAnnotation {
    String methodDesc();
}

切面类

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

@Slf4j
@Aspect
@Component
public class MethodAnnotationLogAspect {

    @Around("@annotation(com.test.ssmtest.aspect.LogAnnotation)")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 获取方法上的注解
        LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
        String methodDesc = annotation == null ? "" : annotation.methodDesc();

        long startTime = System.currentTimeMillis();
        log.info("开始时间:{},进入方法:{}", DateFormatUtils.format(startTime, "yyyy-MM-dd HH:mm:ss:SSS"), methodDesc);
        // 执行方法
        Object proceedReturn = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        long time = endTime - startTime;
        log.info("用时:{} ms,离开方法:{}", time, methodDesc);
        return proceedReturn;
    }
}
相关文章
|
23天前
|
XML 安全 Java
|
27天前
|
缓存 NoSQL Java
什么是缓存?如何在 Spring Boot 中使用缓存框架
什么是缓存?如何在 Spring Boot 中使用缓存框架
39 0
|
2天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
16天前
|
Java Spring
一键注入 Spring 成员变量,顺序编程
介绍了一款针对Spring框架开发的插件,旨在解决开发中频繁滚动查找成员变量注入位置的问题。通过一键操作(如Ctrl+1),该插件可自动在类顶部添加`@Autowired`注解及其成员变量声明,同时保持光标位置不变,有效提升开发效率和代码编写流畅度。适用于IntelliJ IDEA 2023及以上版本。
一键注入 Spring 成员变量,顺序编程
|
9天前
|
IDE Java 测试技术
互联网应用主流框架整合之Spring Boot开发
通过本文的介绍,我们详细探讨了Spring Boot开发的核心概念和实践方法,包括项目结构、数据访问层、服务层、控制层、配置管理、单元测试以及部署与运行。Spring Boot通过简化配置和强大的生态系统,使得互联网应用的开发更加高效和可靠。希望本文能够帮助开发者快速掌握Spring Boot,并在实际项目中灵活应用。
26 5
|
20天前
|
缓存 Java 数据库连接
Spring框架中的事件机制:深入理解与实践
Spring框架是一个广泛使用的Java企业级应用框架,提供了依赖注入、面向切面编程(AOP)、事务管理、Web应用程序开发等一系列功能。在Spring框架中,事件机制是一种重要的通信方式,它允许不同组件之间进行松耦合的通信,提高了应用程序的可维护性和可扩展性。本文将深入探讨Spring框架中的事件机制,包括不同类型的事件、底层原理、应用实践以及优缺点。
48 8
|
29天前
|
存储 Java 关系型数据库
在Spring Boot中整合Seata框架实现分布式事务
可以在 Spring Boot 中成功整合 Seata 框架,实现分布式事务的管理和处理。在实际应用中,还需要根据具体的业务需求和技术架构进行进一步的优化和调整。同时,要注意处理各种可能出现的问题,以保障分布式事务的顺利执行。
51 6
|
1月前
|
Java 数据库连接 数据库
不可不知道的Spring 框架七大模块
Spring框架是一个全面的Java企业级应用开发框架,其核心容器模块为其他模块提供基础支持,包括Beans、Core、Context和SpEL四大子模块;数据访问及集成模块支持数据库操作,涵盖JDBC、ORM、OXM、JMS和Transactions;Web模块则专注于Web应用,提供Servlet、WebSocket等功能;此外,还包括AOP、Aspects、Instrumentation、Messaging和Test等辅助模块,共同构建强大的企业级应用解决方案。
70 2
|
1月前
|
消息中间件 NoSQL Java
springboot整合常用中间件框架案例
该项目是Spring Boot集成整合案例,涵盖多种中间件的使用示例,每个案例项目使用最小依赖,便于直接应用到自己的项目中。包括MyBatis、Redis、MongoDB、MQ、ES等的整合示例。
114 1
|
1月前
|
Java Kotlin 索引
学习Spring框架特性及jiar包下载
Spring 5作为最新版本,更新了JDK基线至8,修订了核心框架,增强了反射和接口功能,支持响应式编程及Kotlin语言,引入了函数式Web框架,并提升了测试功能。Spring框架可在其官网下载,包括文档、jar包和XML Schema文档,适用于Java SE和Java EE项目。
33 0