Spring AOP切面编程实现原理

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: `Spring AOP`是`Spring`框架中极为重要的核心功能,和`Spring IOC`并称为`Spring`的两大核心模块。顾名思义,**AOP 即 Aspect Oriented Programming,翻译为面向切面编程**。OOP面向对象编程是纵向地对一个事物的抽象,一个对象包括静态的属性信息、动态的方法信息等。而AOP是横向地对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。

1.概述

Spring AOPSpring框架中极为重要的核心功能,和Spring IOC并称为Spring的两大核心模块。顾名思义,AOP 即 Aspect Oriented Programming,翻译为面向切面编程。OOP面向对象编程是纵向地对一个事物的抽象,一个对象包括静态的属性信息、动态的方法信息等。而AOP是横向地对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。

Spring AOP 是利用 CGLIB 和 JDK 动态代理等方式来实现运行期动态方法增强,其目的是将与业务无关的代码单独抽离出来,使其逻辑不再与业务代码耦合,从而降低系统的耦合性,提高程序的可重用性和开发效率。因而 AOP 便成为了日志记录、监控管理、性能统计、异常处理、权限管理、统一认证等各个方面被广泛使用的技术。我们之所以能无感知地在Spring容器bean对象方法前后随意添加代码片段进行逻辑增强,是由于Spring 在运行期帮我们把切面中的代码逻辑动态“织入”到了bean对象方法内,所以说AOP本质上就是一个代理模式

对于代理模式和动态代理技术相关知识点不熟悉的,请先看看之前我总结的:浅析动态代理实现与原理,学习一下动态代理知识点,了解CGlib 和 JDK 两种不同动态代理实现方式原理与区别,并且上面说了Spring AOP就是动态代理技术实现的,只有了解动态代理技术,才能快速掌握今天主题AOP。

2.AOP切面编程示例

既然AOP切面编程的特点就是可以做到对某一个功能进行统一切面处理,对业务代码无侵入,降低耦合度。那么下面我们就根据日志记录这一功能进行实例讲解,对于AOP的编程实现可以基于XML配置,也可以基于注解开发,当下注解开发是主流,所以下面我们基于注解进行示例展示。

切面类

定义一个切面类,来进行日志记录的统一打印。

@Component  // bean组件
@Aspect // 切面类
public class LogAspect {
   
   

    // 切入点
    @Pointcut("execution(* com.shepherd.aop.service.*.*(..))")
    private void pt(){
   
   }

    /**
     * 前置通知
     */
    @Before("pt()")
    public  void beforePrintLog(){
   
   
        System.out.println("前置通知beforePrintLog方法开始记录日志了。。。");
    }

    /**
     * 后置通知
     */
    @AfterReturning("pt()")
    public  void afterReturningPrintLog(){
   
   
        System.out.println("后置通知afterReturningPrintLog方法开始记录日志了。。。");
    }
    /**
     * 异常通知
     */
    @AfterThrowing("pt()")
    public  void afterThrowingPrintLog(){
   
   
        System.out.println("异常通知afterThrowingPrintLog方法开始记录日志了。。。");
    }

    /**
     * 最终通知
     */
    @After("pt()")
    public  void afterPrintLog(){
   
   
        System.out.println("最终通知afterPrintLog方法开始记录日志了。。。");
    }

    /**
     * 环绕通知
     */
    @Around("pt()")
    public Object aroundPrintLog(ProceedingJoinPoint pjp){
   
   
        Object rtValue = null;
        try{
   
   
            Object[] args = pjp.getArgs();//得到方法执行所需的参数

            System.out.println("环绕通知aroundPrintLog方法开始记录日志了。。。前置");

            rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)
      System.out.println(rtValue);

            System.out.println("环绕通知aroundPrintLog方法开始记录日志了。。。后置");
            return rtValue;
        }catch (Throwable t){
   
   
            System.out.println("环绕通知aroundPrintLog方法开始记录日志了。。。异常");
            throw new RuntimeException(t);
        }finally {
   
   
            System.out.println("环绕通知aroundPrintLog方法开始记录日志了。。。最终");
        }
    }
}

首先@Aspect表示该类是一个切面类,只要满足@Pointcut标注的切点表达式,就可以执行相应通知方法增强逻辑打印日志。同时我这里写了aop的所有通知:前置、后置、异常、最终、环绕,其实环绕通知就能实现其他四种通知效果了,但是我为了演示所有通知方式和通知方法执行顺序,就全写了,你可以观察一下执行结果。

业务方法

