¿Cómo puedo inyectar un valor de propiedad en un Spring Bean que se configuró usando anotaciones?

Tengo un montón de frijoles de spring que se recogen de la ruta de clase a través de anotaciones, por ejemplo

@Repository("personDao") public class PersonDaoImpl extends AbstractDaoImpl implements PersonDao { // Implementation omitted } 

En el archivo XML de Spring, hay un PropertyPlaceholderConfigurer definido:

    

Quiero inyectar una de las propiedades de app.properites en el bean que se muestra arriba. No puedo simplemente hacer algo como

    

Debido a que PersonDaoImpl no aparece en el archivo XML de Spring (se recoge de classpath a través de anotaciones). Llegué hasta lo siguiente:

 @Repository("personDao") public class PersonDaoImpl extends AbstractDaoImpl implements PersonDao { @Resource(name = "propertyConfigurer") protected void setProperties(PropertyPlaceholderConfigurer ppc) { // Now how do I access results.max? } } 

Pero no me queda claro cómo accedo a la propiedad que me interesa de ppc ?

Puede hacer esto en Spring 3 usando el soporte EL. Ejemplo:

 @Value("#{systemProperties.databaseName}") public void setDatabaseName(String dbName) { ... } @Value("#{strategyBean.databaseKeyGenerator}") public void setKeyGenerator(KeyGenerator kg) { ... } 

systemProperties es un objeto implícito y strategyBean es un nombre de bean.

Un ejemplo más, que funciona cuando quieres tomar una propiedad de un objeto Properties . También muestra que puede aplicar @Value a los campos:

 @Value("#{myProperties['github.oauth.clientId']}") private String githubOauthClientId; 

Aquí hay una publicación de blog que escribí sobre esto para obtener un poco más de información.

Personalmente, me encanta esta nueva forma en Spring 3.0 de los documentos :

 private @Value("${propertyName}") String propertyField; 

¡Sin getters o setters!

Con las propiedades cargadas a través de la configuración:

  

Para boost mi alegría, incluso puedo controlar el clic en la expresión EL en IntelliJ y me lleva a la definición de propiedad.

También está la versión totalmente no xml :

 @PropertySource("classpath:propertyFile.properties") public class AppConfig { @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } 

Hay una nueva anotación @Value en Spring 3.0.0M3 . @Value no solo admite @Value #{...} , sino ${...} marcadores de posición

es el XML equivalente al PropertyPlaceholderConfigurer.

Ejemplo: applicationContext.xml

  

Clase de componente

  private @Value("${propertyName}") String propertyField; 

Otra alternativa es agregar el bean appProperties que se muestra a continuación:

        ${results.max}    

Cuando se recupera, este bean se puede convertir en java.util.Properties que contendrá una propiedad llamada results.max cuyo valor se lee desde app.properties . De nuevo, este bean puede ser una inyección inyectada (como una instancia de java.util.Properties) en cualquier clase a través de la anotación @Resource.

Personalmente, prefiero esta solución (a la otra que propuse), ya que puedes limitar exactamente qué propiedades están expuestas por appProperties, y no necesitas leer app.properties dos veces.

Necesito tener dos archivos de propiedades, uno para producción y otro para desarrollo (que no se implementarán).

Para tener ambos, un Bean de propiedades que se puede autoconectar y un PropertyConfigurer, puede escribir:

      classpath:live.properties classpath:development.properties    

y referencia el Propiedades Bean en el PropertyConfigurer

    

Antes de que obtengamos el resorte 3, que le permite inyectar constantes de propiedad directamente en sus granos usando anotaciones, escribí una subclase del bean PropertyPlaceholderConfigurer que hace lo mismo. Por lo tanto, puede marcar sus configuradores de propiedades y Spring conectará automáticamente sus propiedades a sus granos de la siguiente manera:

 @Property(key="property.key", defaultValue="default") public void setProperty(String property) { this.property = property; } 

La anotación es la siguiente:

 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.FIELD}) public @interface Property { String key(); String defaultValue() default ""; } 

El PropertyAnnotationAndPlaceholderConfigurer es el siguiente:

