Estoy trabajando en una aplicación basada en Spring que registra una "tarea" de alcance personalizado . La idea es que cuando se inicia una nueva tarea, Spring debe proporcionar objetos en el ámbito de la tarea .
La tarea se instancia en el tiempo de ejecución. Se suministra con alguna configuración en forma de objeto de Properties
. Quiero registrar ese objeto con ApplicationContext
pero dentro del alcance de la tarea para que todos los beans dentro de ese alcance puedan hacer referencia a la configuración de esa tarea en particular.
Aquí está la idea aproximada en el código:
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); } }
No puedo entender cómo puedo registrar un bean en ApplicationContext
que tiene el alcance adecuado.
Gracias
Actualizar:
Aquí hay más código para explicar la pregunta un poco mejor. SomeScopedBean
debería estar haciendo algo con la configuración que se le ha proporcionado y se parece a esto:
public class SomeScopedBean { @Autowire public SomeScopedBean (Properties configuration) { // do some work with the configuration } }
La idea de la aplicación es que debe tener varias instancias de MyTask
ejecutándose con una configuración diferente y cada tarea tiene su propio alcance. Dentro del alcance de cada tarea, debe haber 1 instancia de SomeScopedBean
inicializada con la configuración de la tarea.
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); // ... } }
Si tomo tu último comentario:
Lo que quiero es tener 1 instancia de SomeScopedBean dentro de cada ámbito (dentro de cada MyTask), pero cada uno configurado con diferentes propiedades de configuración (que proporciona el marco de implementación cuando instancia cada Tarea,
Y sobre todo within each MyTask
y si se limita a MyTask
.
Puedes:
SomeScopedBean
como un bean prototipoSomeScopedBean
@Configuration
la configuración de propiedades proporcionadaPrimero la configuración:
@Configuration public class SomeScopedBeanFactoryConfiguration { @Bean @Scope(BeanDefinition.SCOPE_PROTOTYPE) public SomeScopedBean create(Properties configuration) { return new SomeScopedBean(configuration); } }
Luego conectó SomeScopedBeanFactoryConfiguration
a MyTask
y crea SomeScopedBean
:
public class MyTask extends SourceTask { @Autowired private SomeScopedBeanFactoryConfiguration someScopedBeanFactoryConfiguration; @Override public void start(Map<String, String> props) { SomeScopedBean scopedBean = someScopedBeanFactoryConfiguration.create(props); } }
Nota: si SomeScopedBean
debe inyectarse en más de un bean con el alcance de la task
/ thread
, puede cambiar su alcance al alcance de su subproceso, por ejemplo:
@Bean @Scope("thread") public SomeScopedBean create(Properties configuration) { return new SomeScopedBean(configuration); }
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);
En su caso, registraría singleton de MyTask Proxy. El proxy puede mantener todas sus instancias dependientes del alcance (por ejemplo, en un mapa o en el almacenamiento ThreadLocal) y en la lógica de delegado de llamadas para corregir una del mapa.
ACTUALIZACIÓN: En realidad, no autoconectas el bean MyTask sino un Proxy. El proxy envuelve todos los métodos de MyTask. Proxy tiene la misma interfaz que MyTask. Suponga que llama al método ProxyMyTask.do(). El proxy intercepta la llamada, obtiene de alguna manera el alcance, por ejemplo, el hilo actual en el caso del ejemplo de Tread Scope y obtiene del mapa (o para el alcance del hilo del almacenamiento ThreadLocal) la instancia adecuada de MyTask. Finalmente llama al método do(0 de la instancia de MyTask encontrada.
ACTUALIZACIÓN 2: vea el ejemplo http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html Puede envolver fácilmente una interfaz. Su lógica para determinar el alcance y devolver la instancia adecuada debe estar en el método
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(target, args); }