【问题标题】:Spring Autowired works before proxies are createdSpring Autowired 在创建代理之前工作
【发布时间】:2021-03-17 20:05:13
【问题描述】:

据我了解,Spring 在postProcessBeforeInitialization 阶段使用AutowiredAnnotationBeanPostProcessor 管理自动装配机制。但是它如何注入应该在postProcessAfterInitialization 阶段创建的代理呢?

编辑 1

假设我有这个 Spring 配置

@Service
class RegularBean {
    // injected on postProcessBeforeInitialization stage
    @Autowired
    private TransactionBean tBean;
    
    // invoked in between of postProcessBeforeInitialization and postProcessAfterInitialization
    @PostConstruct
    void init() {
        tBean.transactionMethod();
    }
}


@Service
class TransactionBean {
    // transactional proxy is created on postProcessAfterInitialization stage
    @Transactional
    public void transactionMethod() { ... }
}

事务代理在postProcessAfterInitialization 阶段创建。但是@PostConstruct 在它之前被调用。注入的tBean 是用事务代理包裹的吗?如果是这样,那为什么?因为不应该。如果不包装,那么以后的交易怎么处理?

假设我将字段注入替换为构造函数注入。它会以某种方式改变行为吗?

【问题讨论】:

    标签: spring spring-mvc dependency-injection spring-aop


    【解决方案1】:

    当您在方法或字段上使用自动装配时,Spring Container 并不总是创建和注入所需的字段/属性实例。 Spring 在内部创建智能代理并将代理注入到您的 bean。这个智能代理将在稍后解析 bean,并在方法调用期间将调用委托给实际的 bean。这是我们使用 Scope 注释将请求和会话范围的 bean 解析为单例实例(比如服务层 bean)的常用策略。

    添加小 sn-p 以显示 Spring 在内部为 Object 创建代理。当我们使用构造函数注入时,考虑一个经典的循环依赖案例。

    @Component
    public class CircularDependencyA {
    
        private CircularDependencyB circB;
    
        public CircularDependencyA(@Lazy CircularDependencyB circB) {
            System.out.println("CircularDependencyA Ctr ->"+circB.getClass().getName());
            this.circB = circB;
        }
    }
    
    @Component
    public class CircularDependencyB {
    
        private CircularDependencyA circA;
    
        public CircularDependencyB(CircularDependencyA circA) {
            System.out.println("CircularDependencyB Ctr ->"+circA.getClass().getName());
            this.circA = circA;
        }
    }
    
        @Configuration
        @ComponentScan(basePackages = { "com.example.springdemo.cd" })
        public class TestConfig {
        }
    
    public class TestCircularDependency {
    
        public static void main(String[] args) {
            try(AnnotationConfigApplicationContext context 
                      = new AnnotationConfigApplicationContext(TestConfig.class);){
                
            }
        }
    
    }
    

    根据我们的提示,Spring 正在为 CircularDependencyB 对象创建代理(使用 CGLIB)并查看来自 CircularDependencyA 构造函数的操作 CircularDependencyA Ctr ->com.example.springdemo.cd.CircularDependencyB$$EnhancerBySpringCGLIB$$e6be3b79 谢谢

    【讨论】:

    • Spring 是否总是通过 setter/fields 注入智能代理?文档中有提及吗?因为这是我第一次听说。顺便说一句,构造函数注入呢? Spring 是否也应用智能代理?
    • 附加了一个sn-p。运行并查看 Spring 如何在构造函数注入时传递代理。这些代理知道如何在以后解析实际的 bean。所以我喜欢称它为智能代理。您在 BeanPostProcessor -> postProcessBeforeInitialization 中获得相同的 bean
    • 这不是我想知道的。您在谈论惰性 bean 和循环依赖项。但我想知道这个“bean 后处理器的东西”一般是如何工作的。我在问题中附加了一个代码 sn-p。
    • EnableTransactionManagement public class TestConfig { @Bean public PlatformTransactionManager transactionManager() { return new ResourcelessTransactionManager(); } } 并在 RegularBean 中查看 TransactionBean 的类型,注入的对象是代理而不是 TransactionBean 。所以 Spring 可以处理 txn 。在你的 sn-p 中,RegularBean 将获得一个代理
    • RegularBean 获取 TransactionBean 时。 TransactionBean 已经完成了 postProcessBeforeInitialization 和 postProcessAfterInitialization 但是如果你把它放在 TransactionBean 上它不会参与任何 TXN ,只是作为正常的方法调用。我的理解。
    猜你喜欢
    • 2014-02-12
    • 2019-01-23
    • 2018-05-12
    • 2021-04-24
    • 1970-01-01
    • 2016-02-17
    • 2018-03-12
    • 2011-04-01
    相关资源
    最近更新 更多