《Spring 手撸专栏》第 13 章:行云流水,把AOP动态代理,融入到Bean的生命周期

简介: 实现1. 工程结构2. 定义Advice拦截器链3. 定义 Advisor 访问者4. 方法拦截器5. 代理工厂6. 融入Bean生命周期的自动代理创建者测试1. 事先准备2. 自定义拦截方法3. spring.xml 配置 AOP4. 单元测试

目录


  • 一、前言
  • 二、目标
  • 三、方案
  • 四、实现
  • 1. 工程结构
  • 2. 定义Advice拦截器链
  • 3. 定义 Advisor 访问者
  • 4. 方法拦截器
  • 5. 代理工厂
  • 6. 融入Bean生命周期的自动代理创建者
  • 五、测试
  • 1. 事先准备
  • 2. 自定义拦截方法
  • 3. spring.xml 配置 AOP
  • 4. 单元测试
  • 六、总结



一、前言

嘎小子,这片代码水太深你把握不住!

在电视剧《楚汉传奇》中有这么一段刘邦与韩信的饮酒对话,刘邦问韩信我那个曹参读过书见过世面能带多少兵,韩信说能带一万五,又补充说一万五都吃力。刘邦又一一说出樊哙卢绾周勃,韩信笑着说不足2万,脑子不行。这时候刘邦有点挂不住脸了,问:那我呢,我能带多少兵。韩信说,你能带十万。刘邦一看比他们都多,啊,还行。转头一想就问韩信那你呢,你能带多少兵。韩信喝多了,说啊,我,我多多益善。这时候刘邦恼了领导劲上来了,问:那我为什么能管着你,你给我说,说呀!


这像不像你领导问你,你能写多少代码、搭多少框架、接多少项目。可能很大一部分没经历太多的新人码农,仅仅是能完成一些简单的功能模块开发,而没有办法驾驭整个项目的涉及到的所有工程,也不能为项目提炼出一些可复用的通用性组件模块。在初级码农的心里,接一点需求还好,但没有人带的时候完全接一个较大型项目就会比较慌了,不知道这里有没有坑,自己也把握住不。这些代码一块块的带着能写,但是都弄到一块,就太难了!

在代码开发成长的这条路上,要经历CRUD、ERP查数据、接口包装、功能开发、服务整合、系统建设等,一直到独立带人承担较大型项目的搭建。这一过程需要你能有大量的编写代码经验积累和复杂问题的处理手段,之后才能一段段的把看似独立的模块后者代码片段组装成一个较大型能跑起来的项目。就像 Spring 的开发过程一样,我们总是不断在添加新的功能片段,最后又把技术实现与Spring 容器整合,让使用方可以更简单的运用 Spring 提供的能力。

二、目标

在上一章节我们通过基于 Proxy.newProxyInstance 代理操作中处理方法匹配和方法拦截,对匹配的对象进行自定义的处理操作。并把这样的技术核心内容拆解到 Spring 中,用于实现 AOP 部分,通过拆分后基本可以明确各个类的职责,包括你的代理目标对象属性、拦截器属性、方法匹配属性,以及两种不同的代理操作 JDK 和 CGlib 的方式。

再有了一个 AOP 核心功能的实现后,我们可以通过单元测试的方式进行验证切面功能对方法进行拦截,但如果这是一个面向用户使用的功能,就不太可能让用户这么复杂且没有与 Spring 结合的方式单独使用 AOP,虽然可以满足需求,但使用上还是过去分散。

因此我们需要在本章节完成 AOP 核心功能与 Spring 框架的整合,最终能通过在 Spring 配置的方式完成切面的操作。

三、方案

其实在有了AOP的核心功能实现后,把这部分功能服务融入到 Spring 其实也不难,只不过要解决几个问题,包括:怎么借着 BeanPostProcessor 把动态代理融入到 Bean 的生命周期中,以及如何组装各项切点、拦截、前置的功能和适配对应的代理器。整体设计结构如下图:

0.jpgimage.gif

  • 为了可以让对象创建过程中,能把xml中配置的代理对象也就是切面的一些类对象实例化,就需要用到 BeanPostProcessor 提供的方法,因为这个类的中的方法可以分别作用与 Bean 对象执行初始化前后修改 Bean 的对象的扩展信息。但这里需要集合于 BeanPostProcessor 实现新的接口和实现类,这样才能定向获取对应的类信息。
  • 但因为创建的是代理对象不是之前流程里的普通对象,所以我们需要前置于其他对象的创建,所以在实际开发的过程中,需要在 AbstractAutowireCapableBeanFactory#createBean 优先完成 Bean 对象的判断,是否需要代理,有则直接返回代理对象。在Spring的源码中会有 createBean 和 doCreateBean 的方法拆分
  • 这里还包括要解决方法拦截器的具体功能,提供一些 BeforeAdvice、AfterAdvice 的实现,让用户可以更简化的使用切面功能。除此之外还包括需要包装切面表达式以及拦截方法的整合,以及提供不同类型的代理方式的代理工厂,来包装我们的切面服务。

四、实现

1. 工程结构

small-spring-step-12
└── src
    ├── main
    │   └── java
    │       └── cn.bugstack.springframework
    │           ├── aop
    │           │   ├── aspectj
    │           │   │   └── AspectJExpressionPointcut.java
    │           │   │   └── AspectJExpressionPointcutAdvisor.java
    │           │   ├── framework 
    │           │   │   ├── adapter
    │           │   │   │   └── MethodBeforeAdviceInterceptor.java
    │           │   │   ├── autoproxy
    │           │   │   │   └── MethodBeforeAdviceInterceptor.java
    │           │   │   ├── AopProxy.java
    │           │   │   ├── Cglib2AopProxy.java
    │           │   │   ├── JdkDynamicAopProxy.java
    │           │   │   ├── ProxyFactory.java
    │           │   │   └── ReflectiveMethodInvocation.java
    │           │   ├── AdvisedSupport.java
    │           │   ├── Advisor.java
    │           │   ├── BeforeAdvice.java
    │           │   ├── ClassFilter.java
    │           │   ├── MethodBeforeAdvice.java
    │           │   ├── MethodMatcher.java
    │           │   ├── Pointcut.java
    │           │   ├── PointcutAdvisor.java
    │           │   └── TargetSource.java
    │           ├── beans
    │           │   ├── factory
    │           │   │   ├── config
    │           │   │   │   ├── AutowireCapableBeanFactory.java
    │           │   │   │   ├── BeanDefinition.java
    │           │   │   │   ├── BeanFactoryPostProcessor.java
    │           │   │   │   ├── BeanPostProcessor.java
    │           │   │   │   ├── BeanReference.java
    │           │   │   │   ├── ConfigurableBeanFactory.java
    │           │   │   │   ├── InstantiationAwareBeanPostProcessor.java
    │           │   │   │   └── SingletonBeanRegistry.java
    │           │   │   ├── support
    │           │   │   │   ├── AbstractAutowireCapableBeanFactory.java
    │           │   │   │   ├── AbstractBeanDefinitionReader.java
    │           │   │   │   ├── AbstractBeanFactory.java
    │           │   │   │   ├── BeanDefinitionReader.java
    │           │   │   │   ├── BeanDefinitionRegistry.java
    │           │   │   │   ├── CglibSubclassingInstantiationStrategy.java
    │           │   │   │   ├── DefaultListableBeanFactory.java
    │           │   │   │   ├── DefaultSingletonBeanRegistry.java
    │           │   │   │   ├── DisposableBeanAdapter.java
    │           │   │   │   ├── FactoryBeanRegistrySupport.java
    │           │   │   │   ├── InstantiationStrategy.java
    │           │   │   │   └── SimpleInstantiationStrategy.java  
    │           │   │   ├── support
    │           │   │   │   └── XmlBeanDefinitionReader.java
    │           │   │   ├── Aware.java
    │           │   │   ├── BeanClassLoaderAware.java
    │           │   │   ├── BeanFactory.java
    │           │   │   ├── BeanFactoryAware.java
    │           │   │   ├── BeanNameAware.java
    │           │   │   ├── ConfigurableListableBeanFactory.java
    │           │   │   ├── DisposableBean.java
    │           │   │   ├── FactoryBean.java
    │           │   │   ├── HierarchicalBeanFactory.java
    │           │   │   ├── InitializingBean.java
    │           │   │   └── ListableBeanFactory.java
    │           │   ├── BeansException.java
    │           │   ├── PropertyValue.java
    │           │   └── PropertyValues.java 
    │           ├── context
    │           │   ├── event
    │           │   │   ├── AbstractApplicationEventMulticaster.java 
    │           │   │   ├── ApplicationContextEvent.java 
    │           │   │   ├── ApplicationEventMulticaster.java 
    │           │   │   ├── ContextClosedEvent.java 
    │           │   │   ├── ContextRefreshedEvent.java 
    │           │   │   └── SimpleApplicationEventMulticaster.java 
    │           │   ├── support
    │           │   │   ├── AbstractApplicationContext.java 
    │           │   │   ├── AbstractRefreshableApplicationContext.java 
    │           │   │   ├── AbstractXmlApplicationContext.java 
    │           │   │   ├── ApplicationContextAwareProcessor.java 
    │           │   │   └── ClassPathXmlApplicationContext.java 
    │           │   ├── ApplicationContext.java 
    │           │   ├── ApplicationContextAware.java 
    │           │   ├── ApplicationEvent.java 
    │           │   ├── ApplicationEventPublisher.java 
    │           │   ├── ApplicationListener.java 
    │           │   └── ConfigurableApplicationContext.java
    │           ├── core.io
    │           │   ├── ClassPathResource.java 
    │           │   ├── DefaultResourceLoader.java 
    │           │   ├── FileSystemResource.java 
    │           │   ├── Resource.java 
    │           │   ├── ResourceLoader.java 
    │           │   └── UrlResource.java
    │           └── utils
    │               └── ClassUtils.java
    └── test
        └── java
            └── cn.bugstack.springframework.test
                ├── bean
                │   ├── IUserService.java
                │   ├── UserService.java
                │   └── UserServiceInterceptor.java
                └── ApiTest.java

工程源码公众号「bugstack虫洞栈」,回复:Spring 专栏,获取完整源码

AOP 动态代理融入到Bean的生命周期中类关系,如图 13-2

1.jpg

图 13-2

  • 整个类关系图中可以看到,在以 BeanPostProcessor 接口实现继承的 InstantiationAwareBeanPostProcessor 接口后,做了一个自动代理创建的类 DefaultAdvisorAutoProxyCreator,这个类的就是用于处理整个 AOP 代理融入到 Bean 生命周期中的核心类。
  • DefaultAdvisorAutoProxyCreator 会依赖于拦截器、代理工厂和Pointcut与Advisor的包装服务 AspectJExpressionPointcutAdvisor,由它提供切面、拦截方法和表达式。
  • Spring 的 AOP 把 Advice 细化了 BeforeAdvice、AfterAdvice、AfterReturningAdvice、ThrowsAdvice,目前我们做的测试案例中只用到了 BeforeAdvice,这部分可以对照 Spring 的源码进行补充测试。

2. 定义Advice拦截器链

cn.bugstack.springframework.aop.BeforeAdvice

public interface BeforeAdvice extends Advice {
}

cn.bugstack.springframework.aop.MethodBeforeAdvice

public interface MethodBeforeAdvice extends BeforeAdvice {
    /**
     * Callback before a given method is invoked.
     *
     * @param method method being invoked
     * @param args   arguments to the method
     * @param target target of the method invocation. May be <code>null</code>.
     * @throws Throwable if this object wishes to abort the call.
     *                   Any exception thrown will be returned to the caller if it's
     *                   allowed by the method signature. Otherwise the exception
     *                   will be wrapped as a runtime exception.
     */
    void before(Method method, Object[] args, Object target) throws Throwable;
}
  • 在 Spring 框架中,Advice 都是通过方法拦截器 MethodInterceptor 实现的。环绕 Advice 类似一个拦截器的链路,Before Advice、After advice等,不过暂时我们需要那么多就只定义了一个 MethodBeforeAdvice 的接口定义。

3. 定义 Advisor 访问者

cn.bugstack.springframework.aop.Advisor

public interface Advisor {
    /**
     * Return the advice part of this aspect. An advice may be an
     * interceptor, a before advice, a throws advice, etc.
     * @return the advice that should apply if the pointcut matches
     * @see org.aopalliance.intercept.MethodInterceptor
     * @see BeforeAdvice
     */
    Advice getAdvice();
}

cn.bugstack.springframework.aop.PointcutAdvisor

public interface PointcutAdvisor extends Advisor {
    /**
     * Get the Pointcut that drives this advisor.
     */
    Pointcut getPointcut();
}
  • Advisor 承担了 Pointcut 和 Advice 的组合,Pointcut 用于获取 JoinPoint,而 Advice 决定于 JoinPoint 执行什么操作。

cn.bugstack.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor

