Подтвердить что ты не робот

Spring - зарегистрировать область bean во время выполнения

Я работаю над приложением Spring, которое регистрирует задачу настраиваемой области действия. Идея заключается в том, что при запуске новой задачи Spring должен поставлять объекты с областью.

Задача создается в среде выполнения. Он поставляется с некоторой конфигурацией в виде объекта Properties. Я хочу зарегистрировать этот объект с помощью ApplicationContext, но в пределах области задач, чтобы все beans внутри этой области могли ссылаться на конфигурацию этой конкретной задачи.

Вот приблизительная идея в коде:

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);        
    }
}

Я не могу понять, как я могу зарегистрировать bean в ApplicationContext, который имеет соответствующую область видимости.

Спасибо

Update:

Вот еще несколько кодов, чтобы объяснить вопрос немного лучше. 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);
        // ...
    }
}
4b9b3361

Ответ 1

Если я сделаю ваш последний комментарий:

Я хочу, чтобы в каждой области присутствовал 1 экземпляр SomeScopedBean (в пределах каждой MyTask), но каждый из них настроен с различной конфигурацией свойства (которые предоставляются платформой развертывания, когда она создает каждую задачу,

И особенно within each MyTask, и если он ограничен MyTask.

Вы можете:

  • define SomeScopedBean как прототип bean
  • создайте factory @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 необходимо ввести более чем в один bean с помощью области task/thread, вы можете изменить область действия своей области потока, например:

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

Ответ 2

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);

В вашем случае я бы зарегистрировал singleton MyTask Proxy. Прокси-сервер может хранить все ваши зависящие от области действия экземпляры (например, на карте или в хранилище ThreadLocal) и логику делегата вызова, чтобы скорректировать его с помощью карты.

UPDATE: На самом деле вы autowire не MyTask bean, а прокси. Прокси-сервер обертывает все методы MyTask. Прокси имеет тот же интерфейс, что и MyTask. Предположим, вы вызываете метод ProxyMyTask.do(). Прокси-сервер перехватывает вызов, получает какой-то объем, например. текущий поток в случае примера протектора и получить от карты (или для области потока из хранилища ThreadLocal) надлежащий экземпляр MyTask. Наконец вызывает метод do (0 найденного экземпляра MyTask.

ОБНОВЛЕНИЕ 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);
}