springframework property org leer beans annotation java spring dependency-injection

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



spring inject property value constructor (17)

Antes de obtener Spring 3, que le permite inyectar constantes de propiedades directamente en sus beans mediante anotaciones, escribí una subclase del bean PropertyPlaceholderConfigurer que hace lo mismo. Por lo tanto, puede marcar sus creadores de propiedades y Spring autowire sus propiedades en sus beans como:

@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 a gusto

Tengo un montón de frijoles de primavera 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:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="/WEB-INF/app.properties" /> </bean>

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

<bean class="com.example.PersonDaoImpl"> <property name="maxResults" value="${results.max}"/> </bean>

Debido a que PersonDaoImpl no aparece en el archivo XML de Spring (se recoge de la ruta de clase a través de anotaciones). He llegado 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 en la que estoy interesado desde ppc ?


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

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<String> currencyTypes;

Otro para obtener un set de una list

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

También puede establecer valores para tipos primitivos.

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

Puedes llamar métodos estáticos:

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

Puedes tener logica

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


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

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 XML Bean:

<bean id="Bean1" class="org.some.beans.MyBean"> <property name="id" value="1"/> <property name="name" value="MyBean"/> </bean>

Para cada property nombre, se invocará setProperty(value) .

Esta forma es especialmente útil si necesita más de un bean basado en una implementación.

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

<bean id="Bean2" class="org.some.beans.MyBean"> <property name="id" value="2"/> <property name="name" value="EnotherBean"/> </bean>

Entonces codifique 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());

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) { ... } } }


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


Manera de primavera:
private @Value("${propertyName}") String propertyField;

es una nueva forma de inyectar el valor utilizando la clase "PropertyPlaceholderConfigurer" de Spring. Otra forma es llamar

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

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


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

Para tener ambos, un bean de propiedades que se puede conectar automáticamente y un PropertyConfigurer, puede escribir:

<bean id="appProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="singleton" value="true" /> <property name="ignoreResourceNotFound" value="true" /> <property name="locations"> <list> <value>classpath:live.properties</value> <value>classpath:development.properties</value> </list> </property> </bean>

y referencia el Bean de Propiedades en el PropertyConfigurer

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="properties" ref="appProperties" /> </bean>


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

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="/WEB-INF/app.properties" /> </bean> <bean id="appProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="singleton" value="true"/> <property name="properties"> <props> <prop key="results.max">${results.max}</prop> </props> </property> </bean>

Cuando se recupera, este bean se puede convertir en un java.util.Properties que contendrá una propiedad llamada results.max cuyo valor se lee desde app.properties . Nuevamente, este bean puede ser una dependencia 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 puede limitar exactamente qué propiedades están expuestas por appProperties y no es necesario leer app.properties dos veces.


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

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

de la página de Captain Debug

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


Personalmente me encanta esta nueva forma en la primavera 3.0 de los documentos :

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

No hay captadores o setters!

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

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="classpath:propertyFile.properties" name="propertiesBean"/>

Para mejorar 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(); }


Puedes 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 desea 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 del blog que escribí sobre esto para un poco más de información.


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

En nuestra aplicación utilizamos:

  • Preferencias para configurar el sistema PreProd y Prod.
  • Preferencias y variables de entorno JNDI (JNDI sobrescribe las preferencias) para "mvn jetty: run"
  • Propiedades del sistema para UnitTests (@BeforeClass anotación)

El orden predeterminado en el que la clave-valor-Fuente se verifica primero, se describe en:
http://settings4j.sourceforge.net/currentrelease/configDefault.html
Se puede personalizar con un settings4j.xml (exacto a log4j.xml) en su classpath.

Déjame saber tu opinión: [email protected]

con un cordial saludo,
Harald


Si se queda atascado utilizando Spring 2.5, podría definir un bean para cada una de sus propiedades e inyectarlos utilizando calificadores. Me gusta esto:

<bean id="someFile" class="java.io.File"> <constructor-arg value="${someFile}"/> </bean>

y

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

No es super legible pero hace el trabajo.


También puedes anotar tu clase:

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

Y tener una variable como esta:

@Autowired private Environment env;

Ahora puedes acceder a todas tus propiedades de esta manera:

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


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

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="/WEB-INF/app.properties" /> </bean> <util:properties id="appProperties" location="classpath:/WEB-INF/app.properties"/>

El bean denominado ''appProperties'' es de tipo java.util.Properties y se puede inyectar la dependencia utilizando el @Resource attruibute que se muestra arriba.


Utilice la clase "PropertyPlaceholderConfigurer" de Spring

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

<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>/WEB-INF/classes/config_properties/dev/database.properties</value> </list> </property> </bean> <bean id="devDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${dev.app.jdbc.driver}"/> <property name="jdbcUrl" value="${dev.app.jdbc.url}"/> <property name="user" value="${dev.app.jdbc.username}"/> <property name="password" value="${dev.app.jdbc.password}"/> <property name="acquireIncrement" value="3"/> <property name="minPoolSize" value="5"/> <property name="maxPoolSize" value="10"/> <property name="maxStatementsPerConnection" value="11000"/> <property name="numHelperThreads" value="8"/> <property name="idleConnectionTestPeriod" value="300"/> <property name="preferredTestQuery" value="SELECT 0"/> </bean>

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


<context:property-placeholder ... /> es el equivalente de XML al PropertyPlaceholderConfigurer.

Ejemplo: applicationContext.xml

<context:property-placeholder location="classpath:test.properties"/>

Clase de componente

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


Autowiring valores de propiedad en frijoles de primavera:

La mayoría de la gente sabe que puede usar @Autowired para decirle a Spring que inyecte un objeto en otro cuando carga 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. ver esta publicación para más información ...

novedades en la primavera 3.0 || autowiring valores de frijol || valores de propiedad de autowiring en primavera