Springboot源码分析之EnableAspectJAutoProxy

开发者在进行springboot开发过程中,经常会使用@EnableAspectJAutoProxy注解来启用AspectJ代理。本篇文章将深入探讨@EnableAspectJAutoProxy注解的源码实现细节及使用技巧,并提供大量实例说明,帮助开发者更好地理解和运用该注解。

一、基本概念

在了解@EnableAspectJAutoProxy注解之前,我们需要先了解以下几个相关的概念:

1. 面向切面编程(AOP)

面向切面编程是一种编程范式,它允许开发者在不改变原有代码基础上,通过切面来增强功能,实现关注点分离。 在AOP中,切面是一组横切逻辑,横跨多个类和对象,用于定义应该在何处以及如何应用横切逻辑。AOP主要解决了开发中的横向关注点问题,如日志、性能监控、事务控制等常见业务实现。

2. AspectJ

AspectJ是基于Java的一种AOP框架,并且支持与Spring框架集成。使用AspectJ,可以使用一些类声明一些横切逻辑,并将其称为“切面(Aspect)”,允许在切点(Pointcut)插入“通知(Advice)”,以此增强应用程序的功能并实现关注点分离。

3. 代理

在AOP中,代理是使用JDK动态代理或CGLib代理来实现对目标对象的封装,从而实现原有对象的增强。Spring框架中有两种代理方式:JDK动态代理和CGLib代理。当目标对象实现了至少一个接口时,将使用JDK动态代理。没有实现任何接口时,将使用CGLib代理,即使用类来增强对象。

4. EnableAspectJAutoProxy

@EnableAspectJAutoProxy注解是Spring框架中用于启用AspectJ代理的注解。它会向应用程序上下文中自动添加一个AnnotationAwareAspectJAutoProxyCreator对象,用于自动创建代理实例,并将它们注入到Spring容器中。在@EnableAspectJAutoProxy注解启用的情况下,容器会自动为标有@Aspect注解的类创建代理对象,并将它们注入到容器中。

二、简单用例

在使用@EnableAspectJAutoProxy注解之前,首先需要在pom.xml文件中集成Spring AOP依赖,加入以下代码:

```

org.springframework.boot

spring-boot-starter-aop

```

接下来,需要在配置类上加上@EnableAspectJAutoProxy注解来开启AspectJ代理,如下所示:

```

@Configuration

@EnableAspectJAutoProxy

public class AppConfig {

// 配置其他Bean

}

```

然后,在定义切面时需要使用注解@Aspect来标注:

```

@Aspect

public class LogAspect {

// 定义切入点

@Pointcut("execution(* com.example.demo.service.*.*(..))")

public void pointcut() {}

// 定义通知

@Around("pointcut()")

public Object around(ProceedingJoinPoint point) throws Throwable {

long start = System.currentTimeMillis();

Object result = point.proceed();

long end = System.currentTimeMillis();

System.out.println("执行时间:" + (end - start));

return result;

}

}

```

现在,已经完成了AspectJ的配置。在运行时,就会在被@Aspect注入的类中切入对应的逻辑,带来额外的功能或行为。

三、@EnableAspectJAutoProxy注解实现分析

1. 原理概述

@EnableAspectJAutoProxy注解是Spring框架中用于启用AspectJ代理的注解。它本质上是一个@Import注解,用于向配置类中注入AnnotationAwareAspectJAutoProxyCreator,该对象是AspectJ自动代理创建器,用于自动创建代理对象。其本质是一个BeanPostProcessor对象,会在Bean对象初始化之前或之后代理bean,为我们提供切面功能。

在开启AspectJ代理的情况下,容器会为标有@Aspect注解的类创建代理对象,并将它注入到容器中。当我们在IOC容器中获取标有@Aspect注解的Bean时,容器会返回其代理对象而不是原始对象。

@EnableAspectJAutoProxy注解与Spring AOP的实现有关。在Spring AOP中,容器创建代理对象是通过AspectJAnnotationAutoProxyCreator实现的。在@EnableAspectJAutoProxy注解的作用下,AnnotationAwareAspectJAutoProxyCreator继承了AspectJAnnotationAutoProxyCreator,并将自动代理创建器的创建和后续处理逻辑注入到了Spring容器中。

2. 注解实现详解

@EnableAspectJAutoProxy源码如下所示:

```

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Import(AutoProxyRegistrar.class)

public @interface EnableAspectJAutoProxy {

boolean proxyTargetClass() default false;

boolean exposeProxy() default false;

}

```