 public class PropertyAnnotationAndPlaceholderConfigurer extends PropertyPlaceholderConfigurer { private static Logger log = Logger.getLogger(PropertyAnnotationAndPlaceholderConfigurer.class); @Override protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties properties) throws BeansException { super.processProperties(beanFactory, properties); for (String name : beanFactory.getBeanDefinitionNames()) { MutablePropertyValues mpv = beanFactory.getBeanDefinition(name).getPropertyValues(); Class clazz = beanFactory.getType(name); if(log.isDebugEnabled()) log.debug("Configuring properties for bean="+name+"["+clazz+"]"); if(clazz != null) { for (PropertyDescriptor property : BeanUtils.getPropertyDescriptors(clazz)) { Method setter = property.getWriteMethod(); Method getter = property.getReadMethod(); Property annotation = null; if(setter != null && setter.isAnnotationPresent(Property.class)) { annotation = setter.getAnnotation(Property.class); } else if(setter != null && getter != null && getter.isAnnotationPresent(Property.class)) { annotation = getter.getAnnotation(Property.class); } if(annotation != null) { String value = resolvePlaceholder(annotation.key(), properties, SYSTEM_PROPERTIES_MODE_FALLBACK); if(StringUtils.isEmpty(value)) { value = annotation.defaultValue(); } if(StringUtils.isEmpty(value)) { throw new BeanConfigurationException("No such property=["+annotation.key()+"] found in properties."); } if(log.isDebugEnabled()) log.debug("setting property=["+clazz.getName()+"."+property.getName()+"] value=["+annotation.key()+"="+value+"]"); mpv.addPropertyValue(property.getName(), value); } } for(Field field : clazz.getDeclaredFields()) { if(log.isDebugEnabled()) log.debug("examining field=["+clazz.getName()+"."+field.getName()+"]"); if(field.isAnnotationPresent(Property.class)) { Property annotation = field.getAnnotation(Property.class); PropertyDescriptor property = BeanUtils.getPropertyDescriptor(clazz, field.getName()); if(property.getWriteMethod() == null) { throw new BeanConfigurationException("setter for property=["+clazz.getName()+"."+field.getName()+"] not available."); } Object value = resolvePlaceholder(annotation.key(), properties, SYSTEM_PROPERTIES_MODE_FALLBACK); if(value == null) { value = annotation.defaultValue(); } if(value == null) { throw new BeanConfigurationException("No such property=["+annotation.key()+"] found in properties."); } if(log.isDebugEnabled()) log.debug("setting property=["+clazz.getName()+"."+field.getName()+"] value=["+annotation.key()+"="+value+"]"); mpv.addPropertyValue(property.getName(), value); } } } } } } 

Siéntase libre de modificar al gusto

Camino de spring:
private @Value("${propertyName}") String propertyField;

es una nueva forma de inyectar el valor usando la clase “PropertyPlaceholderConfigurer” de Spring. Otra forma es llamar

 java.util.Properties props = System.getProperties().getProperty("propertyName"); 

Nota: Para @Value, no puede usar staticField, debe ser no solo estático, de lo contrario, devuelve null. Para solucionarlo, se crea un setter no estático para el campo estático y @Value se aplica sobre ese setter.

Una posible solución es declarar un segundo bean que lea desde el mismo archivo de propiedades:

     

El bean llamado ‘appProperties’ es del tipo java.util.Properties y se puede inyectar mediante la entrada @Resource attruibute que se muestra arriba.

También puede anotar su clase:

 @PropertySource("classpath:/com/myProject/config/properties/database.properties") 

Y tiene una variable como esta:

 @Autowired private Environment env; 

Ahora puede acceder a todas sus propiedades de esta manera:

 env.getProperty("database.connection.driver") 

Si estás atascado con Spring 2.5, puedes definir un bean para cada una de tus propiedades e inyectarlas usando calificadores. Me gusta esto:

     

