Spring系列学习之Spring AOP

Spring AOP

Spring AOP的简单了解、使用。


目录

Spring AOP

一、Spring AOP是什么?

二、了解Spring AOP

三、使用步骤

1.maven中引入依赖

2. 定义切面类和切面方法

2.1 JointPoint核心方法

3. 在applicationContext.xml配置Aspect Bean

4. 定义PointCut

4.1 了解PointCut切点表达式

5. 配置Advice

5.1 五中通知类型

5.2 引介增强

6、使用注解开发Spring AOP

1. 在applicationContext.xml中增加IOC组件扫描和启用AOP注解模式

2.实体类以及三层类

四、Spring AOP实现原理

1、代理模式

1.1 静态代理

1.2 动态代理


一、Spring AOP是什么?

AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。

二、了解Spring AOP

1、Spring AOP与AspectJ的关系

Eclipse AspectJ 是一种基于Java平台的面向切面变成的语言,Spring AOP使用AspectJWeaver实现类的方法匹配,当匹配上后,AOP利用代理模式实现对象运行时的功能扩展

2、几个关键概念

 例如:

//切面类
public class MethodAspect {
    //切面方法,用于扩展额外功能
    //JoinPoint 连接点,通过连接点可以获取目标类/方法的信息
    public void printExecutionTime(JoinPoint joinPoint){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String now = sdf.format(new Date());
        String className = joinPoint.getTarget().getClass().getName();//获取目标类的名称
        String methodName = joinPoint.getSignature().getName();//获取目标方法名称
        System.out.println("---->" + now + ":" + className + "." + methodName);
        Object[] args = joinPoint.getArgs();
        System.out.println("---->参数个数:" + args.length);
        for(Object arg:args){
            System.out.println("---->参数:" + arg);
        }
    }

    public void doAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("<----返回后通知:" + ret);
    }
    public void doAfterThrowing(JoinPoint joinPoint,Throwable th){
        System.out.println("<----异常通知:" + th.getMessage());
    }
    public void doAfter(JoinPoint joinPoint){
        System.out.println("<----触发后置通知");
    }
}

三、使用步骤

1.maven中引入依赖

<repositories>
        <repository>
            <id>aliyun</id>
            <name>aliyun</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

        <!--aspectjweaver是Spring AOP的底层依赖-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>

</dependencies>

2. 定义切面类和切面方法

//切面类
public class MethodAspect {
    //切面方法,用于扩展额外功能
    //JoinPoint 连接点,通过连接点可以获取目标类/方法的信息
    public void printExecutionTime(JoinPoint joinPoint){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String now = sdf.format(new Date());
        String className = joinPoint.getTarget().getClass().getName();//获取目标类的名称
        String methodName = joinPoint.getSignature().getName();//获取目标方法名称
        System.out.println("---->" + now + ":" + className + "." + methodName);
        Object[] args = joinPoint.getArgs();
        System.out.println("---->参数个数:" + args.length);
        for(Object arg:args){
            System.out.println("---->参数:" + arg);
        }
    }

    public void doAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("<----返回后通知:" + ret);
    }
    public void doAfterThrowing(JoinPoint joinPoint,Throwable th){
        System.out.println("<----异常通知:" + th.getMessage());
    }
    public void doAfter(JoinPoint joinPoint){
        System.out.println("<----触发后置通知");
    }
}

在切面方法中需要配置JoinPoint  joinPoint连接点参数。

2.1 JointPoint核心方法

//切面类
public class MethodAspect {
    //切面方法,用于扩展额外功能
    //JoinPoint 连接点,通过连接点可以获取目标类/方法的信息
    public void printExecutionTime(JoinPoint joinPoint){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String now = sdf.format(new Date());

        String className = joinPoint.getTarget().getClass().getName();//获取目标类的名称
        String methodName = joinPoint.getSignature().getName();//获取目标方法名称
        System.out.println("---->" + now + ":" + classNane + "." + methodName);
        Object[] args = joinPoint.getArgs();//获取目标方法参数


        System.out.println("---->参数个数:" + args.length);
        for(Object arg:args){
            System.out.println("---->参数:" + arg);
        }
    }
}

