Saltar al contenido

Spring Java Config: ¿cómo se crea un @Bean con ámbito de prototipo con argumentos en tiempo de ejecución?

Nuestros programadores estrellas han agotado sus reservas de café, por su búsqueda a tiempo completo por la solución, hasta que Linda halló el resultado en GitLab y ahora la comparte aquí.

Solución:

en un @Configuration clase A @Bean método así

@Bean
@Scope("prototype")
public Thing thing(String name) 
    return new Thing(name);

se utiliza para registrar un definición de frijol y proporcionar la fábrica para crear el frijol. El bean que define solo se instancia a pedido utilizando argumentos que se determinan directamente o mediante el escaneo que ApplicationContext.

En el caso de un prototype bean, un nuevo objeto se crea cada vez y por lo tanto el correspondiente @Bean también se ejecuta el método.

Puede recuperar un frijol del ApplicationContext a través de su BeanFactory#getBean(String name, Object... args) método que establece

Permite especificar argumentos de constructor explícitos / argumentos de método de fábrica, anulando los argumentos predeterminados especificados (si los hay) en la definición del bean.

Parámetros:

argumentos argumentos a utilizar si se crea un prototipo utilizando argumentos explícitos para un static método de fábrica. No es válido utilizar unnull valor de args en cualquier otro caso.

En otras palabras, por esto prototype bean con ámbito, está proporcionando los argumentos que se utilizarán, no en el constructor de la clase de bean, sino en el @Bean invocación del método. (Este método tiene garantías de tipo muy débiles ya que utiliza una búsqueda de nombre para el bean).

Alternativamente, puede usar el mecanografiado BeanFactory#getBean(Class requiredType, Object... args) método que busca el bean por tipo.

Esto es al menos true para las versiones Spring 4+.

Tenga en cuenta que, si no desea comenzar con el ApplicationContext o BeanFactory para la recuperación de su frijol, puede inyectar un ObjectProvider (desde Spring 4.3).

Una variante de ObjectFactory diseñado específicamente para puntos de inyección, lo que permite la opcionalidad programática y un manejo indulgente y no exclusivo.

y usa su getObject(Object... args) método

Devuelve una instancia (posiblemente compartida o independiente) del objeto administrado por esta fábrica.

Permite especificar argumentos de construcción explícitos, en la línea de BeanFactory.getBean(String, Object).

Por ejemplo,

@Autowired
private ObjectProvider things;

[...]
Thing newThing = things.getObject(name);
[...]

Con Spring> 4.0 y Java 8 puede hacer esto de forma más segura:

@Configuration    
public class ServiceConfig 

    @Bean
    public Function thingFactory() 
        return name -> thing(name); // or this::thing
     

    @Bean
    @Scope(value = "prototype")
    public Thing thing(String name) 
       return new Thing(name);
    


Uso:

@Autowired
private Function thingFactory;

public void onRequest(Request request) 
    //request is already validated
    String name = request.getParameter("name");
    Thing thing = thingFactory.apply(name);

    // ...

Entonces ahora puede obtener su bean en tiempo de ejecución. Este es un patrón de fábrica, por supuesto, pero puede ahorrar algo de tiempo escribiendo clases específicas como ThingFactory (sin embargo, tendrá que escribir personalizado @FunctionalInterface para pasar más de dos parámetros).

Desde Spring 4.3, hay una nueva forma de hacerlo, que fue cosida para ese problema.

ObjectProvider: le permite simplemente agregarlo como una dependencia a su bean con ámbito de prototipo “argumentado” y crear una instancia usando el argumento.

Aquí hay un ejemplo simple de cómo usarlo:

@Configuration
public class MyConf 
    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public MyPrototype createPrototype(String arg) 
        return new MyPrototype(arg);
    


public class MyPrototype 
    private String arg;

    public MyPrototype(String arg) 
        this.arg = arg;
    

    public void action() 
        System.out.println(arg);
    



@Component
public class UsingMyPrototype 
    private ObjectProvider myPrototypeProvider;

    @Autowired
    public UsingMyPrototype(ObjectProvider myPrototypeProvider) 
        this.myPrototypeProvider = myPrototypeProvider;
    

    public void usePrototype() 
        final MyPrototype myPrototype = myPrototypeProvider.getObject("hello");
        myPrototype.action();
    

Esto, por supuesto, imprimirá hola string al llamar a usePrototype.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *