12

我正在编写自己的作用域(即实现的类org.springframework.beans.factory.config.Scope),我需要注入一些 bean。我怎么做?

背景:Spring 必须首先创建所有范围 bean,以便我可以定义哪些 bean 进入范围。但是我首先需要构建范围的 bean 呢?

4

2 回答 2

4

我想出了这个似乎很安全的解决方法,但我想听听评论(或者我的回答可能会给你一些更好的想法):

  1. 定义范围并给它设置器(而不是使用@Autowired
  2. 创建一个“范围配置器”bean:

    public CustomScopeConfigurer {
        @Autowired private Foo foo;
        private CustomScope scope;
    
        public CustomScopeConfigurer( CustomScope scope ) {
            this.scope = scope;
        }
    
        @PostConstruct
        public void initScope() {
            scope.setFoo( foo );
        }
    }
    

    此配置器 bean 不能是惰性的。

推理:

  1. 范围本身不能使用自动装配,因为它是在第一个 bean 之前创建的。虽然它可能会在以后创建,但您可以确定它将在所有其他 bean 之前创建。所以自动装配不能可靠地工作。

  2. 配置器 bean 将与所有其他 bean 一起创建,但在范围之后。所以自动装配会为它工作。

  3. 由于配置器 bean 不是惰性初始化的,它将在应用程序的其余部分可以看到应用程序上下文之前创建。这意味着@Scope("custom")此时不能创建范围的任何 bean(即带有 的 bean) - 范围不能是“活动的”,但是 -> Spring 不会尝试将任何 bean 放入其中。

  4. 作用域本身通常在某处创建为静态常量。这就是为什么我们必须将它作为参数传递给构造函数。

于 2012-08-17T15:03:13.723 回答
2

你可以很简单地做到这一点。

考虑以下自定义范围类:

package com.way2learn;

import java.util.Map;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

public class MyCustomScope implements Scope{

    private Map<String, Object> scope;

    public void setScope(Map<String, Object> scope) {
        this.scope = scope;
    }

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        checkAndClear();
        Object bean=scope.get(name);
        if(bean==null){
            bean=objectFactory.getObject();
            scope.put(name,bean);
        }
        return bean;
    }
    private void checkAndClear() {
        //Some logic to check condition and clear the scope
    }
    //optional methods
    @Override
    public Object remove(String name) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {

    }

    @Override
    public Object resolveContextualObject(String key) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getConversationId() {
        // TODO Auto-generated method stub
        return null;
    }

}

它依赖于java.util.Map.

您不能自动装配使用@Autowired它作为@Autowired注释AutoWiredAnnotationBeanPostProcessor仅在之后工作。

但自定义范围将在之前注册AutoWiredAnnotationBeanPostProcessor

因此,您可以手动注入MapMyCustomScope,如下所示:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">

        <util:map key-type="java.lang.String" value-type="java.lang.Object" id="custScopeMap"/>

        <bean id="myCustomScope" class="com.way2learn.MyCustomScope">
            <property name="scope" ref="custScopeMap"/>
        </bean>

        <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
            <property name="scopes">
                <map>
                    <entry key="myScope" value-ref="myCustomScope"/>
                </map>
            </property>
        </bean>

</beans>

我尝试过这个。它工作正常。我在Aaron Digulla's答案中发现了一个错误,即

考虑以下场景:Spring's CustomScopeConfigurer将创建第一个 bean,立即创建CustomScopebean,现在我们的自定义范围已准备好使用。一段时间Aaron Digulla's CustomScopeConfigurer后将创建将 foo 初始化为CustomScope. 但是,如果在创建 bean 之后CustomScope registration和之前创建了一些自定义范围的 bean,会发生Aaron Digulla's CustomScopeConfigurer什么?对于那些 bean,bean 中不会有 foo CustomScope

于 2015-11-29T13:22:47.360 回答