3. 在applicationContext.xml配置Aspect Bean

在配置文件中,比IOC的表头增加了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">
</bean>

在配置文件下配置切面类bean

<!-- AOP配置 -->
    <bean id="methodAspect" class="com.imooc.spring.aop.aspect.MethodAspect"></bean>

4. 定义PointCut

4.1 了解PointCut切点表达式

<aop:pointcut id="pointcut" expression="execution(* com.imooc..*Service.*(..))"></aop:pointcut>

 <aop:config>
        <!-- PointCut 切点,使用execution表达式描述切面的作用范围 -->
        <!-- execution(public * com.imooc..*.*(..)) 说明切面作用在com.imooc包下的所有类的所有方法上 -->
        <!--<aop:pointcut id="pointcut" expression="execution(public * com.imooc..*.*(..))"></aop:pointcut>-->
        <!--只对所有Service类生效-->
        <aop:pointcut id="pointcut" expression="execution(* com.imooc..*Service.*(..))"></aop:pointcut>
        <!--只对所有返回值为String类型方法生效-->
        <!--<aop:pointcut id="pointcut" expression="execution(String com.imooc..*Service.*(..))"></aop:pointcut>-->
        <!--对方法名进行约束 -->
        <!--<aop:pointcut id="pointcut" expression="execution(* com.imooc..*Service.create*(..))"></aop:pointcut>-->
        <!-- 对参数进行约束 -->
        <!--<aop:pointcut id="pointcut" expression="execution(* com.imooc..*Service.*(String,*))"></aop:pointcut>-->
        <!-- 定义切面类 -->
        <aop:aspect ref="methodAspect">
            <!-- before通知(Advice),代表在目标方法运行前先执行methodAspect.printExecutionTime() -->
            <aop:before method="printExecutionTime" pointcut-ref="pointcut"/>
            <aop:after-returning method="doAfterReturning" returning="ret" pointcut-ref="pointcut"/>
            <aop:after-throwing method="doAfterThrowing" throwing="th" pointcut-ref="pointcut"/>
            <aop:after method="doAfter" pointcut-ref="pointcut"></aop:after>
        </aop:aspect>
</aop:config>

5. 配置Advice

5.1 五中通知类型

 After Advice 是无论目标方法成功还是异常,方法运行后都会执行

返回后通知:参数有2个,JointPoint以及另一个Object来接受目标方法的返回值。

 public void doAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("<----返回后通知:" + ret);

配置文件:

<aop:aspect ref="methodAspect">
           
            <aop:after-returning method="doAfterReturning" returning="ret" pointcut-ref="pointcut"/>
            
 </aop:aspect>

 返回后通知:参数有2个,JointPoint以及另一个Object来接受异常信息。

public void doAfterThrowing(JoinPoint joinPoint,Throwable th){
        System.out.println("<----异常通知:" + th.getMessage());
}

 配置文件:

<aop:aspect ref="methodAspect">
            
            <aop:after-throwing method="doAfterThrowing" throwing="th" pointcut-ref="pointcut"/>
           
</aop:aspect>

 返回后通知、后置通知、异常通知的顺序由配置文件中定义的顺序而定。


 环绕通知:参数只有一个,ProceedingJointPoint 是JointPoint的升级版,在原有功能外,还可以控制目标方法的是否执行。

public class MethodChecker {
    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;
        }
    }
}

<?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">
    <bean id="userDao" class="com.imooc.spring.aop.dao.UserDao"/>
    <bean id="employeeDao" class="com.imooc.spring.aop.dao.EmployeeDao"/>
    <bean id="userService" class="com.imooc.spring.aop.service.UserService">
        <property name="userDao" ref="userDao"/>
    </bean>
    <bean id="employeeService" class="com.imooc.spring.aop.service.EmployeeService">
        <property name="employeeDao" ref="employeeDao"/>
    </bean>

    <bean id="methodChecker" class="com.imooc.spring.aop.aspect.MethodChecker"></bean>
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.imooc..*.*(..))"></aop:pointcut>
        <aop:aspect ref="methodChecker">
            <!--环绕通知-->
            <aop:around method="check" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

5.2 引介增强