随便写一个业务方法:

public interface MyService {
   
   
    String doSomething();
}
@Service
public class MyServiceImpl implements MyService{
   
   

    @Override
    public String doSomething() {
   
   
        return "========>>> 业务方法执行成功啦!!! ========>>> ";
    }
}

配置类

声明一个配置类开启aop代理功能和bean组件扫描

@Configuration //配置类
@ComponentScan(basePackages = {
   
   "com.shepherd.aop"})   //扫描bean组件
@EnableAspectJAutoProxy   //开启aop切面功能
public class AopConfig {
   
   

    public static void main(String[] args) {
   
   
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AopConfig.class);
        MyService myService = ac.getBean(MyService.class);
        myService.doSomething();

    }
}

通过以上步骤执行main方法结果如下:

环绕通知aroundPrintLog方法开始记录日志了。。。前置
前置通知beforePrintLog方法开始记录日志了。。。
后置通知afterReturningPrintLog方法开始记录日志了。。。
最终通知afterPrintLog方法开始记录日志了。。。
========>>> 业务方法执行成功啦!!! ========>>> 
环绕通知aroundPrintLog方法开始记录日志了。。。后置
环绕通知aroundPrintLog方法开始记录日志了。。。最终

Spring是需要手动添加@EnableAspectJAutoProxy注解进行aop功能集成的,而Spring Boot中使用自动装配的技术,可以不手动加这个注解就实现集成,因为在自动配置类AopAutoConfiguration中已经集成了@EnableAspectJAutoProxy

项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用

Github地址https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址https://gitee.com/plasticene3/plasticene-boot-starter-parent

微信公众号Shepherd进阶笔记

交流探讨qun:Shepherd_126

3.AOP实现原理

首先来看看Spring是如何集成AspectJ AOP的,这时候目光应该定格在在注解@EnableAspectJAutoProxy

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
   
   

    /**
     * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
     * to standard Java interface-based proxies. The default is {@code false}.
     * 该属性指定是否通过CGLIB进行动态代理,spring默认是根据是否实现了接口来判断使用JDK还是CGLIB,
     * 这也是两种代理主要区别,如果为ture,spring则不做判断直接使用CGLIB代理
     */
    boolean proxyTargetClass() default false;

    /**
     * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
     * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
     * Off by default, i.e. no guarantees that {@code AopContext} access will work.
     * @since 4.3.1
     * 暴露aop代理,这样就可以借助ThreadLocal特性在AopContext在上下文中获取到,可用于解决内部方法调用 a()
     * 调用this.b()时this不是增强代理对象问题,通过AopContext获取即可
     */
    boolean exposeProxy() default false;

}

该注解核心代码:@Import(AspectJAutoProxyRegistrar.class),这也是Spring集成其他功能通用方式了,对于注解@Import不太熟悉的,可以看看我之前总结的:@Import使用及原理详解。来到AspectJAutoProxyRegistrar类:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
   
   

    /**
     * Register, escalate, and configure the AspectJ auto proxy creator based on the value
     * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
     * {@code @Configuration} class.
     */
    @Override
    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   
   

    // 重点 重点 重点   注入AspectJAnnotationAutoProxyCreator
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

    // 根据@EnableAspectJAutoProxy注解属性进行代理方式和是否暴露aop代理等设置
        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
   
   
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
   
   
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
   
   
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

}

可以看到这里@import就是作用就是将AnnotationAwareAspectJAutoProxyCreator注册到容器当中,这个类是Spring AOP的关键

创建代理对象的时机就在创建一个Bean的时候,而创建代理对象的关键工作其实是由AnnotationAwareAspectJAutoProxyCreator完成的。从上面类图可以看出它本质上是一种BeanPostProcessor。对BeanPostProcessor后置处理器不了解的,可以查看之前总结的:后置处理器PostProcessor,这是Spring核心扩展点。 所以它的执行是在完成原始 Bean 构建后的初始化Bean(initializeBean)过程中进行代理对象生成的,最终放到Spring容器中,我们可以看下它的postProcessAfterInitialization 方法,该方法在其上级父类中AbstractAutoProxyCreator实现的:

/**
     * Create a proxy with the configured interceptors if the bean is
     * identified as one to proxy by the subclass.
     * @see #getAdvicesAndAdvisorsForBean
     */
    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   
   
        if (bean != null) {
   
   
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
   
   
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

可以看到只有当earlyProxyReferences集合中不存在cacheKey的时候,才会执行wrapIfNecessary方法。Spring AOP对象生成的时机有两个:一个是提前AOP,提前AOP的对象会被放入到earlyProxyReferences集合当中,Spring循环依赖解决方案中如果某个bean有循环依赖,同时需要代理增强,那么就会提前生成aop代理对象放入earlyProxyReferences中,关于循环依赖解决方案详解,请看之前总结的:Spring循环依赖解决方案 若没有提前,AOP会在Bean的生命周期的最后执行postProcessAfterInitialization的时候进行AOP动态代理。

进入#wrapIfNecessary()方法,核心逻辑:

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   
   

        .......

        // Create proxy if we have advice.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
   
   
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

#getAdvicesAndAdvisorsForBean()遍历Spring容器中所有的bean,判断bean上是否加了@Aspect注解,对加了该注解的类再判断其拥有的所有方法,对于加了通知注解的方法构建出Advisor通知对象放入候选通知链当中。接着基于当前加载的Bean通过切点表达式筛选通知,添加ExposeInvocationInterceptor拦截器,最后对通知链进行排序,得到最终的通知链。得到完整的advice通知链信息后,紧接着通过#createProxy()生成代理对象

    protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
            @Nullable Object[] specificInterceptors, TargetSource targetSource) {
   
   

        if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
   
   
            AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
        }

    // new 一个代理工厂对象
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);

    // 判断使用JDK代理还是CGLIB代理
        if (proxyFactory.isProxyTargetClass()) {
   
   
            // Explicit handling of JDK proxy targets (for introduction advice scenarios)
            if (Proxy.isProxyClass(beanClass)) {
   
   
                // Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
                for (Class<?> ifc : beanClass.getInterfaces()) {
   
   
                    proxyFactory.addInterface(ifc);
                }
            }
        }
        else {
   
   
            // No proxyTargetClass flag enforced, let's apply our default checks...
            if (shouldProxyTargetClass(beanClass, beanName)) {
   
   
                proxyFactory.setProxyTargetClass(true);
            }
            else {
   
   
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }

    // 构建advisor通知链
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
      // 将通知链放入代理工厂
    proxyFactory.addAdvisors(advisors);
    // 将被代理的目标类放入到代理工程中
        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);

        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
   
   
            proxyFactory.setPreFiltered(true);
        }
    // 基于代理工厂获取代理对象返回
        return proxyFactory.getProxy(getProxyClassLoader());
    }

#proxyFactory.getProxy(getProxyClassLoader())

public Object getProxy(@Nullable ClassLoader classLoader) {
   
   
        return createAopProxy().getProxy(classLoader);
    }

#createAopProxy()

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   
   
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
   
   
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
   
   
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
   
   
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
   
   
            return new JdkDynamicAopProxy(config);
        }
    }

AOP的代理方式有两种,一种是CGLIB代理,使用ObjenesisCglibAopProxy来创建代理对象,另一种是JDK动态代理,使用JdkDynamicAopProxy来创建代理对象,最终通过对应的AopProxy#getProxy()生成代理对象,来看看JdkDynamicAopProxy的:

    @Override
    public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
    }

    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)这不就是JDK动态代理技术实现模板代码嘛。到这里aop代理对象就已经生成放到Spring容器中。