public class AspectJExpressionPointcutAdvisor implements PointcutAdvisor {
    // 切面
    private AspectJExpressionPointcut pointcut;
    // 具体的拦截方法
    private Advice advice;
    // 表达式
    private String expression;
    public void setExpression(String expression){
        this.expression = expression;
    }
    @Override
    public Pointcut getPointcut() {
        if (null == pointcut) {
            pointcut = new AspectJExpressionPointcut(expression);
        }
        return pointcut;
    }
    @Override
    public Advice getAdvice() {
        return advice;
    }
    public void setAdvice(Advice advice){
        this.advice = advice;
    }
}
  • AspectJExpressionPointcutAdvisor 实现了 PointcutAdvisor 接口,把切面 pointcut、拦截方法 advice 和具体的拦截表达式包装在一起。这样就可以在 xml 的配置中定义一个 pointcutAdvisor 切面拦截器了。

4. 方法拦截器

cn.bugstack.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor

public class MethodBeforeAdviceInterceptor implements MethodInterceptor {
    private MethodBeforeAdvice advice;
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        this.advice = advice;
    }
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        this.advice.before(methodInvocation.getMethod(), methodInvocation.getArguments(), methodInvocation.getThis());
        return methodInvocation.proceed();
    }
}
  • MethodBeforeAdviceInterceptor 实现了 MethodInterceptor 接口,在 invoke 方法中调用 advice 中的 before 方法,传入对应的参数信息。
  • 而这个 advice.before 则是用于自己实现 MethodBeforeAdvice 接口后做的相应处理。其实可以看到具体的 MethodInterceptor 实现类,其实和我们之前做的测试是一样的,只不过现在交给了 Spring 来处理

5. 代理工厂

cn.bugstack.springframework.aop.framework.ProxyFactory

public class ProxyFactory {
    private AdvisedSupport advisedSupport;
    public ProxyFactory(AdvisedSupport advisedSupport) {
        this.advisedSupport = advisedSupport;
    }
    public Object getProxy() {
        return createAopProxy().getProxy();
    }
    private AopProxy createAopProxy() {
        if (advisedSupport.isProxyTargetClass()) {
            return new Cglib2AopProxy(advisedSupport);
        }
        return new JdkDynamicAopProxy(advisedSupport);
    }
}
  • 其实这个代理工厂主要解决的是关于 JDK 和 Cglib 两种代理的选择问题,有了代理工厂就可以按照不同的创建需求进行控制。

6. 融入Bean生命周期的自动代理创建者

cn.bugstack.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator

public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
    private DefaultListableBeanFactory beanFactory;
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (isInfrastructureClass(beanClass)) return null;
        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
        for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            ClassFilter classFilter = advisor.getPointcut().getClassFilter();
            if (!classFilter.matches(beanClass)) continue;
            AdvisedSupport advisedSupport = new AdvisedSupport();
            TargetSource targetSource = null;
            try {
                targetSource = new TargetSource(beanClass.getDeclaredConstructor().newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
            advisedSupport.setTargetSource(targetSource);
            advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
            advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
            advisedSupport.setProxyTargetClass(false);
            return new ProxyFactory(advisedSupport).getProxy();
        }
        return null;
    }
}
  • 这个 DefaultAdvisorAutoProxyCreator 类的主要核心实现在于 postProcessBeforeInstantiation 方法中,从通过 beanFactory.getBeansOfType 获取 AspectJExpressionPointcutAdvisor 开始。
  • 获取了 advisors 以后就可以遍历相应的 AspectJExpressionPointcutAdvisor 填充对应的属性信息,包括:目标对象、拦截方法、匹配器,之后返回代理对象即可。
  • 那么现在调用方获取到的这个 Bean 对象就是一个已经被切面注入的对象了,当调用方法的时候,则会被按需拦截,处理用户需要的信息。

五、测试

1. 事先准备

