关于Spring AOP的一点疑问

bean完成属性填充后,在执行完初始化后会通过AbstractAutoProxyCreatorpostProcessAfterInitialization判断是否需要代理


wrapIfNecessary中有个判断我有点疑惑

targetSourcedBeans的处理逻辑在createbean时的postProcessBeforeInstantiation方法中处理,如果此处处理并返回了bean实例,将不会继续走bean的创建流程了。

在这种情况下wrapIfNecessary方法判断targetSourcedBeans是否有必要?我怎么都想不通,什么情况下会导致targetSourcedBeans里有数据还走到了wrapIfNecessary方法里

我不熟悉 AOP 的源码,我把这个问题喂给了 AI,它的回答如下(你可以参考参考):


这个问题的核心是关于Spring AOP中的代理创建流程,特别是在AbstractAutoProxyCreator中的处理逻辑。

问题涉及两个关键点:

  1. wrapIfNecessary方法中对targetSourcedBeans的判断
  2. postProcessBeforeInstantiation中的提前返回逻辑

从流程上来说:

  1. 如果bean在postProcessBeforeInstantiation阶段创建了实例并返回,确实不会继续走后续的bean创建流程
  2. 正常情况下,如果一个bean被加入到targetSourcedBeans集合中,它应该在postProcessBeforeInstantiation就返回了代理对象

但是,这个判断仍然是必要的,原因如下:

  1. Spring的生命周期管理是复杂的,可能存在多个BeanPostProcessor
  2. 在某些场景下(比如循环依赖),bean的创建过程可能会被打断和重试
  3. 这个判断可以作为一个安全检查,确保已经处理过的bean不会被重复代理

所以这个检查虽然在正常情况下可能显得多余,但是从框架的健壮性考虑是必要的。它可以防止在一些边缘情况下的重复代理问题。

让我们通过代码示例来详细解释这个问题。

首先,我们来看看相关的核心代码结构:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    
    // 存储已经处理过的targetSource的bean名称
    private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        // 1. 检查是否需要创建代理
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            return null;
        }

        // 2. 尝试获取自定义TargetSource
        TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
        if (targetSource != null) {
            // 如果存在自定义TargetSource,将bean名称加入到targetSourcedBeans集合
            targetSourcedBeans.add(beanName);
            // 创建代理对象
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            return createProxy(beanClass, beanName, specificInterceptors, targetSource);
        }
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean != null) {
            // 检查是否需要包装成代理对象
            Object wrapIfNecessary = wrapIfNecessary(bean, beanName);
            return wrapIfNecessary;
        }
        return bean;
    }

    protected Object wrapIfNecessary(Object bean, String beanName) {
        // 1. 已经处理过的targetSource的bean,直接返回
        if (targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        // 2. 如果不需要代理,直接返回
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            return bean;
        }

        // 3. 获取适用于该bean的通知器
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        // 4. 如果有适用的通知器,创建代理
        if (specificInterceptors != DO_NOT_PROXY) {
            proxyFactory.addAdvisors(specificInterceptors);
            return proxyFactory.getProxy();
        }
        return bean;
    }
}

让我们通过一个具体的例子来说明这个流程:

// 1. 定义一个简单的接口
public interface UserService {
    void createUser(String username);
}

// 2. 实现类
@Service
public class UserServiceImpl implements UserService {
    public void createUser(String username) {
        System.out.println("Creating user: " + username);
    }
}

// 3. 定义一个切面
@Aspect
@Component
public class UserServiceAspect {
    @Before("execution(* com.example.service.UserService.createUser(..))")
    public void beforeCreate(JoinPoint joinPoint) {
        System.out.println("Before creating user");
    }
}

// 4. 自定义TargetSource示例
public class CustomUserServiceTargetSource implements TargetSource {
    private final UserService userService;

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

    @Override
    public Class<?> getTargetClass() {
        return UserService.class;
    }

    @Override
    public boolean isStatic() {
        return true;
    }

    @Override
    public Object getTarget() {
        return userService;
    }

    @Override
    public void releaseTarget(Object target) {
    }
}

// 5. 配置类示例
@Configuration
public class AopConfig implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            BeanDefinition beanDefinition = registry.getBeanDefinition("userService");
            // 设置自定义TargetSource
            beanDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        }
    }
}

