Spring Boot入门系列之:十一、Spring Boot Aop

深入理解Spring 之 源码剖析 SpringBoot Aop 切面编织过程和代理执行过程 分析 SpringBoot AOP 原理 阅读详情

spring-boot-aop

什么是aop

面向切面的程序设计(Aspect-oriented programming,AOP,又译作面向方面的程序设计、剖面导向程序设计)是计算机科学中的一种程序设计思想,旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度。通过在现有代码基础上增加额外的通知(Advice)机制,能够对被声明为“切点(Pointcut)”的代码块进行统一管理与装饰,如“对所有方法名以‘set*’开头的方法添加后台日志”。该思想使得开发人员能够将与代码核心业务逻辑关系不那么密切的功能(如日志功能)添加至程序中,同时又不降低业务代码的可读性。面向切面的程序设计思想也是面向切面软件开发的基础。

面向切面的程序设计将代码逻辑切分为不同的模块(即关注点(Concern),一段特定的逻辑功能)。几乎所有的编程思想都涉及代码功能的分类,将各个关注点封装成独立的抽象模块(如函数、过程、模块、类以及方法等),后者又可供进一步实现、封装和重写。部分关注点“横切”程序代码中的数个模块,即在多个模块中都有出现,它们即被称作“横切关注点(Cross-cutting concerns, Horizontal concerns)”。

日志功能即是横切关注点的一个典型案例,因为日志功能往往横跨系统中的每个业务模块,即“横切”所有有日志需求的类及方法体。而对于一个信用卡应用程序来说,存款、取款、帐单管理是它的核心关注点,日志和持久化将成为横切整个对象结构的横切关注点。

切面的概念源于对面向对象的程序设计的改进,但并不只限于此,它还可以用来改进传统的函数。与切面相关的编程概念还包括元对象协议、主题(Subject)、混入(Mixin)和委托(Delegate)。

AOP中的相关概念

看过了上面解释,想必大家对aop已经有个大致的雏形了,但是又对上面提到的切面之类的术语有一些模糊的地方,接下来就来讲解一下AOP中的相关概念,了解了AOP中的概念,才能真正的掌握AOP的精髓。

  • Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。

  • Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。

  • Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。

  • Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。

  • Target(目标对象):织入 Advice 的目标对象.。
    Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

spring aop

Spring AOP使用纯Java实现,它不需要专门的编译过程,也不需要特殊的类装载器,它在运行期通过代理方式向目标类织入增强代码。在Spring中可以无缝地将Spring AOP、IoC和AspectJ整合在一起。Spring AOP构建在动态代理基础之上,因此,Spring对AOP的支持局限于方法拦截。在Java中动态代理有两种方式:JDK动态代理和CGLib动态代理

  • jdk proxy

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * <p>
 *
 * @author leone
 * @since 2018-11-09
 **/
public class JdkProxy {

    interface IUserService {
        Integer delete(Integer userId);
    }

    static class UserServiceImpl implements IUserService {
        @Override
        public Integer delete(Integer userId) {
            // 业务
            System.out.println("delete user");
            return userId;
        }
    }

    // 自定义InvocationHandler
    static class UserServiceProxy implements InvocationHandler {
        // 目标对象
        private Object target;

        public UserServiceProxy(Object target) {
            this.target = target;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("------方法调用前---------");
            //执行相应的目标方法
            Object result = method.invoke(target, args);
            System.out.println("------方法调用后---------");
            return result;
        }
    }

    public static void main(String[] args) {
        IUserService userService = new UserServiceImpl();
        // 创建调用处理类
        UserServiceProxy handler = new UserServiceProxy(userService);
        // 得到代理类实例
        IUserService proxy = (IUserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(),
                                 new Class[]{IUserService.class}, handler);
        // 调用代理类的方法
        Integer userId = proxy.delete(3);
        System.out.println(userId);
    }

}

  • cglib proxy

而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * <p>
 *
 * @author leone
 * @since 2018-11-09
 **/
public class CglibProxy {

    static class UserService implements MethodInterceptor {

        private Object target;