public class UserService implements IUserService {
    public String queryUserInfo() {
        try {
            Thread.sleep(new Random(1).nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "小傅哥,100001,深圳";
    }
    public String register(String userName) {
        try {
            Thread.sleep(new Random(1).nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "注册用户:" + userName + " success!";
    }
}
  • 在 UserService 中提供了2个不同方法,另外你还可以增加新的类来加入测试。后面我们的测试过程,会给这个两个方法添加我们的拦截处理,打印方法执行耗时。

2. 自定义拦截方法

public class UserServiceBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("拦截方法:" + method.getName());
    }
}
  • 与上一章节的拦截方法相比,我们不在是实现 MethodInterceptor 接口,而是实现 MethodBeforeAdvice 环绕拦截。在这个方法中我们可以获取到方法的一些信息,如果还开发了它的 MethodAfterAdvice 则可以两个接口一起实现。

3. spring.xml 配置 AOP

<beans>
    <bean id="userService" class="cn.bugstack.springframework.test.bean.UserService"/>
    <bean class="cn.bugstack.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
    <bean id="beforeAdvice" class="cn.bugstack.springframework.test.bean.UserServiceBeforeAdvice"/>
    <bean id="methodInterceptor" class="cn.bugstack.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
        <property name="advice" ref="beforeAdvice"/>
    </bean>
    <bean id="pointcutAdvisor" class="cn.bugstack.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
        <property name="expression" value="execution(* cn.bugstack.springframework.test.bean.IUserService.*(..))"/>
        <property name="advice" ref="methodInterceptor"/>
    </bean>
</beans>
  • 这回再使用 AOP 就可以像 Spring 中一样,通过在 xml 中配置即可。因为我们已经把 AOP 的功能融合到 Bean 的生命周期里去了,你的新增拦截方法都会被自动处理。

4. 单元测试

@Test
public void test_aop() {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
    IUserService userService = applicationContext.getBean("userService", IUserService.class);
    System.out.println("测试结果:" + userService.queryUserInfo());
}
  • 在单元测试中你只需要按照正常获取和使用 Bean 对象即可,不过这个时候如果被切面拦截了,那么其实你获取到的就是对应的代理对象里面的处理操作了。

测试结果

2.jpg

拦截方法:queryUserInfo
测试结果:小傅哥,100001,深圳
Process finished with exit code 0
  • 通过测试结果可以看到,我们已经让拦截方法生效了,也不需要自己手动处理切面、拦截方法等内容。截图上可以看到,这个时候的 IUserService 就是一个代理对象

六、总结

  • 本章节实现 AOP 功能的外在体现主要是把以前自己在单元测试中的切面拦截,交给 Spring 的 xml 配置了,也就不需要自己手动处理了。那么这里有一个非常重要的知识点,就是把相应的功能如何与 Spring 的 Bean 生命周期结合起来,本章节用到的 BeanPostProcessor,因为它可以解决在 Bean 对象执行初始化方法之前,用于修改新实例化 Bean 对象的扩展点,所以我们也就可以处理自己的 AOP 代理对象逻辑了。
  • 一个功能的实现往往包括核心部分、组装部分、链接部分,为了这些各自职责的分工,则需要创建接口和类,由不同关系的继承、实现进行组装。只有明确了各个职责分工,才好灵活的扩展相应的功能逻辑,否则很难驾驭大型系统的开发和建设,也就是那种不好把握的感觉。
  • 目前我们实现的 AOP 与 Spring 源码中的核心逻辑是类似的,但更会偏简单一些,也不会考虑更多的复杂场景遇到的问题,包括是否有构造函数、是否为代理中的切面等。其实也可以看出只要是 Java 中的一些特性,都需要在真实使用的 Spring 中进行完整的实现,否则在使用这些功能的时候就会遇到各种问题。
目录
相关文章
|
4月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
|
12天前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
11天前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
7月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
451 26
|
8月前
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
366 6
|
7月前
|
XML Java 测试技术
Spring AOP—通知类型 和 切入点表达式 万字详解(通俗易懂)
Spring 第五节 AOP——切入点表达式 万字详解!
310 25
|
7月前
|
XML 安全 Java
Spring AOP—深入动态代理 万字详解(通俗易懂)
Spring 第四节 AOP——动态代理 万字详解!
225 24
|
6月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
607 0
|
6月前
|
Java 开发者 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——什么是AOP
本文介绍了Spring Boot中的切面AOP处理。AOP(Aspect Oriented Programming)即面向切面编程,其核心思想是分离关注点。通过AOP,程序可以将与业务逻辑无关的代码(如日志记录、事务管理等)从主要逻辑中抽离,交由专门的“仆人”处理,从而让开发者专注于核心任务。这种机制实现了模块间的灵活组合,使程序结构更加可配置、可扩展。文中以生活化比喻生动阐释了AOP的工作原理及其优势。
230 0
|
8月前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
488 8