有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaSpring在运行时注册作用域bean

我正在开发一个基于Spring的应用程序,它注册了一个自定义作用域“任务”。其思想是,当一个新任务启动时,Spring应该提供任务范围的对象

任务在运行时中实例化。它以Properties对象的形式提供了一些配置。我想将该对象注册到任务范围内的ApplicationContext,以便该范围内的所有bean都可以引用该特定任务的配置

以下是代码中的大致概念:

public class MyTask extends SourceTask {
    @Override
    public void start(Map<String, String> props) {
        context = ContextProvider.getApplicationContext();
        // Initialize the scope
        ConnectorTaskScope scope = context.getBean(ConnectorTaskScope.class);
        scope.startNewTask();

        // TODO register the props object in the context

        // get an object which requires the properties and work with it
        context.getBean(SomeScopedBean.class);        
    }
}

我不知道如何在ApplicationContext中注册范围适当的bean

多谢各位

更新:

这里有更多的代码来更好地解释这个问题SomeScopedBean应该使用它提供的bean的配置做一些事情,看起来像这样:

public class SomeScopedBean {
    @Autowire
    public SomeScopedBean (Properties configuration) {
        // do some work with the configuration 
    }
}

该应用程序的思想是,它应该有多个MyTask实例以不同的配置运行,每个任务都有自己的作用域。在每个任务的范围内,应该有一个用任务配置初始化的SomeScopedBean实例

public class MyApplication {
    public static void main (String[] args) {
        // ...
        Properties config1 = loadConfiguration1();
        Properties config2 = loadConfiguration2();
        MyTask task1 = new MyTask();
        MyTask task2 = new MyTask();
        task1.start(config1);
        task2.start(config2);
        // ...
    }
}

共 (2) 个答案

  1. # 1 楼答案

    AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
    
    MyTask instance = new MyTask();
    beanFactory.autowireBean(instance);
    beanFactory.initializeBean(instance, MyTask.class.getCanonicalName());
    
    //for singleton I used
    ((ConfigurableListableBeanFactory)beanFactory).registerSingleton(MyTask.class.getCanonicalName(), instance);
    

    在您的情况下,我将注册MyTask代理的singleton。代理可以保留所有与作用域相关的实例(例如,在映射或ThreadLocal存储中)和调用委托逻辑,以便从映射中更正一个实例

    更新: 实际上,您不是自动连接MyTaskBean,而是一个代理。代理将包装所有MyTask方法。代理与MyTask具有相同的接口。假设您调用ProxyMyTask。do()方法。代理截取调用,以某种方式获取作用域,例如,在Tread作用域示例中获取当前线程,并从映射(或从ThreadLocal存储中获取线程作用域)中获取MyTask的正确实例。最后调用找到的MyTask实例的do(0)方法

    更新2: 参见示例http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html您可以轻松包装接口。确定作用域并返回正确实例的逻辑应该在方法中

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(target, args);
    }
    
  2. # 2 楼答案

    如果我接受你最后的评论:

    What I want is to have 1 instance of SomeScopedBean within each scope (within each MyTask), but each configured with different configuration properties (which are provided by the deployment framework when it instantiates each Task,

    尤其是within each MyTask,如果它被限制在MyTask

    你可以:

    • SomeScopedBean定义为原型bean
    • 创建一个工厂@Configuration,它将使用提供的属性配置实例化SomeScopedBean

    首先是配置:

    @Configuration
    public class SomeScopedBeanFactoryConfiguration {
    
        @Bean
        @Scope(BeanDefinition.SCOPE_PROTOTYPE)
        public SomeScopedBean create(Properties configuration) {
            return new SomeScopedBean(configuration);
        }
    
    }
    

    然后将SomeScopedBeanFactoryConfiguration自动连接到MyTask并创建SomeScopedBean

    public class MyTask extends SourceTask {
    
        @Autowired
        private SomeScopedBeanFactoryConfiguration  someScopedBeanFactoryConfiguration;
    
        @Override
        public void start(Map<String, String> props) {
            SomeScopedBean scopedBean = someScopedBeanFactoryConfiguration.create(props);    
        }
    }
    

    注意:如果必须将SomeScopedBean注入多个具有task/thread作用域的bean,则可以将其作用域更改为线程作用域,例如:

        @Bean
        @Scope("thread")
        public SomeScopedBean create(Properties configuration) {
            return new SomeScopedBean(configuration);
        }