        /**
         * 业务方法
         *
         * @param userId
         * @return
         */
        public Integer delete(Integer userId) {
            System.out.println("delete user");
            return userId;
        }

        /**
         * 利用Enhancer类生成代理类
         *
         * @param target
         * @return
         */
        public Object getInstance(Object target) {
            this.target = target;
            // 创建加强器,用来创建动态代理类
            Enhancer enhancer = new Enhancer();
            // 为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
            enhancer.setSuperclass(target.getClass());
            // 设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
            enhancer.setCallback(this);
            // 创建动态代理类对象并返回
            return enhancer.create();
        }


        /**
         * @param o
         * @param method
         * @param objects
         * @param methodProxy
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) 
                                throws Throwable {
            System.out.println("------方法调用前---------");
            Object object = methodProxy.invokeSuper(o, objects);
            System.out.println("------方法调用后---------");
            return object;
        }

    }

    public static void main(String[] args) {
        UserService userService = new UserService();
        UserService proxy = (UserService) userService.getInstance(userService);
        Integer userId = proxy.delete(2);
        System.out.println(userId);
    }

}

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP,可以强制使用CGLIB实现AOP
2、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

spirng boot aop

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

Advice的主要类型

  • @Before:该注解标注的方法在业务模块代码执行之前执行,其不能阻止业务模块的执行,除非抛出异常;

  • @AfterReturning:该注解标注的方法在业务模块代码执行之后执行;

  • @AfterThrowing:该注解标注的方法在业务模块抛出指定异常后执行;

  • @After:该注解标注的方法在所有的Advice执行完成后执行,无论业务模块是否抛出异常,类似于finally的作用;

  • @Around:该注解功能最为强大,其所标注的方法用于编写包裹业务模块执行的代码,其可以传入一个ProceedingJoinPoint用于调用业务模块的代码,无论是调用前逻辑还是调用后逻辑,都可以在该方法中编写,甚至其可以根据一定的条件而阻断业务模块的调用;

  • @DeclareParents:其是一种Introduction类型的模型,在属性声明上使用,主要用于为指定的业务模块添加新的接口和相应的实现。

切点表达式

1.通配符

  • [*] 匹配任意字符,但只能匹配一个元素

  • […] 匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用

  • [+] 必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类

2.逻辑运算符

表达式可由多个切点函数通过逻辑运算组成

  • && 与操作,求交集,也可以写成and

例如 execution(* chop(…)) && target(Horseman) 表示Horseman及其子类的chop方法

  • || 或操作,任一表达式成立即为true,也可以写成 or

例如 execution(* chop(…)) || args(String) 表示名称为chop的方法或者有一个String型参数的方法

  • ! 非操作,表达式为false则结果为true,也可以写成 not

例如 execution(* chop(…)) and !args(String) 表示名称为chop的方法但是不能是只有一个String型参数的方法

  • execution() 方法匹配模式串

表示满足某一匹配模式的所有目标类方法连接点。如execution(* save(…))表示所有目标类中的 save()方法。

由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的部件,并且在Spring中,大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的。如下是execution表达式的语法

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

execution(<修饰符> <返回类型> <类路径> <方法名>(<参数列表>) <异常模式> )

  • modifiers-pattern:方法的可见性,如public,protected;

  • ret-type-pattern:方法的返回值类型,如int,void等;

  • declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;

  • name-pattern:方法名类型,如buisinessService();

  • param-pattern:方法的参数类型,如java.lang.String;

  • throws-pattern:方法抛出的异常类型,如java.lang.Exception;

切点函数

  • @annotation(annotation-type) 方法注解类名

    如下示例表示匹配使用com.leone.aop.AopTest注解标注的方法:

    @annotation(com.leone.aop.AopTest)

  • args(param-pattern) 方法入参切点函数

    如下示例表示匹配所有只有一个参数,并且参数类型是java.lang.String类型的方法:

    args(java.lang.String)

  • @args(annotation-type) 方法入参类注解切点函数

    如下示例表示匹配使用了com.leone.aop.AopTest注解标注的类作为参数的方法:

    @args(com.leone.aop.AopTest)

  • within(declaring-type-pattern) 类名匹配切点函数

    within表达式只能指定到类级别,如下示例表示匹配com.leone.aop.UserService中的所有方法:

    within(com.leone.aop.UserService)

  • @within(annotation-type) 类注解匹配切点函数

    如下示例表示匹配使用org.springframework.web.bind.annotation.RestController注解标注的类:

    @within(org.springframework.web.bind.annotation.RestController)

  • target(declaring-type-pattern) 类名切点函数

    如下示例表示匹配com.leone.aop.UserService中的所有方法:

    target(com.leone.aop.UserService)

  • this

spring-boot-aop 实战

  • 配置切面类,实现代理

1.在类上使用 @Component 注解把切面类加入到IOC容器中
2.在类上使用 @Aspect 注解使之成为切面类

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * 描述一个切面类
 *
 * @author leone
 * @since 2018-06-21
 **/
@Slf4j
@Aspect
@Component
public class AopConfig {

