From 931ce1fdc98bca81be276fa190e2800a99ada274 Mon Sep 17 00:00:00 2001 From: linlei Date: Mon, 15 Apr 2024 16:38:59 +0800 Subject: [PATCH] =?UTF-8?q?AspectInstanceFactory=E6=BA=90=E7=A0=81?= =?UTF-8?q?=E5=88=86=E6=9E=90=20MetadataAwareAspectInstanceFactory?= =?UTF-8?q?=E6=BA=90=E7=A0=81=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 + spring-aop/pom.xml | 3 + .../pom.xml | 14 + .../README.md | 386 +++++++++++++ .../spring-aop-aspectInstanceFactory/pom.xml | 14 + .../xcs/spring/AspectInstanceFactoryDemo.java | 39 ++ .../main/java/com/xcs/spring/MyAspect.java | 8 + .../main/java/com/xcs/spring/AppConfig.java | 2 +- .../main/java/com/xcs/spring/AspectDemo.java | 6 +- .../{LoggingAspect.java => MyAspect.java} | 2 +- .../java/com/xcs/spring/MyTestService.java | 11 + .../README.md | 533 ++++++++++++++++++ .../pom.xml | 23 + ...etadataAwareAspectInstanceFactoryDemo.java | 41 ++ .../main/java/com/xcs/spring/MyAspect.java | 8 + 15 files changed, 1089 insertions(+), 3 deletions(-) create mode 100644 spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/pom.xml create mode 100644 spring-aop/spring-aop-aspectInstanceFactory/README.md create mode 100644 spring-aop/spring-aop-aspectInstanceFactory/pom.xml create mode 100644 spring-aop/spring-aop-aspectInstanceFactory/src/main/java/com/xcs/spring/AspectInstanceFactoryDemo.java create mode 100644 spring-aop/spring-aop-aspectInstanceFactory/src/main/java/com/xcs/spring/MyAspect.java rename spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/{LoggingAspect.java => MyAspect.java} (94%) create mode 100644 spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyTestService.java create mode 100644 spring-aop/spring-aop-metadataAwareAspectInstanceFactory/README.md create mode 100644 spring-aop/spring-aop-metadataAwareAspectInstanceFactory/pom.xml create mode 100644 spring-aop/spring-aop-metadataAwareAspectInstanceFactory/src/main/java/com/xcs/spring/MetadataAwareAspectInstanceFactoryDemo.java create mode 100644 spring-aop/spring-aop-metadataAwareAspectInstanceFactory/src/main/java/com/xcs/spring/MyAspect.java diff --git a/README.md b/README.md index b90c19d..ea5fd39 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,8 @@ - [TargetSource](spring-aop/spring-aop-targetSource/README.md):管理AOP代理对象的获取与释放。 - [@EnableAspectJAutoProxy](spring-aop/spring-aop-enableAspectJAutoProxy/README.md):启用AspectJ切面自动代理。 - [@EnableLoadTimeWeaving](spring-aop/spring-aop-enableLoadTimeWeaving/README.md):启用Spring加载时编织。 + - [AspectInstanceFactory](spring-aop/spring-aop-aspectInstanceFactory/README.md):创建切面实例,支持多种实现方式。 + - [MetadataAwareAspectInstanceFactory](spring-aop/spring-aop-metadataAwareAspectInstanceFactory/README.md):管理切面实例和元数据,支持多种实例化策略和生命周期管理。 + Spring AOT diff --git a/spring-aop/pom.xml b/spring-aop/pom.xml index b4a40c9..0d37dae 100644 --- a/spring-aop/pom.xml +++ b/spring-aop/pom.xml @@ -34,6 +34,9 @@ spring-aop-advice-throwsAdvice spring-aop-advice-introductionInterceptor spring-aop-aopProxyFactory + spring-aop-annotationAwareAspectJAutoProxyCreator + spring-aop-aspectInstanceFactory + spring-aop-metadataAwareAspectInstanceFactory 4.0.0 diff --git a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/pom.xml b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/pom.xml new file mode 100644 index 0000000..8e81898 --- /dev/null +++ b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/pom.xml @@ -0,0 +1,14 @@ + + + + com.xcs.spring + spring-aop + 0.0.1-SNAPSHOT + + + 4.0.0 + spring-aop-annotationAwareAspectJAutoProxyCreator + + \ No newline at end of file diff --git a/spring-aop/spring-aop-aspectInstanceFactory/README.md b/spring-aop/spring-aop-aspectInstanceFactory/README.md new file mode 100644 index 0000000..718a46e --- /dev/null +++ b/spring-aop/spring-aop-aspectInstanceFactory/README.md @@ -0,0 +1,386 @@ +## AspectInstanceFactory + +- [AspectInstanceFactory](#aspectinstancefactory) + - [一、基本信息](#一基本信息) + - [二、基本描述](#二基本描述) + - [三、主要功能](#三主要功能) + - [四、接口源码](#四接口源码) + - [五、主要实现](#五主要实现) + - [六、最佳实践](#六最佳实践) + - [七、源码分析](#七源码分析) + - [SimpleAspectInstanceFactory](#simpleaspectinstancefactory) + - [SingletonAspectInstanceFactory](#singletonaspectinstancefactory) + - [SimpleBeanFactoryAwareAspectInstanceFactory](#simplebeanfactoryawareaspectinstancefactory) + - [八、常见问题](#八常见问题) + +### 一、基本信息 + +✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https://github.com/xuchengsheng/spring-reading) + +### 二、基本描述 + +`AspectInstanceFactory` 接口是 Spring AOP 中的关键接口,负责在运行时动态创建切面实例,以适应不同的场景和需求,其实现类通过 `getAspectInstance()` 方法提供切面实例,并可指定切面的创建模式。 + +### 三、主要功能 + +1. **动态创建切面实例** + + + 允许在运行时动态地创建切面实例,以便在应用程序中应用切面功能。 + +2. **提供切面实例** + + + 通过 `getAspectInstance()` 方法获取切面实例,以供 Spring AOP 使用。 + +3. **管理切面生命周期** + + + 可控制切面实例的生命周期,例如可以指定为单例模式(Singleton)或原型模式(Prototype)。 + +4. **灵活适应不同需求** + + + 允许根据应用程序的需求定制切面实例的创建和管理方式,提供了灵活性和可扩展性。 + +### 四、接口源码 + + `AspectInstanceFactory`接口,用于提供 AspectJ 切面的实例。它与 Spring 的 bean 工厂解耦,通过 `getAspectInstance()` 方法创建切面实例,并通过 `getAspectClassLoader()` 方法公开切面类加载器。此接口还继承了 `Ordered` 接口,以表达切面在链中的顺序值。 + +```java +/** + * 用于提供一个 AspectJ 切面实例的接口,与 Spring 的 bean 工厂解耦。 + * + *