从代码中可以看出,@EnableAspectJAutoProxy注解主要包含两个属性:proxyTargetClass和exposeProxy。其中,proxyTargetClass用于指定代理目标类,exposeProxy属性用于指定是否能通过AopContext来访问当前代理对象。

其中,@Import(AutoProxyRegistrar.class)是该注解的核心,它会向容器中注入配置增强的对象,即AnnotationAwareAspectJAutoProxyCreator对象,该对象是AspectJ自动代理创建器,目的是为了为目标Bean创建代理对象,从而实现切面。

@EnableAspectJAutoProxy注解的注入过程由AutoProxyRegistrar类负责,它是一个ImportBeanDefinitionRegistrar接口的实现类。该类被@Import注解修饰,会在容器启动时自动调用。AutoProxyRegistrar类的主要功能是处理注解@EnableAspectJAutoProxy,根据注解中的参数生成对应的AnnotationAwareAspectJAutoProxyCreator对象,将其注入到容器中。

AutoProxyRegistrar类的代码如下:

```

class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

// 省略其他代码

@Override

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);

if (enableAspectJAutoProxy != null) {

if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {

AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);

}

if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {

// AOP框架支持在AOP代理对象实现类中注入当前AOP代理对象,

// exposeProxy用于指定注入的代理对象是否为当前对象,并且设置注入的属性名

AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);

}

}

}

// 省略其他代码

}

```

在这段代码中,registerBeanDefinitions方法会先调用AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)方法,该方法主要进行容器中BeanPostProcessor对象是否存在的检测以及向容器中注入AnnotationAwareAspectJAutoProxyCreator对象,从而实现对目标Bean进行代理的功能。

接下来,代码会读取@EnableAspectJAutoProxy注解的proxyTargetClass属性和exposeProxy属性,并分别调用AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry)方法和AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry)方法来处理这些属性。其中,forceAutoProxyCreatorToUseClassProxying(registry)方法是用来区分JDK代理和CGLib代理,而forceAutoProxyCreatorToExposeProxy(registry)方法则是用于控制容器是否可以获取当前代理对象。

三、使用建议

@EnableAspectJAutoProxy注解可以方便快捷地开启AspectJ代理,从而实现切面功能。不过,在使用过程中需要小心。以下是使用该注解的一些建议:

1. 抓住切入点时机

如果切入点设置的不够精细,会造成切入时机不准确的问题。在定义切入点的时候,应当尽可能地准确捕捉业务逻辑的粒度,以便我们尽可能地对目标方法进行控制或增强。

2. 注入的对象是否代理对象

在使用@EnableAspectJAutoProxy注解时,需要注意获取的对象是否为代理对象。如果我们需要从容器中获取标有@Aspect注解的Bean对它进行需要执行的方法,那么我们应该保证获取的对象是代理对象,否则我们将得到原始对象而不是代理对象。获取代理对象的方法一般是通过实现了ApplicationContextAware接口来获取ApplicationContext对象,通过调用ApplicationContext中的getBean方法来获取代理对象。

3. 仔细处理代理顺序

在一个Bean被多个切面所代理的情况下,我们需要了解各切面的优先级。在AspectJ切面中,如果可能,应在通知类型上声明优先级,以明确切面单元之间的执行顺序。Spring AOP采用@Order注解或Order接口来指定优先级,如:

```

@Aspect

@Order(2)

public class LoggingAspect {

// 定义通知

}

```

```

@Aspect

public class SecurityAspect {

// 定义通知

}

```

4. 不要让代理对象自己调用自己的非public方法

如果代理对象自己调用自己的非public方法,将无法拦截。因此,在使用@EnableAspectJAutoProxy注解时,应避免在代理对象自己的public方法中调用自己的非public方法。

5. 不要过度使用切面

切面需要运行时检查,这会产生额外的性能开销。因此,切面应该只在必要的情况下使用。

四、总结

@EnableAspectJAutoProxy注解是Spring框架中用于启用AspectJ代理的注解,它会向IOC容器中自动注入AnnotationAwareAspectJAutoProxyCreator对象,用于自动创建AspectJ代理对象。通过本篇文章,我们对@EnableAspectJAutoProxy注解的使用方法、原理和注意事项进行了详细介绍,并提供了大量实例和使用建议,希望能够对读者在应用@EnableAspectJAutoProxy注解时有所帮助。 如果你喜欢我们三七知识分享网站的文章, 欢迎您分享或收藏知识分享网站文章 欢迎您到我们的网站逛逛喔!https://www.37seo.cn/

点赞(41) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿
发表
评论
返回
顶部