引介增强(IntroductionInterceptor)是对类的增强,而非方法,上面5中增强是对方法的增强,而引介增强是允许在运行时为目标类增加新属性或方法,这是一种高级引用,程序运行时,这些类被加载到jvm中,引介增强再对内存中的类动态增强。引介增强允许在运行时改变类的行为,让类随运行环境动态变更。

6、使用注解开发Spring AOP

1. 在applicationContext.xml中增加IOC组件扫描和启用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>

2.实体类以及三层类

Dao类

/**
 * 员工表Dao
 */
@Repository
public class EmployeeDao {
    public void insert(){
        System.out.println("新增员工数据");
    }
}
/**
 * 用户表Dao
 */
@Repository
public class UserDao {
    public void insert(){
        System.out.println("新增用户数据");
    }
}

Service类:

/**
 * 用户服务
 */
@Service
public class UserService {
    @Resource
    private UserDao userDao;

    public void createUser(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("执行员工入职业务逻辑");
        userDao.insert();
    }

    public String generateRandomPassword(String type , Integer length){
        System.out.println("按" + type + "方式生成"+ length  + "位随机密码");
        return "Zxcquei1";
    }

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}
/**
 * 员工服务
 */
@Service
public class EmployeeService {
    @Resource
    private EmployeeDao employeeDao;
    public void entry(){
        System.out.println("执行员工入职业务逻辑");
        employeeDao.insert();
    }

    public EmployeeDao getEmployeeDao() {
        return employeeDao;
    }

    public void setEmployeeDao(EmployeeDao employeeDao) {
        this.employeeDao = employeeDao;
    }
}

aspect类:

1、在类上加@Aspect注解。

2、在方法上添加@Around注解说明是环绕通知

@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;
        }
    }
}

四、Spring AOP实现原理

Spring基于2种代理模式实现功能动态扩展:

1、目标类拥有接口,通过JDK动态代理实现功能扩展

2、目标类没有接口,通过CGlib组件实现功能扩展

目标类有接口优先使用JDK动态代理,没有接口使用CGLib动态代理。

1、代理模式

代理模式通过代理对象对原对象的实现功能扩展

 静态代理,是指必须手动创建代理类的代理模式,也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

动态代理,代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。

1.1 静态代理

 需要手动去new代理类,如下 Application类中:

public interface UserService {
    public void createUser();
}


public class UserServiceImpl implements UserService{
    public void createUser() {
        System.out.println("执行创建用户业务逻辑");
    }
}


//静态代理是指必须手动创建代理类的代理模式使用方式
public class UserServiceProxy implements UserService{
    //持有委托类的对象
    private UserService userService ;
    public UserServiceProxy(UserService userService){
        this.userService = userService;
    }

    //===========前置功能===========
    public void createUser() {
        System.out.println("=====" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()) +"=========");
        userService.createUser();
    }
}


public class UserServiceProxy1 implements UserService{
    private UserService userService ;
    public UserServiceProxy1(UserService userService){
        this.userService = userService;
    }

    public void createUser() {
        userService.createUser();
        System.out.println("========后置扩展功能======");
    }
}



public class Application {
    public static void main(String[] args) {
        UserService userService = new UserServiceProxy1(new UserServiceProxy(new UserServiceImpl()));
        userService.createUser();
    }
}

1.2 动态代理

JDK动态代理:(要求:目标类必须有接口

public interface UserService {
    public void createUser();
}

public class UserServiceImpl implements UserService{
    public void createUser() {
        System.out.println("执行创建用户业务逻辑");
    }
}

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);
        //动态创建代理类,传入三个参数:类加载器、实现的接口对象、invocationHandler
        UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                invocationHandler);
        userServiceProxy.createUser();

    }
}

JDK动态代理解析:

当执行Proxy.newProxyInstance(。。)语句后:本地硬盘会生成一个$Proxy().class文件

1、确定生成的代理类的包在 :com.sun.proxy下 。

2、确定代理类的类名为(不出现重复的情况下):com.sun.proxy.$Proxy0

3、确定代理类的类名:$Proxy()生成代理类的代码ProxyGenerator.generateProxyClass

        语句执行会发生会执行相当于以下的伪代码:

public class $Proxy0 implements  UserService(
    private UserService targetObject;
    public void createUser(){
    System.out.println("........");//前置通知等方法以及下面的接口中的方法都会被搬入这个同名方法中
    targetObject.createUser();
    }
)

4、执行 defineClass0 方法,这些字节码文件会通过被代理类的类加载器载入到JVM的方法区中(heap  ),保存的是字节码解析以后的这些与类的描述的定义信息。

5、类被加载以后会执行new $Proxy0()方法创建对象,对象被保存到jvm的堆中。

然后执行代理对象userServiceProxy.createUser()方法,也就是包括前置通知的方法。


 CGLib实现代理类: 不需要接口

CGLib是运行时字节码增强技术,Spring AOP扩展无接口类使用CGLib,AOP会运行时生成目标继承类字节码的方式进行行为扩展。

yygs!
关注 关注
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
spring aop
07-17
spring aop spring aop spring aop
Spring实现AOP的4种方式
08-27 2380
Spring实现AOP的4种方式
SpringAOP
最新发布
梦想是很难很难的,所以先勇敢一点
08-16 431
其实,集体评议往往会埋没人才。“歪瓜裂枣”很多,我们的专家要识别他特殊能力的一面就行,也不用全面评价一个人,“不拘一格降人才”。比如,清华大学数学系主任熊庆来让只有初中学历的华罗庚破格进入清华大学,开启了华罗庚高水平数学的研究生涯;罗家伦当清华校长时,录取了数学成绩只有15分的钱钟书,成就了一位文学大师。初始职级,在校园招聘时可以定一次,在与优秀新员工喝咖啡时也可以再定一次,我们直接授权这批专家。
SpringAop
CSDN19970806的博客
07-04 467
先在说一下什么是Aop。我们之前在学filter的时候说过一点,当请求进入到servlet的时候,我们进行设置了字符编码以及跨域问题, 那么我们每个servelt都要去写,很麻烦,所以,我们可以利用aop思想,纵向重复,横行抽取。我们可以在过滤器中配置编码以及解决跨域问题,因为我们设置的过滤器是过滤我们的所有请求。所以在过滤器里面可以设置这些。那么SpringAop也是如此,我们每次在servic...
Spring AOP教程
12-07
Spring框架的关键组件之一是面向方面编程(AOP)框架。 面向方面的编程需要将程序逻辑分解成不同的部分。 此教程将通过简单实用的方法来学习Spring框架提供的AOP/面向方面编程。
spring aop 学习笔记
05-27
本学习笔记将深入探讨Spring AOP的核心概念、工作原理以及实际应用。 1. **核心概念** - **切面(Aspect)**:切面是关注点的模块化,包含业务逻辑之外的横切关注点,如日志、事务管理。 - **连接点(Join Point...
springaop学习
03-28
### Spring AOP 学习知识点详解 #### 一、Spring AOP 原理 **Spring AOP**(面向切面编程)是 Spring 框架中的一个关键特性,它提供了一种优雅的方式来处理横切关注点(cross-cutting concerns)。在实际应用中,...
SpringAOP学习笔记
01-27
,文章属于基础级文章,适合入门级的小伙伴,它的概念,应用场景,实现原理及SpringAOP的开发。全称:面向切面编程(AspectOrientedProgramming),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。...
Spring AOP 16道面试题及答案.docx
06-29
Spring AOP,全称为Aspect Oriented Programming,是面向切面编程的一种编程范式,它是对传统的面向对象编程(OOP)的一种补充。在OOP中,核心是对象,而在AOP中,核心则是切面。切面是关注点的模块化,即程序中的...
Spring Framework 开发参考手册 之五 Spring AOP: Spring之面向方面编程
pioneer's blog
04-28 1802
第 5 章 Spring AOP: Spring之面向方面编程5.1. 概念面向方面编程 (AOP) 提供从另一个角度来考虑程序结构以完善面向对象编程(OOP)。 面向对象将应用程序分解成 各个层次的对象,而AOP将程序分解成各个方面 或者说 关注点 。 这使得可以模块化诸如事务管理等这些横切多个对象的关注点。(这些关注点术语称作 横切关注点。)Spring的一个关键组件就是AOP框架。 Spri
springAop
HelloWorld
08-21 838
一、Introduction 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度...
Spring-AOP
weixin_48542526的博客
03-15 162
Spring中有A切面包第二步基础操作第三步 通知类和通知内容第四步匹配关系在配置类中用注解表明 我要用注解开发AOP了加一个Enable……然后在通知类里面第一步加一个Component 告诉Spring 这个类是你管2第二步加一个Aspect 告诉配置类 我这个是用注解开发的AOP内容(切面)第三步把通知类内容做出来:你要追加的功能 上面标明是在方法执行前还是后 然后()里填通知类里面的方法(空壳)id。
spring AOP
supermanman_的博客
07-04 147
Spring AOP概述 Spring AOP 意为面向切面编程,以程序预编译方式和运行期动态代理的方式在不修改源代码的前提下程序动态的新添加功能的一种技术,AOP的原理是动态代理, 个人认为学习AOP之前一定要先掌握动态代理技术, 静态/动态代理模式 AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注
Spring AOP
chenchenchencl的博客
05-31 854
SpringAOP
Spring 2.5 整合与AOP实践学习笔记
在学习Spring 2.5的过程中,我们需要理解这个版本的核心特性,特别是依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented Programming, AOP)。以下是对每个章节的详细解释: ### 第一课:面向...
写文章