扩展了 {@link org.springframework.core.Ordered} 接口,用于表达链中底层切面的顺序值。 + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 2.0 + * @see org.springframework.beans.factory.BeanFactory#getBean + */ +public interface AspectInstanceFactory extends Ordered { + + /** + * 创建此工厂的切面实例。 + * @return 切面实例(永远不会为 {@code null}) + */ + Object getAspectInstance(); + + /** + * 公开此工厂使用的切面类加载器。 + * @return 切面类加载器(对于引导加载器,为 {@code null}) + * @see org.springframework.util.ClassUtils#getDefaultClassLoader() + */ + @Nullable + ClassLoader getAspectClassLoader(); + +} +``` + +### 五、主要实现 + +1. **SimpleAspectInstanceFactory** + + + 一个简单的切面实例工厂,用于创建基于注解的切面实例。 + +2. **SingletonAspectInstanceFactory** + + + 一个单例的切面实例工厂,用于创建单例的切面实例。 + +3. **SimpleBeanFactoryAwareAspectInstanceFactory** + + + 一个简单的 Bean 工厂感知切面实例工厂,用于在创建切面实例时考虑 Bean 工厂的上下文信息。 + +### 六、最佳实践 + +使用不同类型的 `AspectInstanceFactory` 实现类来创建和管理切面实例。首先,通过 `SimpleAspectInstanceFactory` 和 `SingletonAspectInstanceFactory` 分别创建简单实例和单例实例的切面。然后,通过注册一个名为 "myAspect" 的单例 bean,并将其用于配置 `SimpleBeanFactoryAwareAspectInstanceFactory`,从而创建一个依赖于 Bean 工厂的切面实例。最后,展示了获取 `SimpleBeanFactoryAwareAspectInstanceFactory` 实例的切面对象,并输出其结果。 + +```java +public class AspectInstanceFactoryDemo { + + public static void main(String[] args) { + // 使用 SimpleAspectInstanceFactory 创建切面实例 + SimpleAspectInstanceFactory sAif = new SimpleAspectInstanceFactory(MyAspect.class); + System.out.println("SimpleAspectInstanceFactory (1): " + sAif.getAspectInstance()); + System.out.println("SimpleAspectInstanceFactory (2): " + sAif.getAspectInstance()); + + // 使用 SingletonAspectInstanceFactory 创建单例切面实例 + SingletonAspectInstanceFactory singletonAif = new SingletonAspectInstanceFactory(new MyAspect()); + System.out.println("SingletonAspectInstanceFactory (1): " + singletonAif.getAspectInstance()); + System.out.println("SingletonAspectInstanceFactory (2): " + singletonAif.getAspectInstance()); + + // 创建一个 DefaultListableBeanFactory 实例,用于注册和管理 bean + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + // 注册一个名为 "myAspect" 的单例 bean,类型为 MyAspect + beanFactory.registerSingleton("myAspect", new MyAspect()); + // 创建一个切面工厂的 BeanDefinition + RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class); + // 设置切面工厂的属性 aspectBeanName 为 "myAspect" + aspectFactoryDef.getPropertyValues().add("aspectBeanName", "myAspect"); + // 设置切面工厂为合成的,即不对外暴露 + aspectFactoryDef.setSynthetic(true); + // 注册名为 "simpleBeanFactoryAwareAspectInstanceFactory" 的 bean,并使用切面工厂的 BeanDefinition + beanFactory.registerBeanDefinition("simpleBeanFactoryAwareAspectInstanceFactory", aspectFactoryDef); + // 从 BeanFactory 中获取 SimpleBeanFactoryAwareAspectInstanceFactory 的实例 + SimpleBeanFactoryAwareAspectInstanceFactory simpleBeanFactoryAwareAif = beanFactory.getBean(SimpleBeanFactoryAwareAspectInstanceFactory.class); + System.out.println("SimpleBeanFactoryAwareAspectInstanceFactory (1): " + simpleBeanFactoryAwareAif.getAspectInstance()); + System.out.println("SimpleBeanFactoryAwareAspectInstanceFactory (2): " + simpleBeanFactoryAwareAif.getAspectInstance()); + } +} +``` + +运行结果,通过不同的切面实例工厂创建切面对象的情况:`SimpleAspectInstanceFactory` 每次调用 `getAspectInstance()` 都会创建一个新的切面对象,因此得到的实例不同;而 `SingletonAspectInstanceFactory` 返回的是单例对象,所以多次调用 `getAspectInstance()` 得到的是同一个实例;`SimpleBeanFactoryAwareAspectInstanceFactory` 从 `BeanFactory` 中获取指定名称的 bean,该 bean 默认是单例的,因此也得到相同的实例。 + +```java +SimpleAspectInstanceFactory (1): com.xcs.spring.MyAspect@6d8a00e3 +SimpleAspectInstanceFactory (2): com.xcs.spring.MyAspect@548b7f67 +SingletonAspectInstanceFactory (1): com.xcs.spring.MyAspect@5f375618 +SingletonAspectInstanceFactory (2): com.xcs.spring.MyAspect@5f375618 +SimpleBeanFactoryAwareAspectInstanceFactory (1): com.xcs.spring.MyAspect@41ee392b +SimpleBeanFactoryAwareAspectInstanceFactory (2): com.xcs.spring.MyAspect@41ee392b +``` + +### 七、源码分析 + +#### SimpleAspectInstanceFactory + + `SimpleAspectInstanceFactory`类是 `AspectInstanceFactory` 接口的实现。每次调用 `getAspectInstance()` 方法创建指定切面类的新实例。它通过反射机制在运行时实例化切面类,并提供了方法来获取切面类、获取切面类的类加载器以及确定切面实例的顺序。 + +```java +/** + * {@link AspectInstanceFactory} 接口的实现类,用于在每次调用 {@link #getAspectInstance()} 方法时为指定的切面类创建一个新实例。 + * 创建新实例的切面工厂。 + * + * @author Juergen Hoeller + * @since 2.0.4 + */ +public class SimpleAspectInstanceFactory implements AspectInstanceFactory { + + // 切面类 + private final Class aspectClass; + + /** + * 为给定的切面类创建一个新的 SimpleAspectInstanceFactory。 + * @param aspectClass 切面类 + */ + public SimpleAspectInstanceFactory(Class aspectClass) { + Assert.notNull(aspectClass, "Aspect class must not be null"); + this.aspectClass = aspectClass; + } + + /** + * 返回指定的切面类(永远不为 {@code null})。 + */ + public final Class getAspectClass() { + return this.aspectClass; + } + + @Override + public final Object getAspectInstance() { + try { + // 使用反射获取切面类的可访问构造函数,并创建新实例 + return ReflectionUtils.accessibleConstructor(this.aspectClass).newInstance(); + } catch (NoSuchMethodException ex) { + throw new AopConfigException("No default constructor on aspect class: " + this.aspectClass.getName(), ex); + } catch (InstantiationException ex) { + throw new AopConfigException("Unable to instantiate aspect class: " + this.aspectClass.getName(), ex); + } catch (IllegalAccessException ex) { + throw new AopConfigException("Could not access aspect constructor: " + this.aspectClass.getName(), ex); + } catch (InvocationTargetException ex) { + throw new AopConfigException("Failed to invoke aspect constructor: " + this.aspectClass.getName(), ex.getTargetException()); + } + } + + @Override + @Nullable + public ClassLoader getAspectClassLoader() { + // 返回切面类的类加载器 + return this.aspectClass.getClassLoader(); + } + + /** + * 确定此工厂的切面实例的顺序, + * 可通过实现 {@link org.springframework.core.Ordered} 接口表达实例特定的顺序, + * 或者使用一个默认顺序。 + * @see org.springframework.core.Ordered + * @see #getOrderForAspectClass + */ + @Override + public int getOrder() { + return getOrderForAspectClass(this.aspectClass); + } + + /** + * 确定在切面实例没有通过实现 {@link org.springframework.core.Ordered} 接口表达实例特定顺序时的后备顺序。 + *