    /**
     * 1.通配符
     * [*]  匹配任意字符,但只能匹配一个元素
     * <p>
     * [..] 匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用
     * <p>
     * [+]  必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类
     * <p>
     * 切点表达式分为 修饰符  返回类型  包路径  方法名  参数
     * <p>
     * 2.切点表达式
     * <p>
     * 3.逻辑运算符
     * 表达式可由多个切点函数通过逻辑运算组成
     * ** && 与操作,求交集,也可以写成and
     * <p>
     * 例如 execution(* chop(..)) && target(Horseman)  表示Horseman及其子类的chop方法
     * <p>
     * ** || 或操作,任一表达式成立即为true,也可以写成 or
     * <p>
     * 例如 execution(* chop(..)) || args(String)  表示名称为chop的方法或者有一个String型参数的方法
     * <p>
     * ** ! 非操作,表达式为false则结果为true,也可以写成 not
     * <p>
     * 例如 execution(* chop(..)) and !args(String)  表示名称为chop的方法但是不能是只有一个String型参数的方法
     */
    @Pointcut("execution(* com.leone.boot.aop.service.*.*(..))")
    public void pointCut() {
    }

    /**
     * 环绕通知在 target 开始和结束执行
     *
     * @param point
     * @return
     */
    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint point) {
        long start = System.currentTimeMillis();
        String methodName = point.getSignature().getName();
        log.info("around method name: {} params: {}", methodName, Arrays.asList(point.getArgs()));
        try {
            log.info("around end time: {}", (System.currentTimeMillis() - start) + " ms!");
            return point.proceed();
        } catch (Throwable e) {
            log.error("message: {}", e.getMessage());
        }
        return null;
    }

    /**
     * 前置通知在 target 前执行
     *
     * @param joinPoint
     */
    // @Before("@annotation(com.leone.boot.aop.anno.AopBefore)")
    // @Before("within(com.leone.boot.aop.controller.*)")
    // @Before("@within(org.springframework.web.bind.annotation.RestController)")
    // @Before("target(com.leone.boot.aop.controller.UserController)")
    @Before("@target(com.leone.boot.aop.anno.ClassAop) && @annotation(com.leone.boot.aop.anno.AopBefore)")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        log.info("before inform method name: {} param: {}", methodName, args);
    }

    /**
     * 后置通知在target后执行
     *
     * @param joinPoint
     */
    @After("@args(org.springframework.stereotype.Component) && 
            execution(* com.leone.boot.aop.controller.*.*(..))")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        log.info("after inform method name : {} param: {}", methodName, args);
    }

    /**
     * 后置返回在target返回后执行
     *
     * @param joinPoint
     * @param result
     */
    @AfterReturning(value = "within(com.leone.boot.aop.controller.*)", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        log.info("afterReturning inform method name: {} return value: {}", methodName, result);
    }

    /**
     * 后置异常通知在target异常后执行
     *
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(value = "args(com.leone.boot.common.entity.User) && 
            execution(* com.leone.boot.aop.controller.*.*(..))", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        log.info("afterThrowing inform method name: {} exceptions: {}" + methodName, ex);
    }
}

  • 测试类
import com.leone.boot.aop.anno.AopBefore;
import com.leone.boot.aop.anno.ClassAop;
import com.leone.boot.aop.interf.UserService;
import com.leone.boot.common.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author leone
 * @since 2018-06-21
 **/
@Slf4j
@ClassAop
@RestController
@RequestMapping("/api")
public class UserController {