热门文章

  • JWT双令牌(双token)实现登录验证 6483
  • SpringCloud Alibaba Nacos启动失败,nacos的startup.cmd启动失败 4490
  • Dependency ‘org.springframework.bootspring-boot-starter-amqp not found 的解决方法 4352
  • [已解决]无法连接MySQL:Unable to load authentication plugin ‘caching_sha2_password‘ 2519
  • Spring系列学习之Spring AOP 2034

最新评论

  • JWT双令牌(双token)实现登录验证

    CyAgyp123: 参考redisson的看门狗机制,而且单token可能更容易被黑客劫持,你可以去了解下三验证的过程,长token在没过期前是不会暴露在网络上的.

  • JWT双令牌(双token)实现登录验证

    CyAgyp123: 那问题来了,服务端或者客户端改如何知道access_token快过期了,那是不是要设置一个定时任务,那定时任务多起来是不是会占用资源。但如果设置一个长短token,可以保证在请求时在根据实际需要进行续签

  • SpringCloud Alibaba Nacos启动失败,nacos的startup.cmd启动失败

    m0_72565029: 厉害,解决了,很直接管用

  • SpringCloud Alibaba Nacos启动失败,nacos的startup.cmd启动失败

    披星戴月看天晓: 解决了,很简单有用!

  • JWT双令牌(双token)实现登录验证

    yygs!: 比如服务端给定token30分钟过期时间。如果29分的时候想延长token时间,但是这时候如果出现网络问题2分钟。单token的话,这时已经过期就没有办法延长,只能再登录操作。双token就可以规避这种情况。

最新文章

  • Spring @Transcational使用多数据源,注解@Transcational使用TranscationManager控制不同数据源事务
  • [已解决]无法连接MySQL:Unable to load authentication plugin ‘caching_sha2_password‘
  • SpringCloud Alibaba Nacos启动失败,nacos的startup.cmd启动失败
2023年3篇
2022年19篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

深圳SEO优化公司如何优化一个好网站虞城专业网站关键词优化价格长安的网站优化关键词推广网站seo优化关键词河北诚信服务企业网站优化滁州公司网站优化有用吗韶关网站关键词优化联系热线网站标题和内容的优化江门德阳网站优化公司义马优化网站银川网站优化推广公司哪个好google 网站优化猎流网店优化官网站哪种网站不能优化seo保定网站关键词优化晋州市网站seo优化排名优化网站降权分析怎么优化网站排名网站结构优化中什么是合理结构网站SEO优化专员招聘洛阳网站seo优化北京seo网站优化培训鄂州工厂网站优化要多少钱济南瓷砖行业网站优化推广特点深圳北易网站怎么优化凌海网站优化服务商怎么优化房地产网站增城网站优化推广报价企业网站优化价格低新兴搜索引擎网站优化服务歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化