默认实现简单地返回 {@code Ordered.LOWEST_PRECEDENCE}。 + * @param aspectClass 切面类 + */ + protected int getOrderForAspectClass(Class aspectClass) { + return Ordered.LOWEST_PRECEDENCE; + } +} +``` + +#### SingletonAspectInstanceFactory + + `SingletonAspectInstanceFactory` 类是 `AspectInstanceFactory` 接口的实现。该类通过指定的单例对象作为后端支持,每次调用 `getAspectInstance()` 方法时都返回相同的实例。此外,它还提供了方法来获取切面实例的类加载器以及确定切面实例的顺序,支持实现了 `Ordered` 接口的切面实例。 + +```java +/** + * {@link AspectInstanceFactory} 接口的实现类,由指定的单例对象支持, + * 每次调用 {@link #getAspectInstance()} 方法时返回相同的实例。 + * 单例切面实例工厂。 + * + * 由指定的单例对象支持,每次调用 getAspectInstance() 方法时返回相同的实例。 + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 2.0 + * @see SimpleAspectInstanceFactory + */ +@SuppressWarnings("serial") +public class SingletonAspectInstanceFactory implements AspectInstanceFactory, Serializable { + + // 单例切面实例 + private final Object aspectInstance; + + /** + * 为给定的切面实例创建一个新的 SingletonAspectInstanceFactory。 + * @param aspectInstance 单例切面实例 + */ + public SingletonAspectInstanceFactory(Object aspectInstance) { + Assert.notNull(aspectInstance, "Aspect instance must not be null"); + this.aspectInstance = aspectInstance; + } + + @Override + public final Object getAspectInstance() { + // 返回单例切面实例 + return this.aspectInstance; + } + + @Override + @Nullable + public ClassLoader getAspectClassLoader() { + // 返回切面实例的类加载器 + return this.aspectInstance.getClass().getClassLoader(); + } + + /** + * 确定此工厂的切面实例的顺序, + * 可通过实现 {@link org.springframework.core.Ordered} 接口表达实例特定的顺序, + * 或者使用一个默认顺序。 + * @see org.springframework.core.Ordered + * @see #getOrderForAspectClass + */ + @Override + public int getOrder() { + if (this.aspectInstance instanceof Ordered) { + // 如果切面实例实现了 Ordered 接口,则返回其顺序 + return ((Ordered) this.aspectInstance).getOrder(); + } + // 否则返回切面实例类的默认顺序 + return getOrderForAspectClass(this.aspectInstance.getClass()); + } + + /** + * 确定在切面实例没有通过实现 {@link org.springframework.core.Ordered} 接口表达实例特定顺序时的后备顺序。 + *

默认实现简单地返回 {@code Ordered.LOWEST_PRECEDENCE}。 + * @param aspectClass 切面类 + */ + protected int getOrderForAspectClass(Class aspectClass) { + return Ordered.LOWEST_PRECEDENCE; + } + +} +``` + +#### SimpleBeanFactoryAwareAspectInstanceFactory + +`SimpleBeanFactoryAwareAspectInstanceFactory` 类是 `AspectInstanceFactory` 接口的实现。该类通过配置的 bean 名称从 `BeanFactory` 中定位切面实例。每次调用 `getAspectInstance()` 方法时,都会查找并返回指定名称的 bean。此外,它还提供了方法来获取切面实例的类加载器以及确定切面实例的顺序,支持实现了 `Ordered` 接口的切面实例。 + +```java +/** + * {@link AspectInstanceFactory} 接口的实现类,通过配置的 bean 名称从 {@link org.springframework.beans.factory.BeanFactory} 中定位切面。 + * SimpleBeanFactoryAwareAspectInstanceFactory 类。 + * + * 通过配置的 bean 名称从 BeanFactory 中定位切面。 + * + * @author Rob Harrop + * @author Juergen Hoeller + * @since 2.0 + */ +public class SimpleBeanFactoryAwareAspectInstanceFactory implements AspectInstanceFactory, BeanFactoryAware { + + // 切面 bean 名称 + @Nullable + private String aspectBeanName; + + // BeanFactory + @Nullable + private BeanFactory beanFactory; + + /** + * 设置切面 bean 的名称。调用 {@link #getAspectInstance()} 时返回该 bean。 + * @param aspectBeanName 切面 bean 名称 + */ + public void setAspectBeanName(String aspectBeanName) { + this.aspectBeanName = aspectBeanName; + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + Assert.notNull(this.aspectBeanName, "'aspectBeanName' is required"); + } + + /** + * 从 BeanFactory 中查找切面 bean 并返回。 + * @see #setAspectBeanName + */ + @Override + public Object getAspectInstance() { + Assert.state(this.beanFactory != null, "No BeanFactory set"); + Assert.state(this.aspectBeanName != null, "No 'aspectBeanName' set"); + return this.beanFactory.getBean(this.aspectBeanName); + } + + @Override + @Nullable + public ClassLoader getAspectClassLoader() { + if (this.beanFactory instanceof ConfigurableBeanFactory) { + return ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader(); + } else { + return ClassUtils.getDefaultClassLoader(); + } + } + + @Override + public int getOrder() { + if (this.beanFactory != null && this.aspectBeanName != null && + this.beanFactory.isSingleton(this.aspectBeanName) && + this.beanFactory.isTypeMatch(this.aspectBeanName, Ordered.class)) { + return ((Ordered) this.beanFactory.getBean(this.aspectBeanName)).getOrder(); + } + return Ordered.LOWEST_PRECEDENCE; + } +} +``` + +### 八、常见问题 + +1. **切面实例化方式** + + + 如何创建切面实例?不同的实现类可能采用不同的实例化方式,比如单例、原型等。 + +2. **切面对象生命周期** + + + 切面实例是单例还是多例?在 Spring AOP 中,切面对象通常是单例的,但也可以是原型的,这可能会影响到切面对象的状态管理和线程安全性。 + +3. **切面对象获取方式** + + + 切面对象是如何被获取的?有些实现类可能通过配置文件指定 bean 名称,然后从 `BeanFactory` 中获取,而另一些可能直接实例化切面对象。 + +4. **切面对象依赖注入** + + + 切面对象是否可以依赖注入其他 Spring 管理的 bean?如果是,如何实现依赖注入? + +5. **切面对象的顺序** + + + 如果多个切面对象同时存在,它们的执行顺序是如何确定的?是否可以通过实现 `Ordered` 接口或其他方式指定切面对象的执行顺序? \ No newline at end of file diff --git a/spring-aop/spring-aop-aspectInstanceFactory/pom.xml b/spring-aop/spring-aop-aspectInstanceFactory/pom.xml new file mode 100644 index 0000000..9086e79 --- /dev/null +++ b/spring-aop/spring-aop-aspectInstanceFactory/pom.xml @@ -0,0 +1,14 @@ + + + + com.xcs.spring + spring-aop + 0.0.1-SNAPSHOT + + + 4.0.0 + spring-aop-aspectInstanceFactory + + \ No newline at end of file diff --git a/spring-aop/spring-aop-aspectInstanceFactory/src/main/java/com/xcs/spring/AspectInstanceFactoryDemo.java b/spring-aop/spring-aop-aspectInstanceFactory/src/main/java/com/xcs/spring/AspectInstanceFactoryDemo.java new file mode 100644 index 0000000..617d481 --- /dev/null +++ b/spring-aop/spring-aop-aspectInstanceFactory/src/main/java/com/xcs/spring/AspectInstanceFactoryDemo.java @@ -0,0 +1,39 @@ +package com.xcs.spring; + +import org.springframework.aop.aspectj.SimpleAspectInstanceFactory; +import org.springframework.aop.aspectj.SingletonAspectInstanceFactory; +import org.springframework.aop.config.SimpleBeanFactoryAwareAspectInstanceFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; + +public class AspectInstanceFactoryDemo { + + public static void main(String[] args) { + // 使用 SimpleAspectInstanceFactory 创建切面实例 + SimpleAspectInstanceFactory sAif = new SimpleAspectInstanceFactory(MyAspect.class); + System.out.println("SimpleAspectInstanceFactory (1): " + sAif.getAspectInstance()); + System.out.println("SimpleAspectInstanceFactory (2): " + sAif.getAspectInstance()); + + // 使用 SingletonAspectInstanceFactory 创建单例切面实例 + SingletonAspectInstanceFactory singletonAif = new SingletonAspectInstanceFactory(new MyAspect()); + System.out.println("SingletonAspectInstanceFactory (1): " + singletonAif.getAspectInstance()); + System.out.println("SingletonAspectInstanceFactory (2): " + singletonAif.getAspectInstance()); + + // 创建一个 DefaultListableBeanFactory 实例,用于注册和管理 bean + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + // 注册一个名为 "myAspect" 的单例 bean,类型为 MyAspect + beanFactory.registerSingleton("myAspect", new MyAspect()); + // 创建一个切面工厂的 BeanDefinition + RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class); + // 设置切面工厂的属性 aspectBeanName 为 "myAspect" + aspectFactoryDef.getPropertyValues().add("aspectBeanName", "myAspect"); + // 设置切面工厂为合成的,即不对外暴露 + aspectFactoryDef.setSynthetic(true); + // 注册名为 "simpleBeanFactoryAwareAspectInstanceFactory" 的 bean,并使用切面工厂的 BeanDefinition + beanFactory.registerBeanDefinition("simpleBeanFactoryAwareAspectInstanceFactory", aspectFactoryDef); + // 从 BeanFactory 中获取 SimpleBeanFactoryAwareAspectInstanceFactory 的实例 + SimpleBeanFactoryAwareAspectInstanceFactory simpleBeanFactoryAwareAif = beanFactory.getBean(SimpleBeanFactoryAwareAspectInstanceFactory.class); + System.out.println("SimpleBeanFactoryAwareAspectInstanceFactory (1): " + simpleBeanFactoryAwareAif.getAspectInstance()); + System.out.println("SimpleBeanFactoryAwareAspectInstanceFactory (2): " + simpleBeanFactoryAwareAif.getAspectInstance()); + } +} diff --git a/spring-aop/spring-aop-aspectInstanceFactory/src/main/java/com/xcs/spring/MyAspect.java b/spring-aop/spring-aop-aspectInstanceFactory/src/main/java/com/xcs/spring/MyAspect.java new file mode 100644 index 0000000..eb070bc --- /dev/null +++ b/spring-aop/spring-aop-aspectInstanceFactory/src/main/java/com/xcs/spring/MyAspect.java @@ -0,0 +1,8 @@ +package com.xcs.spring; + +import org.aspectj.lang.annotation.Aspect; + +@Aspect +class MyAspect { + +} diff --git a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AppConfig.java b/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AppConfig.java index 23375bb..a8a3b1d 100644 --- a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AppConfig.java +++ b/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AppConfig.java @@ -6,6 +6,6 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy -@ComponentScan(basePackages = "com.xcs.spring") +@ComponentScan("com.xcs.spring") public class AppConfig { } diff --git a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AspectDemo.java b/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AspectDemo.java index 5d723ab..b898878 100644 --- a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AspectDemo.java +++ b/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AspectDemo.java @@ -6,7 +6,11 @@ public class AspectDemo { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); MyService service = context.getBean(MyService.class); - System.out.println("service.getClass() = " + service.getClass()); + System.out.println("MyService = " + service.getClass()); service.doSomething(); + + MyTestService myTestService = context.getBean(MyTestService.class); + System.out.println("MyTestService = " + myTestService.getClass()); + myTestService.test(); } } diff --git a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/LoggingAspect.java b/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyAspect.java similarity index 94% rename from spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/LoggingAspect.java rename to spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyAspect.java index 97bf06a..f2d8c7c 100644 --- a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/LoggingAspect.java +++ b/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyAspect.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Component; @Aspect @Component -class LoggingAspect { +class MyAspect { @Before("execution(* com.xcs.spring.MyService.doSomething(..))") public void beforeAdvice() { diff --git a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyTestService.java b/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyTestService.java new file mode 100644 index 0000000..cf8a64f --- /dev/null +++ b/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyTestService.java @@ -0,0 +1,11 @@ +package com.xcs.spring; + +import org.springframework.stereotype.Service; + +@Service +public class MyTestService { + + public void test() { + System.out.println("test"); + } +} diff --git a/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/README.md b/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/README.md new file mode 100644 index 0000000..e144b93 --- /dev/null +++ b/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/README.md @@ -0,0 +1,533 @@ +## MetadataAwareAspectInstanceFactory + +- [MetadataAwareAspectInstanceFactory](#MetadataAwareAspectInstanceFactory) + - [一、基本信息](#一基本信息) + - [二、基本描述](#二基本描述) + - [三、主要功能](#三主要功能) + - [四、接口源码](#四接口源码) + - [五、主要实现](#五主要实现) + - [六、最佳实践](#六最佳实践) + - [七、源码分析](#七源码分析) + - [八、常见问题](#八常见问题) + +### 一、基本信息 + +✒️ **作者** - Lex 📝 **博客** - [掘金](https//juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https//github.com/xuchengsheng/spring-reading) + +### 二、基本描述 + +`MetadataAwareAspectInstanceFactory` 接口是 Spring AOP 中的关键接口,用于实例化切面并处理其元数据信息,为 Spring 框架提供了对 AspectJ 注解风格的 AOP 切面的支持。 + +### 三、主要功能 + +1. **实例化切面** + + + 通过 `getAspectInstance()` 方法,提供切面实例,以便在运行时应用切面的通知。 + +2. **处理元数据信息** + + + 通过 `getAspectMetadata()` 方法,获取切面类的元数据信息,如类名、所属的类、切点表达式等,以便在运行时能够正确地应用切面。 + +3. **支持 AspectJ 注解风格的 AOP** + + + 通过这个接口,Spring AOP 能够实现对 AspectJ 注解风格的 AOP 切面的实例化和元数据处理,从而支持在 Spring 应用中使用 AspectJ 注解定义切面。 + +### 四、接口源码 + +`MetadataAwareAspectInstanceFactory` 接口是 `AspectInstanceFactory` 的子接口,用于返回与 AspectJ 注解类关联的 `AspectMetadata`。`AspectMetadata` 包含与切面相关的元数据信息。此接口还定义了一个方法 `getAspectCreationMutex()`,用于返回此工厂的最佳创建互斥锁。由于 `AspectMetadata` 使用了 Java 5 专用的 `org.aspectj.lang.reflect.AjType`,因此需要将此方法拆分到这个子接口中。 + +```java +/** + * {@link org.springframework.aop.aspectj.AspectInstanceFactory} 的子接口,用于返回与 AspectJ 注解类关联的 {@link AspectMetadata}。 + * + *

理想情况下,AspectInstanceFactory 本身应该包括此方法,但由于 AspectMetadata 使用了 Java 5 专用的 {@link org.aspectj.lang.reflect.AjType}, + * 我们需要拆分出这个子接口。 + * + * @author Rod Johnson + * @since 2.0 + * @see AspectMetadata + * @see org.aspectj.lang.reflect.AjType + */ +public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory { + + /** + * 返回此工厂的切面的 AspectJ AspectMetadata。 + * @return 切面元数据 + */ + AspectMetadata getAspectMetadata(); + + /** + * 返回此工厂的最佳创建互斥锁。 + * @return 互斥锁对象(如果不需要使用锁,则可能为 {@code null}) + * @since 4.3 + */ + @Nullable + Object getAspectCreationMutex(); + +} +``` + +### 五、主要实现 + +1. **SimpleMetadataAwareAspectInstanceFactory** + + - 这个实现类是最简单的一种,它用于创建单例的切面实例。它简单地实例化切面类,并提供其实例作为切面的实例。 + +2. **SingletonMetadataAwareAspectInstanceFactory** + + - 与 `SimpleMetadataAwareAspectInstanceFactory` 类似,这个实现类也用于创建单例的切面实例,但是它可以与 Spring 的容器集成,以便将切面实例作为容器中的单例 bean 进行管理。 + +3. **BeanFactoryAspectInstanceFactory** + + - 这个实现类与 Spring 的 BeanFactory 集成,它用于创建切面实例,并且能够处理切面类的依赖注入。它可以在切面类中注入其他 Spring 管理的 bean,实现更复杂的业务逻辑。 + +4. **PrototypeAspectInstanceFactory** + + - 这个实现类用于创建原型(prototype)的切面实例。与单例不同,原型实例每次请求时都会创建一个新的实例,适用于需要在每次使用时都重新创建实例的场景。 + +5. **LazySingletonAspectInstanceFactoryDecorator** + + - 这个实现类是一个装饰器,用于延迟初始化单例的切面实例。它在首次请求切面实例时才进行实例化,以提高性能并延迟资源消耗。 + +### 六、最佳实践 + +使用不同的 `MetadataAwareAspectInstanceFactory` 实现类来实例化切面,并展示了它们的不同行为。首先,使用 `SimpleMetadataAwareAspectInstanceFactory` 和 `SingletonMetadataAwareAspectInstanceFactory` 分别创建单例的切面实例,然后使用 `BeanFactoryAspectInstanceFactory` 在 Spring Bean 工厂中注册并实例化切面,最后使用 `LazySingletonAspectInstanceFactoryDecorator` 延迟初始化单例切面实例。在每个步骤中,都输出了切面实例及其元数据信息。 + +```java +public class MetadataAwareAspectInstanceFactoryDemo { + + public static void main(String[] args) { + // 使用 SimpleMetadataAwareAspectInstanceFactory 实例化切面 + SimpleMetadataAwareAspectInstanceFactory simpleMetadataAwareAif = new SimpleMetadataAwareAspectInstanceFactory(MyAspect.class, "myAspect"); + System.out.println("SimpleMetadataAwareAspectInstanceFactory (1) = " + simpleMetadataAwareAif.getAspectInstance()); + System.out.println("SimpleMetadataAwareAspectInstanceFactory (2) = " + simpleMetadataAwareAif.getAspectInstance()); + System.out.println("SimpleMetadataAwareAspectInstanceFactory AspectMetadata = " + JSONUtil.toJsonStr(simpleMetadataAwareAif.getAspectMetadata())); + System.out.println(); + + // 使用 SingletonMetadataAwareAspectInstanceFactory 实例化切面 + SingletonMetadataAwareAspectInstanceFactory singletonMetadataAwareAif = new SingletonMetadataAwareAspectInstanceFactory(new MyAspect(), "myAspect"); + System.out.println("SingletonMetadataAwareAspectInstanceFactory (1) = " + singletonMetadataAwareAif.getAspectInstance()); + System.out.println("SingletonMetadataAwareAspectInstanceFactory (2) = " + singletonMetadataAwareAif.getAspectInstance()); + System.out.println("SimpleMetadataAwareAspectInstanceFactory AspectMetadata = " + JSONUtil.toJsonStr(singletonMetadataAwareAif.getAspectMetadata())); + System.out.println(); + + // 使用 BeanFactoryAspectInstanceFactory 实例化切面 + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + beanFactory.registerSingleton("myAspect", new MyAspect()); + BeanFactoryAspectInstanceFactory banFactoryAif = new BeanFactoryAspectInstanceFactory(beanFactory, "myAspect"); + System.out.println("BeanFactoryAspectInstanceFactory (1) = " + banFactoryAif.getAspectInstance()); + System.out.println("BeanFactoryAspectInstanceFactory (2) = " + banFactoryAif.getAspectInstance()); + System.out.println("SimpleMetadataAwareAspectInstanceFactory AspectMetadata = " + JSONUtil.toJsonStr(banFactoryAif.getAspectMetadata())); + System.out.println(); + + // 使用 LazySingletonAspectInstanceFactoryDecorator 实例化切面 + LazySingletonAspectInstanceFactoryDecorator lazySingletonAifD = new LazySingletonAspectInstanceFactoryDecorator(banFactoryAif); + System.out.println("LazySingletonAspectInstanceFactoryDecorator (1) = " + lazySingletonAifD.getAspectInstance()); + System.out.println("LazySingletonAspectInstanceFactoryDecorator (2) = " + lazySingletonAifD.getAspectInstance()); + System.out.println("LazySingletonAspectInstanceFactoryDecorator AspectCreationMutex = " + lazySingletonAifD.getAspectCreationMutex()); + System.out.println("LazySingletonAspectInstanceFactoryDecorator AspectMetadata = " + JSONUtil.toJsonStr(lazySingletonAifD.getAspectMetadata())); + System.out.println(); + } +} +``` + +运行结果,展示了不同类型的 `MetadataAwareAspectInstanceFactory` 实现类的行为。`SimpleMetadataAwareAspectInstanceFactory` 每次返回不同的切面实例,而 `SingletonMetadataAwareAspectInstanceFactory` 每次返回相同的实例,说明了它们的单例和非单例的行为。`BeanFactoryAspectInstanceFactory` 在 Spring Bean 工厂中注册并实例化切面,表现出与前两者类似的行为。`LazySingletonAspectInstanceFactoryDecorator` 是对 `BeanFactoryAspectInstanceFactory` 的装饰器,延迟初始化单例切面实例,但最终结果与 `BeanFactoryAspectInstanceFactory` 相同。 + +```java +SimpleMetadataAwareAspectInstanceFactory (1) = com.xcs.spring.MyAspect@5f341870 +SimpleMetadataAwareAspectInstanceFactory (2) = com.xcs.spring.MyAspect@553f17c +SimpleMetadataAwareAspectInstanceFactory AspectMetadata = {"aspectName":"myAspect","aspectClass":"com.xcs.spring.MyAspect","perClausePointcut":{}} + +SingletonMetadataAwareAspectInstanceFactory (1) = com.xcs.spring.MyAspect@1da51a35 +SingletonMetadataAwareAspectInstanceFactory (2) = com.xcs.spring.MyAspect@1da51a35 +SimpleMetadataAwareAspectInstanceFactory AspectMetadata = {"aspectName":"myAspect","aspectClass":"com.xcs.spring.MyAspect","perClausePointcut":{}} + +BeanFactoryAspectInstanceFactory (1) = com.xcs.spring.MyAspect@6646153 +BeanFactoryAspectInstanceFactory (2) = com.xcs.spring.MyAspect@6646153 +SimpleMetadataAwareAspectInstanceFactory AspectMetadata = {"aspectName":"myAspect","aspectClass":"com.xcs.spring.MyAspect","perClausePointcut":{}} + +LazySingletonAspectInstanceFactoryDecorator (1) = com.xcs.spring.MyAspect@6646153 +LazySingletonAspectInstanceFactoryDecorator (2) = com.xcs.spring.MyAspect@6646153 +LazySingletonAspectInstanceFactoryDecorator AspectCreationMutex = null +LazySingletonAspectInstanceFactoryDecorator AspectMetadata = {"aspectName":"myAspect","aspectClass":"com.xcs.spring.MyAspect","perClausePointcut":{}} +``` + +### 七、源码分析 + +#### SimpleMetadataAwareAspectInstanceFactory + +`SimpleMetadataAwareAspectInstanceFactory` 是一个实现了 `MetadataAwareAspectInstanceFactory` 接口的类,它在每次调用 `getAspectInstance()` 方法时都会为指定的切面类创建一个新的实例。这个类通过 `AspectMetadata` 对象来管理切面的元数据信息,并且实现了 `getAspectMetadata()` 方法来提供这些元数据。它还实现了 `getAspectCreationMutex()` 方法来返回切面实例的创建锁,以及 `getOrderForAspectClass()` 方法来确定切面类的顺序。 + +```java +/** + * 实现了 {@link MetadataAwareAspectInstanceFactory} 接口的类,每次调用 {@link #getAspectInstance()} 方法都会为指定的切面类创建一个新的实例。 + * + * @author Juergen Hoeller + * @since 2.0.4 + */ +public class SimpleMetadataAwareAspectInstanceFactory extends SimpleAspectInstanceFactory + implements MetadataAwareAspectInstanceFactory { + + private final AspectMetadata metadata; // 切面的元数据信息 + + /** + * 创建一个新的 SimpleMetadataAwareAspectInstanceFactory 实例,用于给定的切面类。 + * + * @param aspectClass 切面类 + * @param aspectName 切面名称 + */ + public SimpleMetadataAwareAspectInstanceFactory(Class aspectClass, String aspectName) { + super(aspectClass); + this.metadata = new AspectMetadata(aspectClass, aspectName); // 创建切面的元数据信息 + } + + /** + * 获取切面的元数据信息。 + * + * @return 切面的元数据信息 + */ + @Override + public final AspectMetadata getAspectMetadata() { + return this.metadata; + } + + /** + * 获取切面实例的创建锁。 + * + * @return 切面实例的创建锁 + */ + @Override + public Object getAspectCreationMutex() { + return this; + } + + /** + * 获取切面类的顺序。 + * + * @param aspectClass 切面类 + * @return 切面类的顺序 + */ + @Override + protected int getOrderForAspectClass(Class aspectClass) { + return OrderUtils.getOrder(aspectClass, Ordered.LOWEST_PRECEDENCE); // 获取切面类的顺序 + } + +} +``` + +#### SingletonMetadataAwareAspectInstanceFactory + +`SingletonMetadataAwareAspectInstanceFactory` 是一个实现了 `MetadataAwareAspectInstanceFactory` 接口的类,它通过指定的单例对象支持切面实例的创建,每次调用 `getAspectInstance()` 方法都返回相同的实例。该类使用一个单例的切面实例,并通过 `AspectMetadata` 对象管理切面的元数据信息。它也实现了 `Serializable` 接口以支持序列化,并且继承自 `SingletonAspectInstanceFactory`,提供了获取切面实例的相关方法和逻辑。 + +```java +/** + * 实现了 {@link MetadataAwareAspectInstanceFactory} 接口的类,通过指定的单例对象支持切面实例的创建,每次调用 {@link #getAspectInstance()} 方法都返回同一个实例。 + * + * 该类通过 {@link AspectMetadata} 对象管理切面的元数据信息,并且实现了 {@link Serializable} 接口以支持序列化。 + * + * 作者:Rod Johnson, Juergen Hoeller + * @since 2.0 + * @see SimpleMetadataAwareAspectInstanceFactory + */ +@SuppressWarnings("serial") +public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspectInstanceFactory + implements MetadataAwareAspectInstanceFactory, Serializable { + + private final AspectMetadata metadata; // 切面的元数据信息 + + /** + * 为给定的切面创建一个新的 SingletonMetadataAwareAspectInstanceFactory。 + * + * @param aspectInstance 切面的单例实例 + * @param aspectName 切面的名称 + */ + public SingletonMetadataAwareAspectInstanceFactory(Object aspectInstance, String aspectName) { + super(aspectInstance); // 调用父类的构造方法,传入切面的单例实例 + this.metadata = new AspectMetadata(aspectInstance.getClass(), aspectName); // 创建切面的元数据信息 + } + + /** + * 获取切面的元数据信息。 + * + * @return 切面的元数据信息 + */ + @Override + public final AspectMetadata getAspectMetadata() { + return this.metadata; + } + + /** + * 获取切面实例的创建锁。 + * + * @return 切面实例的创建锁 + */ + @Override + public Object getAspectCreationMutex() { + return this; + } + + /** + * 获取切面类的顺序。 + * + * @param aspectClass 切面类 + * @return 切面类的顺序 + */ + @Override + protected int getOrderForAspectClass(Class aspectClass) { + return OrderUtils.getOrder(aspectClass, Ordered.LOWEST_PRECEDENCE); // 获取切面类的顺序 + } + +} +``` + +#### BeanFactoryAspectInstanceFactory + +`BeanFactoryAspectInstanceFactory` 是一个实现了 `MetadataAwareAspectInstanceFactory` 接口的类,它通过 Spring 的 `BeanFactory` 支持切面实例的创建。这个工厂可以通过指定的 bean 名称从 `BeanFactory` 中获取切面实例,并且可以通过提供的类型来自省以创建 AspectJ 的元数据信息。它可以处理单例和非单例的情况,并且能够确定切面的顺序,支持使用 `Ordered` 接口或 `@Order` 注解来定义顺序。 + +```java +/** + * {@link org.springframework.aop.aspectj.AspectInstanceFactory} 接口的实现, + * 由 Spring {@link org.springframework.beans.factory.BeanFactory} 支持。 + * + *

注意,如果使用原型模式可能会多次实例化,这可能不会得到您期望的语义。 + * 使用 {@link LazySingletonAspectInstanceFactoryDecorator} 来包装这个工厂, + * 以确保只返回一个新的切面。 + * + * 作者:Rod Johnson, Juergen Hoeller + * @since 2.0 + * @see org.springframework.beans.factory.BeanFactory + * @see LazySingletonAspectInstanceFactoryDecorator + */ +@SuppressWarnings("serial") +public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory, Serializable { + + private final BeanFactory beanFactory; // Bean 工厂 + private final String name; // Bean 名称 + private final AspectMetadata aspectMetadata; // 切面的元数据信息 + + /** + * 创建一个 BeanFactoryAspectInstanceFactory。AspectJ 将被调用来自省, + * 使用从 BeanFactory 中为给定的 bean 名称返回的类型创建 AJType 元数据。 + * + * @param beanFactory BeanFactory,用于获取实例 + * @param name bean 的名称 + */ + public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name) { + this(beanFactory, name, null); + } + + /** + * 创建一个 BeanFactoryAspectInstanceFactory,提供一个类型,AspectJ 应该自省以创建 AJType 元数据。 + * 如果 BeanFactory 可能将类型视为子类(例如使用 CGLIB),并且信息应该与超类相关,则使用此选项。 + * + * @param beanFactory BeanFactory,用于获取实例 + * @param name bean 的名称 + * @param type AspectJ 应该自省的类型({@code null} 表示通过 bean 名称解析通过 {@link BeanFactory#getType} 的类型) + */ + public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name, @Nullable Class type) { + Assert.notNull(beanFactory, "BeanFactory must not be null"); + Assert.notNull(name, "Bean name must not be null"); + this.beanFactory = beanFactory; + this.name = name; + Class resolvedType = type; + if (type == null) { + resolvedType = beanFactory.getType(name); + Assert.notNull(resolvedType, "Unresolvable bean type - explicitly specify the aspect class"); + } + this.aspectMetadata = new AspectMetadata(resolvedType, name); // 创建切面的元数据信息 + } + + /** + * 获取切面实例。 + * + * @return 切面实例 + */ + @Override + public Object getAspectInstance() { + return this.beanFactory.getBean(this.name); + } + + /** + * 获取切面的类加载器。 + * + * @return 切面的类加载器 + */ + @Override + @Nullable + public ClassLoader getAspectClassLoader() { + return (this.beanFactory instanceof ConfigurableBeanFactory ? + ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() : + ClassUtils.getDefaultClassLoader()); + } + + /** + * 获取切面的元数据信息。 + * + * @return 切面的元数据信息 + */ + @Override + public AspectMetadata getAspectMetadata() { + return this.aspectMetadata; + } + + /** + * 获取切面实例的创建锁。 + * + * @return 切面实例的创建锁 + */ + @Override + @Nullable + public Object getAspectCreationMutex() { + if (this.beanFactory.isSingleton(this.name)) { + // 依赖于工厂提供的单例语义 -> 没有本地锁。 + return null; + } else if (this.beanFactory instanceof ConfigurableBeanFactory) { + // 从工厂中没有单例保证 -> 让我们本地锁定,但重用工厂的单例锁,以防万一我们的通知 bean 的惰性依赖项 + // 不小心触发了单例锁隐式... + return ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex(); + } else { + return this; + } + } + + /** + * 确定此工厂目标切面的顺序,可以通过实现 {@link org.springframework.core.Ordered} 接口来表达实例特定的顺序 + * (仅对单例 bean 进行检查),也可以通过 {@link org.springframework.core.annotation.Order} 注解在类级别表达顺序。 + * + * @see org.springframework.core.Ordered + * @see org.springframework.core.annotation.Order + */ + @Override + public int getOrder() { + Class type = this.beanFactory.getType(this.name); + if (type != null) { + if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) { + return ((Ordered) this.beanFactory.getBean(this.name)).getOrder(); + } + return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE); + } + return Ordered.LOWEST_PRECEDENCE; + } + + @Override + public String toString() { + return getClass().getSimpleName() + ": bean name '" + this.name + "'"; + } +} +``` + +#### LazySingletonAspectInstanceFactoryDecorator + +`LazySingletonAspectInstanceFactoryDecorator`类是一个装饰器,用于确保一个 `MetadataAwareAspectInstanceFactory` 只实例化一次。它包装了另一个 `MetadataAwareAspectInstanceFactory` 实例,并在首次调用 `getAspectInstance()` 方法时进行实例化。在后续的调用中,它将返回已经实例化的对象,而不会再次实例化。 + +```java +/** + * 修饰器,使 {@link MetadataAwareAspectInstanceFactory} 仅实例化一次。 + * + * 作者:Rod Johnson, Juergen Hoeller + * @since 2.0 + */ +@SuppressWarnings("serial") +public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwareAspectInstanceFactory, Serializable { + + private final MetadataAwareAspectInstanceFactory maaif; // 要装饰的 MetadataAwareAspectInstanceFactory 实例 + + @Nullable + private volatile Object materialized; // 实例化的对象 + + /** + * 创建一个对给定 AspectInstanceFactory 进行懒初始化的修饰器。 + * @param maaif 要装饰的 MetadataAwareAspectInstanceFactory + */ + public LazySingletonAspectInstanceFactoryDecorator(MetadataAwareAspectInstanceFactory maaif) { + Assert.notNull(maaif, "AspectInstanceFactory must not be null"); + this.maaif = maaif; + } + + /** + * 获取切面实例。 + * 如果实例化过程中已经存在一个实例,则直接返回该实例; + * 否则,根据实例化互斥锁(如果存在)保证多线程环境下只实例化一次。 + * 如果没有互斥锁,则直接实例化切面对象并将其赋值给 materialized 变量,然后返回该实例。 + * 如果存在互斥锁,则使用该锁来保护实例化过程,确保在多线程环境下只有一个线程可以执行实例化操作。 + * + * @return 切面实例 + */ + @Override + public Object getAspectInstance() { + // 尝试获取已实例化的对象 + Object aspectInstance = this.materialized; + // 如果不存在已实例化的对象 + if (aspectInstance == null) { + // 获取实例化互斥锁 + Object mutex = this.maaif.getAspectCreationMutex(); + // 如果不存在互斥锁 + if (mutex == null) { + // 直接实例化切面对象 + aspectInstance = this.maaif.getAspectInstance(); + // 将实例化后的对象赋值给 materialized 变量 + this.materialized = aspectInstance; + } else { + // 使用互斥锁保护实例化过程 + synchronized (mutex) { + // 再次尝试获取已实例化的对象 + aspectInstance = this.materialized; + // 双重检查,确保在锁内部只实例化一次 + if (aspectInstance == null) { + // 实例化切面对象 + aspectInstance = this.maaif.getAspectInstance(); + // 将实例化后的对象赋值给 materialized 变量 + this.materialized = aspectInstance; + } + } + } + } + return aspectInstance; // 返回切面实例 + } + + /** + * 返回是否已经实例化。 + */ + public boolean isMaterialized() { + return (this.materialized != null); + } + + @Override + @Nullable + public ClassLoader getAspectClassLoader() { + return this.maaif.getAspectClassLoader(); + } + + @Override + public AspectMetadata getAspectMetadata() { + return this.maaif.getAspectMetadata(); + } + + @Override + @Nullable + public Object getAspectCreationMutex() { + return this.maaif.getAspectCreationMutex(); + } + + @Override + public int getOrder() { + return this.maaif.getOrder(); + } + + @Override + public String toString() { + return "LazySingletonAspectInstanceFactoryDecorator: decorating " + this.maaif; + } + +} +``` + +### 八、常见问题 + +1. **切面实例化策略** + + + 我们需要了解不同实现类的切面实例化策略,例如单例模式、原型模式等,以便选择适合应用场景的实现类。 + +2. **AOP配置错误** + + + 在使用 `MetadataAwareAspectInstanceFactory` 实现时,可能会出现AOP配置错误导致切面无法正确实例化的问题,需要仔细检查配置并进行调试。 \ No newline at end of file diff --git a/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/pom.xml b/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/pom.xml new file mode 100644 index 0000000..ad7ac2a --- /dev/null +++ b/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/pom.xml @@ -0,0 +1,23 @@ + + + + com.xcs.spring + spring-aop + 0.0.1-SNAPSHOT + + + 4.0.0 + spring-aop-metadataAwareAspectInstanceFactory + + + + + cn.hutool + hutool-json + 5.8.27 + + + + \ No newline at end of file diff --git a/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/src/main/java/com/xcs/spring/MetadataAwareAspectInstanceFactoryDemo.java b/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/src/main/java/com/xcs/spring/MetadataAwareAspectInstanceFactoryDemo.java new file mode 100644 index 0000000..7db957b --- /dev/null +++ b/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/src/main/java/com/xcs/spring/MetadataAwareAspectInstanceFactoryDemo.java @@ -0,0 +1,41 @@ +package com.xcs.spring; + +import cn.hutool.json.JSONUtil; +import org.springframework.aop.aspectj.annotation.*; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; + +public class MetadataAwareAspectInstanceFactoryDemo { + + public static void main(String[] args) { + // 使用 SimpleMetadataAwareAspectInstanceFactory 实例化切面 + SimpleMetadataAwareAspectInstanceFactory simpleMetadataAwareAif = new SimpleMetadataAwareAspectInstanceFactory(MyAspect.class, "myAspect"); + System.out.println("SimpleMetadataAwareAspectInstanceFactory (1) = " + simpleMetadataAwareAif.getAspectInstance()); + System.out.println("SimpleMetadataAwareAspectInstanceFactory (2) = " + simpleMetadataAwareAif.getAspectInstance()); + System.out.println("SimpleMetadataAwareAspectInstanceFactory AspectMetadata = " + JSONUtil.toJsonStr(simpleMetadataAwareAif.getAspectMetadata())); + System.out.println(); + + // 使用 SingletonMetadataAwareAspectInstanceFactory 实例化切面 + SingletonMetadataAwareAspectInstanceFactory singletonMetadataAwareAif = new SingletonMetadataAwareAspectInstanceFactory(new MyAspect(), "myAspect"); + System.out.println("SingletonMetadataAwareAspectInstanceFactory (1) = " + singletonMetadataAwareAif.getAspectInstance()); + System.out.println("SingletonMetadataAwareAspectInstanceFactory (2) = " + singletonMetadataAwareAif.getAspectInstance()); + System.out.println("SimpleMetadataAwareAspectInstanceFactory AspectMetadata = " + JSONUtil.toJsonStr(singletonMetadataAwareAif.getAspectMetadata())); + System.out.println(); + + // 使用 BeanFactoryAspectInstanceFactory 实例化切面 + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + beanFactory.registerSingleton("myAspect", new MyAspect()); + BeanFactoryAspectInstanceFactory banFactoryAif = new BeanFactoryAspectInstanceFactory(beanFactory, "myAspect"); + System.out.println("BeanFactoryAspectInstanceFactory (1) = " + banFactoryAif.getAspectInstance()); + System.out.println("BeanFactoryAspectInstanceFactory (2) = " + banFactoryAif.getAspectInstance()); + System.out.println("SimpleMetadataAwareAspectInstanceFactory AspectMetadata = " + JSONUtil.toJsonStr(banFactoryAif.getAspectMetadata())); + System.out.println(); + + // 使用 LazySingletonAspectInstanceFactoryDecorator 实例化切面 + LazySingletonAspectInstanceFactoryDecorator lazySingletonAifD = new LazySingletonAspectInstanceFactoryDecorator(banFactoryAif); + System.out.println("LazySingletonAspectInstanceFactoryDecorator (1) = " + lazySingletonAifD.getAspectInstance()); + System.out.println("LazySingletonAspectInstanceFactoryDecorator (2) = " + lazySingletonAifD.getAspectInstance()); + System.out.println("LazySingletonAspectInstanceFactoryDecorator AspectCreationMutex = " + lazySingletonAifD.getAspectCreationMutex()); + System.out.println("LazySingletonAspectInstanceFactoryDecorator AspectMetadata = " + JSONUtil.toJsonStr(lazySingletonAifD.getAspectMetadata())); + System.out.println(); + } +} diff --git a/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/src/main/java/com/xcs/spring/MyAspect.java b/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/src/main/java/com/xcs/spring/MyAspect.java new file mode 100644 index 0000000..eb070bc --- /dev/null +++ b/spring-aop/spring-aop-metadataAwareAspectInstanceFactory/src/main/java/com/xcs/spring/MyAspect.java @@ -0,0 +1,8 @@ +package com.xcs.spring; + +import org.aspectj.lang.annotation.Aspect; + +@Aspect +class MyAspect { + +}