接下来我们就来看看AOP是怎么执行增强方法的,也就是如何执行aspect切面的通知方法的?还是以JDK实现的动态代理JdkDynamicAopProxy为例,其实现了InvocationHandler来实现动态代理,意味着调用代理对象的方法会调用JdkDynamicAopProxy中的invoke()方法,核心逻辑如下:

    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
   
        Object oldProxy = null;
        boolean setProxyContext = false;

        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

        try {
   
   

            .......

            Object retVal;

            if (this.advised.exposeProxy) {
   
   
                // Make invocation available if necessary.
        // 暴露aop代理对象
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // Get as late as possible to minimize the time we "own" the target,
            // in case it comes from a pool.
            target = targetSource.getTarget();
            Class<?> targetClass = (target != null ? target.getClass() : null);

            // Get the interception chain for this method.
      // 根据切面通知,获取方法的拦截链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            // Check whether we have any advice. If we don't, we can fallback on direct
            // reflective invocation of the target, and avoid creating a MethodInvocation.
            // 拦截链为空,直接反射调用目标方法
      if (chain.isEmpty()) {
   
   
                // We can skip creating a MethodInvocation: just invoke the target directly
                // Note that the final invoker must be an InvokerInterceptor so we know it does
                // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
   
   
        // 如果不为空,那么会构建一个MethodInvocation对象,调用该对象的proceed()方法执行拦截器链以及目标方法
                // We need to create a method invocation...
                MethodInvocation invocation =
                        new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }

            // Massage return value if necessary.
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                    returnType != Object.class && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
   
   
                // Special case: it returned "this" and the return type of the method
                // is type-compatible. Note that we can't help if the target sets
                // a reference to itself in another returned object.
                retVal = proxy;
            }
            else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
   
   
                throw new AopInvocationException(
                        "Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        }
        finally {
   
   
            if (target != null && !targetSource.isStatic()) {
   
   
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
   
   
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

4.总结

基于以上全部就是今天要讲解的Spring AOP相关知识点啦,AOP作为Spring框架的核心模块,在很多场景都有应用到,如Spring的事务控制就是通过aop实现的。采用横向抽取机制,取代了传统纵向继承体系重复性代码,将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码,从而做到保证开发者在不修改源代码的前提下,为系统中不同的业务组件添加某些通用功能,同时AOP切面编程便于减少系统的重复代码,降低模块间的耦合度,有利于系统未来的可拓展性和可维护性。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
24天前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
AOP(面向切面编程)能够帮助我们在不修改现有代码的前提下,为应用程序添加新的功能或行为。Micronaut框架中的AOP模块通过动态代理机制实现了这一目标。AOP将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高模块化程度。在Micronaut中,带有特定注解的类会在启动时生成代理对象,在运行时拦截方法调用并执行额外逻辑。例如,可以通过创建切面类并在目标类上添加注解来记录方法调用信息,从而在不侵入原有代码的情况下增强应用功能,提高代码的可维护性和可扩展性。
46 1
|
15天前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
2天前
|
设计模式 Java Spring
Spring Boot监听器的底层实现原理
Spring Boot监听器的底层实现原理主要基于观察者模式(也称为发布-订阅模式),这是设计模式中用于实现对象之间一对多依赖的一种常见方式。在Spring Boot中,监听器的实现依赖于Spring框架提供的事件监听机制。
9 1
|
16天前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
57 3
|
1天前
|
负载均衡 Java 网络架构
Spring Cloud原理详解
介绍了Spring Cloud的原理和核心组件,包括服务注册与发现、配置管理、负载均衡、断路器、智能路由、分布式消息传递、分布式追踪和服务熔断等,旨在帮助开发人员快速构建和管理微服务架构中的分布式系统。
6 0
|
1月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
【9月更文挑战第9天】AOP(面向切面编程)通过分离横切关注点提高模块化程度,如日志记录、事务管理等。Micronaut AOP基于动态代理机制,在应用启动时为带有特定注解的类生成代理对象,实现在运行时拦截方法调用并执行额外逻辑。通过简单示例展示了如何在不修改 `CalculatorService` 类的情况下记录 `add` 方法的参数和结果,仅需添加 `@Loggable` 注解即可。这不仅提高了代码的可维护性和可扩展性,还降低了引入新错误的风险。
38 13
|
29天前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
2月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
29 0
Spring高手之路22——AOP切面类的封装与解析
|
2月前
|
Java Spring XML
掌握面向切面编程的秘密武器:Spring AOP 让你的代码优雅转身,横切关注点再也不是难题!
【8月更文挑战第31天】面向切面编程(AOP)通过切面封装横切关注点,如日志记录、事务管理等,使业务逻辑更清晰。Spring AOP提供强大工具,无需在业务代码中硬编码这些功能。本文将深入探讨Spring AOP的概念、工作原理及实际应用,展示如何通过基于注解的配置创建切面,优化代码结构并提高可维护性。通过示例说明如何定义切面类、通知方法及其应用时机,实现方法调用前后的日志记录,展示AOP在分离关注点和添加新功能方面的优势。
44 0
|
2月前
|
Java Spring 容器
彻底改变你的编程人生!揭秘 Spring 框架依赖注入的神奇魔力,让你的代码瞬间焕然一新!
【8月更文挑战第31天】本文介绍 Spring 框架中的依赖注入(DI),一种降低代码耦合度的设计模式。通过 Spring 的 DI 容器,开发者可专注业务逻辑而非依赖管理。文中详细解释了 DI 的基本概念及其实现方式,如构造器注入、字段注入与 setter 方法注入,并提供示例说明如何在实际项目中应用这些技术。通过 Spring 的 @Configuration 和 @Bean 注解,可轻松定义与管理应用中的组件及其依赖关系,实现更简洁、易维护的代码结构。
38 0