现在让我们分析可能的场景:

  1. 正常场景:
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Application.class, args);
        UserService userService = context.getBean(UserService.class);
        userService.createUser("test");
    }
}
  1. 循环依赖场景:
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private OrderService orderService;
    
    public void createUser(String username) {
        System.out.println("Creating user: " + username);
        orderService.createOrder(username);
    }
}

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private UserService userService;
    
    public void createOrder(String username) {
        System.out.println("Creating order for user: " + username);
    }
}

在这些场景中,targetSourcedBeans的检查是必要的原因:

  1. 正常场景

    • 如果一个bean使用了自定义的TargetSource,它会在postProcessBeforeInstantiation中被 处理
    • 该bean会被加入到targetSourcedBeans集合中
    • 后续的wrapIfNecessary检查可以避免重复代理
  2. 循环依赖场景

    • Spring需要提前暴露代理对象来解决循环依赖
    • bean的创建过程可能会被打断和重试
    • targetSourcedBeans的检查可以确保在这个复杂过程中不会创建多余的代理
  3. 多个BeanPostProcessor场景

@Configuration
public class MultiplePostProcessorConfig {
    @Bean
    public BeanPostProcessor customPostProcessor1() {
        return new CustomBeanPostProcessor1();
    }
    
    @Bean
    public BeanPostProcessor customPostProcessor2() {
        return new CustomBeanPostProcessor2();
    }
}

在这种情况下:

  • 多个后处理器可能都会尝试创建代理
  • targetSourcedBeans的检查可以防止重复代理
  • 确保最终只有一个代理层

所以,虽然在简单场景下这个检查可能看起来冗余,但是在复杂场景下它是必要的安全保障:

  1. 防止重复代理
  2. 处理循环依赖
  3. 确保代理创建的一致性
  4. 提高框架的健壮性

需要说明的是,这段代码是Spring框架的核心部分,它需要处理各种复杂的场景和边缘情况。框架的设计必须考虑到所有可能的使用场景,而不仅仅是常见的简单场景。

postProcessAfterInitialization 会调用 wrapIfNecessary()。 如果是提前创建,则判断为不需要,就直接返回原对象。这里判断为unNecessary 就用上了targeSourceBeans.contains(beanName)earlyBeanReferences 是在循环依赖的时候加入,是在后面bean 实例化完成后才会调用。这里.remove 必定是不等于bean 的。

3 个赞

你的意思是如果在实例化前返回了代理对象, 初始化后这个处理里的判断是多余的。
但是在postProcessBeforeInstantiation 返回了对象之后,确实还会走一遍postProcessAfterInitialization 的过程呀,代码里有

1 个赞

是会走,这是大框架的默认流程,既然有返回对象,就一定触发后处理器。但这个后处理器不会有任何作用,因为在warp 里面会直接返回。大框架是一定要遵守的,但是你不一定要真干活,就这么个意思。


@Configuration
class MyBeanPostProcessor : BeanPostProcessor, PriorityOrdered {
    
    override fun getOrder(): Int {
        return Ordered.HIGHEST_PRECEDENCE
    }

    @Throws(BeansException::class)
    override fun postProcessAfterInitialization(bean: Any, beanName: String): Any? {
        val targetSource: TargetSource = object : TargetSource {
            override fun getTargetClass(): Class<*>? {
                return Demo::class.java
            }

            @Throws(Exception::class)
            override fun getTarget(): Any {
                val d = Demo()
                d.name = "a"
                return d
            }
        }

        if (bean is AbstractAutoProxyCreator) {
            val creator: TargetSourceCreator =
                object : TargetSourceCreator {
                    override fun getTargetSource(beanClass: Class<*>, beanName: String): TargetSource? {
                        if (Demo::class.java.isAssignableFrom(beanClass)) {
                            return targetSource
                        }
                        return null
                    }

                }
            bean.setCustomTargetSourceCreators(creator)
        }

        return bean
    }

}
@Component
class Demo() {
    lateinit var name:String
}
@SpringBootTest
class Demo1ApplicationTests {
    @Autowired(required = false)
    lateinit var demo:Demo

    @Test
    fun contextLoads() {
        println(demo.name)
    }

}

你可以自己debug

1 个赞

明白了,通过applyBeanPostProcessorsBeforeInstantiation返回的对象,虽然不会继续走默认的bean创建流程了,但是依然还会应用applyBeanPostProcessorsAfterInitialization方法,之前是我忽略了,以为applyBeanPostProcessorsBeforeInstantiation后直接返回了。

1 个赞