y

 @Service public class Thing public Thing(@Qualifier("someFile") File someFile) { ... 

No es súper legible pero hace el trabajo bien.

Como se mencionó, @Value hace el trabajo y es bastante flexible, ya que puede tener EL de spring.

Aquí hay algunos ejemplos que podrían ser útiles:

 //Build and array from comma separated parameters //Like currency.codes.list=10,11,12,13 @Value("#{'${currency.codes.list}'.split(',')}") private List currencyTypes; 

Otro para obtener un set de una list

 //If you have a list of some objects like (List) //and the BranchVO has areaCode,cityCode,... //You can easily make a set or areaCodes as below @Value("#{BranchList.![areaCode]}") private Set areas; 

También puede establecer valores para tipos primitivos.

 @Value("${amount.limit}") private int amountLimit; 

Puede llamar a métodos estáticos:

 @Value("#{T(foo.bar).isSecurityEnabled()}") private boolean securityEnabled; 

Puedes tener lógica

 @Value("#{T(foo.bar).isSecurityEnabled() ? '${security.logo.path}' : '${default.logo.path}'}") private String logoPath; 

Autocablear valores de propiedad en Spring Beans:

La mayoría de las personas sabe que puede usar @Autowired para decirle a Spring que inyecte un objeto en otro cuando cargue el contexto de su aplicación. Un nugget de información menos conocido es que también puede usar la anotación @Value para inyectar valores de un archivo de propiedades en los atributos de un bean. mira esta publicación para más información …

cosas nuevas en Spring 3.0 || valores del bebedero automático || autocablear los valores de las propiedades en spring

Para mí, fue la respuesta de @ Lucky, y específicamente, la línea

 AutowiredFakaSource fakeDataSource = ctx.getBean(AutowiredFakaSource.class); 

de la página Captain Debug

eso solucionó mi problema Tengo una aplicación basada en ApplicationContext que se ejecuta desde la línea de comandos y, a juzgar por varios comentarios sobre SO, Spring conecta estas aplicaciones de forma diferente a las basadas en MVC.

Si necesita más flexibilidad para las configuraciones, intente con Settings4jPlaceholderConfigurer: http://settings4j.sourceforge.net/currentrelease/configSpringPlaceholder.html

En nuestra aplicación usamos:

  • Preferencias para configurar el sistema PreProd y Prod
  • Preferencias y variables de entorno JNDI (JNDI sobrescribe las preferencias) para “mvn embarcadero: ejecutar”
  • Propiedades del sistema para UnitTests (anotación @BeforeClass)

La orden por defecto que key-value-Source se verifica primero, se describe en:
http://settings4j.sourceforge.net/currentrelease/configDefault.html
Se puede personalizar con un settings4j.xml (preciso para log4j.xml) en su classpath.

Déjame saber tu opinión: settings4j-user@lists.sourceforge.net

con cordiales saludos,
Harald

Creo que es la forma más conveniente de inyectar propiedades en el método bean is setter.

Ejemplo:

 package org.some.beans; public class MyBean { Long id; String name; public void setId(Long id) { this.id = id; } public Long getId() { return id; } public void setName(String name) { this.name = name; } public String getName() { return name; } } 

Definición de frijol xml:

     

Para cada método de property nombrado se invocará setProperty(value) .

De esta manera es especialmente útil si necesita más de un bean en base a una implementación.

Por ejemplo, si definimos un bean más en xml:

     

Luego codifica así:

 MyBean b1 = appContext.getBean("Bean1"); System.out.println("Bean id = " + b1.getId() + " name = " + b1.getName()); MyBean b2 = appContext.getBean("Bean2"); System.out.println("Bean id = " + b2.getId() + " name = " + b2.getName()); 

Se imprimirá

 Bean id = 1 name = MyBean Bean id = 2 name = AnotherBean 

Entonces, en tu caso debería verse así:

 @Repository("personDao") public class PersonDaoImpl extends AbstractDaoImpl implements PersonDao { Long maxResults; public void setMaxResults(Long maxResults) { this.maxResults = maxResults; } // Now use maxResults value in your code, it will be injected on Bean creation public void someMethod(Long results) { if (results < maxResults) { ... } } } 

Use la clase “PropertyPlaceholderConfigurer” de Spring

Un ejemplo simple que muestra el archivo de propiedades leído dinámicamente como propiedad de bean

    /WEB-INF/classes/config_properties/dev/database.properties                 

Archivo de propiedad

dev.app.jdbc.driver = com.mysql.jdbc.Driver

dev.app.jdbc.url = jdbc: mysql: // localhost: 3306 / addvertisement

dev.app.jdbc.username = root

dev.app.jdbc.password = root