    private UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }


    @AopBefore
    @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
    public User findOne(@PathVariable Long userId) {
        return userService.findOne(userId);
    }

    @AopBefore
    @RequestMapping("/user")
    public User save(User user) {
        return user;
    }
}
一篇文章搞懂spring aop,什么是AOP,什么是面向切面编程,动态代理实现AOP,Spring boot 实现Aop,spring 实现aop,附代码图文演示(保姆级教程) spring、aop、oop、java 阅读详情

相关推荐

Spring boot 入门教程-AOP详细介绍及使用

面试难免让人焦虑不安。经历过的人都懂的。但是如果你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”

2401_83330193的博客 1248

Spring Boot Aop

spring-boot-aop 什么是aop 面向切面的程序设计(Aspect-oriented programming,AOP,又译作面向方面的程序设计、剖面导向程序设计)是计算机科学中的一种程序设计思想,旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度。通过在现有代码基础上增加额外的通知(Advice)机制,能够对被声明为“切点(Pointcut)”的代码块进行统一管理与装...

weixin_33711647的博客 223

【Spring Boot】Spring AOP中的环绕通知

AspectOrientedProgramming(面向切面编程)AOP是Spring框架的第核(第核是IoC)AOP是一种思想,是对某一类事情的集中处理。其中在下面的学习中我们会学习到拦截器、统一异常处理,统一结果处理等,这些都是运用了AOP的统一思想来实现的。拦截器实现AOP思想作用的维度是前端对后端进行的一次请求和一次响应,主要是检索前端传来的URL,如果检索后返回True,则可以进入Controller开始执行代码,如果返回的为False,则表示失败,直接被拦截在外面,无法执行代码。

Ase5gqe的博客 1210

SpringBoot使用AOP详解

AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。 利用AOP可对业务逻辑进行增强,在不改变原有逻辑的基础上,在其前后进行处理。降低了耦合性,减少了大量冗余的操作。特别适合用于大量方法都需要进行相同处理的操作。 讲解了切面(Aspect)、切入点(Pointcut)、通知(Advice)、环绕通知

个人笔记git:https://gitee.com/tlangp/note.git 1万+

Spring boot 入门教程-AOP详细介绍及使用(1)

蚂蚁面试比较重视基础,所以Java那些基本功一定要扎实。蚂蚁的工作环境还是挺赞的,因为我面的是稳定性保障部门,还有许多单独的小组,什么三年1班,很有青春的感觉。面试官基本水平都比较高,基本都P7以上,除了基础还问了不少架构设计方面的问题,收获还是挺大的。经历这次面试我还通过一些渠道发现了需要大厂真实面试主要有:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。

2401_83330193的博客 1163

Spring Boot 进阶-Spring Boot如何整合AOP实现自定义注解

首先什么是AOP?AOP即面向切面编程,是在Spring 中提供的核心功能之一,其主要的目的是实现对业务功能的横向扩展操作,从而达到低耦合的效果。在后台应用开发的过程中,一个比较经典的使用就是在我们的业务系统中进行日志记录功能。日志操作功能在应用中算是辅助性的功能,不需要一遍一遍的重新开发,所以我们需要完成的操作就是通过AOP技术来实现日志切面,AOP操作可以在不改变任何逻辑的基础上实现对应用的基础功能进行扩展的操作。第一步、需要引入AOP框架使用的场景启动器依赖,代码如下

初学者 1491

SpringBoot中AOP

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

weixin_46073538的博客 3294

Java快速入门系列-9(Spring框架与Spring Boot —— 深度探索及实践指南)

Spring框架自诞生以来,凭借其独特的设计理念和广泛的适用性,在Java企业级应用开发领域占据主导地位。Spring框架的核心设计理念体现在IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)两个关键技术上。IoC通过容器管理对象的生命周期和依赖关系,从而降低耦合度;而AOP则允许我们将横切关注点(如日志、事务管理、权限验证等)从核心业务逻辑中分离出来,实现业务逻辑与系统服务的解耦。

