sirve que para ejemplo componentes component bean anotaciones spring constructor spring-annotations autowired

ejemplo - para que sirve spring



De todos modos, @Autowire un bean que requiere argumentos constructor? (8)

Estoy usando Spring 3.0.5 y estoy usando la anotación @Autowire para los miembros de mi clase tanto como sea posible. Uno de los beans que necesito para autoaumentar requiere argumentos para su constructor. Revisé los documentos de Spring, pero parece que no puedo encontrar ninguna referencia sobre cómo anotar los argumentos de los constructores.

En XML, puedo usarlo como parte de la definición de bean. ¿Hay un mecanismo similar para la anotación @Autowire?

Ex:

@Component public class MyConstructorClass{ String var; public MyConstructorClass( String constrArg ){ this.var = var; } ... } @Service public class MyBeanService{ @Autowired MyConstructorClass myConstructorClass; .... }

En este ejemplo, ¿cómo especifico el valor de "constrArg" en MyBeanService con la anotación @Autowire? ¿Hay alguna manera de hacer esto?

Gracias,

Eric


En este ejemplo, ¿cómo especifico el valor de "constrArg" en MyBeanService con la anotación @Autowire ? ¿Hay alguna manera de hacer esto?

No, no en la forma en que te refieres. El bean que representa MyConstructorClass debe ser configurable sin requerir ninguno de sus beans de cliente, por lo que MyBeanService no tiene voz en cómo se configura MyConstructorClass .

Esto no es un problema de autoenvío, el problema aquí es cómo Spring MyConstructorClass instancia de MyConstructorClass , dado que MyConstructorClass es un @Component (y está utilizando el escaneo de componentes, y por lo tanto no especifica un MyConstructorClass explícitamente en su configuración).

Como dijo @Sean, una respuesta aquí es usar @Value en el parámetro constructor, de modo que Spring obtenga el valor del constructor de una propiedad del sistema o archivo de propiedades. La alternativa es que MyBeanService instancia directamente MyConstructorClass , pero si lo haces, MyConstructorClass ya no es un Spring Bean.


Bueno, de vez en cuando me encuentro con la misma pregunta. Hasta donde yo sé, uno no puede hacer eso cuando uno quiere agregar parámetros dinámicos al constructor. Sin embargo, el patrón de fábrica puede ayudar.

public interface MyBean { // here be my fancy stuff } public interface MyBeanFactory { public MyBean getMyBean(/* bean parameters */); } @Component public class MyBeanFactoryImpl implements MyBeanFactory { @Autowired WhateverIWantToInject somethingInjected; public MyBean getMyBean(/* params */) { return new MyBeanImpl(/* params */); } private class MyBeanImpl implements MyBean { public MyBeanImpl(/* params */) { // let''s do whatever one has to } } } @Component public class MyConsumerClass { @Autowired private MyBeanFactory beanFactory; public void myMethod() { // here one has to prepare the parameters MyBean bean = beanFactory.getMyBean(/* params */); } }

Ahora, MyBean no es un grano de primavera per se, pero está lo suficientemente cerca. La Inyección de Dependencia funciona, aunque inyecte la fábrica y no el grano en sí, uno tiene que inyectar una nueva fábrica sobre su propia implementación MyBean si quiere reemplazarla.

Además, MyBean tiene acceso a otros beans, ya que puede tener acceso a los autocables de la fábrica.

Y uno podría querer agregar algo de lógica a la función getMyBean , que es un esfuerzo extra que permito, pero desafortunadamente no tengo una mejor solución. Dado que el problema generalmente es que los parámetros dinámicos provienen de una fuente externa, como una base de datos o interacción del usuario, por lo tanto debo instanciar ese bean solo a mitad de ejecución, solo cuando esa información esté disponible, por lo que la Factory debería ser bastante adecuada. .


La mayoría de las respuestas son bastante antiguas, por lo que podría no haber sido posible en aquel entonces, pero en realidad hay una solución que satisface todos los casos de uso posibles.

Así que bien, sé que las respuestas son:

  • No proporciona un componente real de Spring (el diseño de la fábrica)
  • o no se ajusta a todas las situaciones (usando @Value tienes que tener el valor en un archivo de configuración en alguna parte)

La solución para resolver esos problemas es crear el objeto manualmente utilizando ApplicationContext :

@Component public class MyConstructorClass { String var; public MyConstructorClass() {} public MyConstructorClass(String constrArg) { this.var = var; } } @Service public class MyBeanService implements ApplicationContextAware { private static ApplicationContext applicationContext; MyConstructorClass myConstructorClass; public MyBeanService() { // Creating the object manually MyConstructorClass myObject = new MyConstructorClass("hello world"); // Initializing the object as a Spring component AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory(); factory.autowireBean(myObject); factory.initializeBean(myObject, myObject.getClass().getSimpleName()); } @Override public void setApplicationContext(ApplicationContext context) throws BeansException { applicationContext = context; } }

Esta es una solución genial porque:

  • Te da acceso a todas las funcionalidades de Spring en tu objeto ( @Autowired obviamente, pero también @Async por ejemplo),
  • Puede usar cualquier fuente para sus argumentos de constructor (archivo de configuración, valor calculado, valor codificado, ...),
  • Solo requiere agregar algunas líneas de código sin tener que cambiar nada.
  • También se puede usar para crear dinámicamente un número desconocido de instancias de una clase administrada por Spring (lo estoy usando para crear múltiples ejecutores asincrónicos sobre la marcha, por ejemplo)

Lo único que debe tener en cuenta es que debe tener un constructor que no tome argumentos (y que pueda estar vacío) en la clase que desea instanciar (o un constructor @Autowired si lo necesita).


Necesita usar @Autowired y @Value. Consulte esta post para obtener más información sobre este tema.


Necesitas la anotación @Value .

Un caso de uso común es asignar valores de campo predeterminados utilizando expresiones de estilo "#{systemProperties.myProp}" .

public class SimpleMovieLister { private MovieFinder movieFinder; private String defaultLocale; @Autowired public void configure(MovieFinder movieFinder, @Value("#{ systemProperties[''user.region''] }"} String defaultLocale) { this.movieFinder = movieFinder; this.defaultLocale = defaultLocale; } // ... }

Ver: Lenguaje de Expresión> Configuración de Anotación

Para ser más claro: en su escenario, conectaría dos clases, MybeanService y MyConstructorClass , algo como esto:

@Component public class MyBeanService implements BeanService{ @Autowired public MybeanService(MyConstructorClass foo){ // do something with foo } } @Component public class MyConstructorClass{ public MyConstructorClass(@Value("#{some expression here}") String value){ // do something with value } }

Actualización: si necesita varias instancias diferentes de MyConstructorClass con valores diferentes, debe usar las anotaciones de Calificador


Otra alternativa, si ya tiene una instancia del objeto creado y desea agregarla como una dependencia @autowired para inicializar todas las variables internas de @autowired, podría ser la siguiente:

@Autowired private AutowireCapableBeanFactory autowireCapableBeanFactory; public void doStuff() { YourObject obj = new YourObject("Value X", "etc"); autowireCapableBeanFactory.autowireBean(obj); }


También puede configurar su componente de esta manera:

package mypackage; import org.springframework.context.annotation.Configuration; @Configuration public class MyConstructorClassConfig { @Bean public MyConstructorClass myConstructorClass(){ return new myConstructorClass("foobar"); } } }

Con la anotación Bean , le está diciendo a Spring que registre el bean devuelto en BeanFactory .

Para que pueda conectarlo como desee.


Una alternativa sería, en lugar de pasar los parámetros al constructor, tenerlos como getter y setters y luego, en @PostConstruct, inicializar los valores como lo desee. En este caso, Spring creará el bean usando el constructor predeterminado. Un ejemplo está debajo

@Component public class MyConstructorClass{ String var; public void setVar(String var){ this.var = var; } public void getVar(){ return var; } @PostConstruct public void init(){ setVar("var"); } ... } @Service public class MyBeanService{ //field autowiring @Autowired MyConstructorClass myConstructorClass; .... }