赤兔码 1659

【Spring Boot】Spring AOP 快速上手指南:开启面向切面编程新旅程

本期主要讲解了关于Spring AOP入门概念,以及快速入门,以及Spring AOP的代码的详细介绍:切点,连接点,通知,以及切面的概念,还有通知类型等其他注解的介绍~~~

GGBond778的博客 5648

Spring Boot系列十三 Spring Boot集成RabbitMQ

1. 概述之前我有一系列关于RabbitMQ文章介绍了RabbitMQ的用法,本篇我们介绍如何在Spring Boot中集成RabbitMQ。本篇主要内容如下: 在Spring boot中消息的发送和接收的两种方式的demo 配置使用MessageConverter对消息序列化 2. Demo工程公共部分介绍工程名称:rabbitmq需要在我们的工程中的pom.xml引入新jar <!-- spri

不积跬步无以至千里; 不积小流无以成江海 1万+

AG32VF407直流电流采集仪设计:从1uA到10A宽范围采样与FPGA加速方案

本文详细介绍了基于AG32VF407芯片的直流电流采集仪设计方案,实现了从1uA到10A的宽范围采样。方案采用低噪声电源、精密运放调理、高速比较器自动档位切换及高精度ADC同步采样,并重点阐述了利用AG32VF407片内FPGA实现硬件加速以提升性能的架构思路,为精密电流测量提供了完整的硬件与FPGA加速解决方案。

weixin_33245447的博客 310

Spring Boot AOP(一) 入门与核心概念

在企业级项目中,日志记录、性能监控、事务管理、权限校验等通常会重复出现在多个模块,如果将这些逻辑直接写入业务方法,会导致代码耦合高、难维护。想看更多 那就点个关注吧 我会尽力带来有趣的内容 😎。如果你遇到了问题,自己没法解决,可以去我掘金评论区问。代码都在Github或Gitee上,如有需要可以去上面自行下载。,只对 Spring 管理的 Bean 生效,无法处理普通对象的直接方法调用。吧~ 我会很高兴的 😄 (^ ~ ^)。

Java、Python、AI、前沿技术等领域的技术总结和经验分享。 4859

【读论文】AI陪伴场景长期记忆(用户画像)解决方案

在长程人机交互中,如何让 AI 记住用户,不再是简单的“检索增强(RAG)”就能解决的问题。传统的向量数据库面临“信息信噪比低”、“人格不一致”以及“随着对话无限增长而崩塌”的困境。MemTensor 团队联合人大提出的Inside Out框架,从认知心理学汲取灵感,提出了一种基于PersonaTree(人格树)的显式记忆进化机制。该方案通过训练一个轻量级的(使用 DeepSeek-R1 蒸馏数据 + GRPO 强化学习),实现了将非结构化对话流实时压缩为结构化树操作(新增|更新|删除)。

kakaZhui的博客 817

Spring AOP从入门到放弃之概念以及Spring Boot AOP demo

AOP核心概念1、横切关注点对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点2、切面(aspect)-》(通知+切点)类是对物体特征的抽象,切面就是对横切关注点的抽象。 通知+切点 意思就是所有要被应用到增强(advice)代码的地方。(包括方法的方位信息)3、连接点(joinpoint)-》(被拦截的方法)被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中

不想当码农的程序员 2830

【记录】游戏体验报告怎么写(自我成长篇)

2019年3月更新: 这个倒是不用推翻,我个人虽然写的东西还是有一些偏差的,但是“表哥”说的倒是没毛病的,这篇主要是为了记录用,具体的干货也有,都在图片里,请自行提取 =====18年初原答案 作为一个游戏策划新人,游戏分析可能抓不到点子上,试着总结记录一下游戏体验报告分析的成长(因为水平不同,视野可能也不一样,也许之后几年回头看这些东西都是小儿科或者是错误的,所以只写出当下的想...

eat_human的博客 6万+

如何用ISBN API快速获取图书信息?Python实战教程(附完整代码)

本文是一篇Python实战教程,详细介绍了如何利用ISBN API高效获取图书元数据。内容涵盖从API服务选择、密钥管理,到使用requests库构建健壮的请求模块,并利用Pydantic进行数据验证与解析。教程还提供了批量查询、缓存优化及集成到Flask Web应用等高级技巧,帮助开发者快速实现图书信息的自动化获取与处理。

p8q9r0的博客 455

Spring Boot 实现动态插拔的 AOP 详解

在现代软件开发中,**面向切面编程(AOP)** 是一种非常重要的技术,能够有效实现日志记录、安全控制、性能监控等横切关注点的分离。在传统的 AOP 实现中,切面逻辑往往是固定的,难以动态调整。然而,在某些复杂业务场景下,我们需要根据运行时的条件动态地插拔不同的切面逻辑。本文将详细探讨如何利用 Spring Boot 实现动态插拔的 AOP,并通过完整案例进行演示。

fudaihb的博客 2018

Synology-群晖(三)DSM7.0系统Video Station无法播放DTS eac3解决方案

群晖升级DSM7.0后,发现部分DTS eac3解码的视频无法通过Vedio Station 3.0.1-2067进行播放,提示不支持该格式视频,初步判断是无法加载ffmpeg解码导致,网上搜了很多处理办法都没有办法解决,最终在知乎上看到一片文章,按此办法解决了这个问题,目前经过验证,该方案完美支持最新版本Video Station 3.0.1-2067,验证系统为DSM7.0和DSM7.0.1,这里使用的NAS为 Vmware虚拟机 黑群晖 演示。大概步骤如下: 添加这个社群来源 http://p

weixin_45827203的博客 3万+

Spring Boot 入门:解锁 Spring 全家桶

Spring 全家桶是现代 Java 开发者不可或缺的工具集,它提供了从轻量级的框架到微服务架构的完整支持。本文将带你快速了解 Spring 框架、核心概念如 IoC(控制反转)和 AOP(面向切面编程),并深入介绍 Spring Boot、Spring MVC、Spring Cloud 及其在企业应用开发中的优势。Spring 框架诞生于 2003 年,最初的目标是简化企业级 Java 开发,它通过去除冗余的 Java EE 代码,并提供灵活的配置方式,迅速成为了开发者心中的首选。

m0_61118741的博客 3238

Python 爬虫实战:爬取 B 站 UP 主的全部视频数据

本文详细介绍了基于Python开发B站UP主视频数据爬虫的技术方案。通过分析B站API接口,使用requests库发送HTTP请求并处理JSON数据,结合pandas进行结构化存储。文章重点解决了接口鉴权、分页爬取、反爬策略等核心难点,实现获取视频标题、播放量、点赞数等关键指标。同时强调数据爬取需遵守平台规范,仅限技术研究使用。该方案为B站视频内容分析提供了可靠的数据采集基础,具有实际应用价值。

2503_91057718的博客 2492

vscode配置matlab工作环境

前面有两篇文章我们分别讲了在vscode里面如何配置C语言环境和python环境,那两篇文章总体来说比较复杂,当然这篇也有许多有趣的问题。 附上链接: 文章目录matlab简介基本要求code runner插件与matlab相关的插件添加路径小结code runner是否支持更多语言更多选择另一个选择 matlab简介 MATLAB是美国MathWorks公司出品的商业数学软件,用于数据分析、无线通信、深度学习、图像处理与计算机视觉、信号处理、量化金融与风险管理、机器人,控制系统等领域。 MATLAB是ma

Cachel Wood的博客 4540

spring boot aop

一、简介 AOP(Aspect Orient Programming),即面向切面编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理。 Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。 1.通知(有的地方叫增强)(Advic...

Zllvincent的博客 3868

LLaMA Factory添加新模型template的实战解析

本文主要介绍了LLaMA Factory添加新模型template的实战解析,希望对使用大语言模型的同学们有所帮助。 文章目录 1. 前言 2. 实战解析 2.1 检查代码 2.2 修改代码

herosunly的博客 19万+
上一篇: ubuntu下编译 Hadoop
下一篇: linux常见压缩格式详解
exklin
博客等级 码龄9年 35粉丝 68原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值