주석을 사용하여 구성된 Spring Bean에 속성 값을 삽입하는 방법은 무엇입니까?


294

주석을 통해 클래스 패스에서 가져온 스프링 콩이 있습니다.

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

Spring XML 파일에는 PropertyPlaceholderConfigurer가 정의되어 있습니다.

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

app.properites의 속성 중 하나를 위에 표시된 bean에 주입하고 싶습니다. 나는 단순히 같은 것을 할 수 없다

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

PersonDaoImpl은 Spring XML 파일에 포함되어 있지 않기 때문에 (주석을 통해 클래스 경로에서 선택된다). 나는 다음과 같은 것을 얻었습니다.

@Repository("personDao")
public class PersonDaoImpl extends AbstractDaoImpl implements PersonDao {

    @Resource(name = "propertyConfigurer")
    protected void setProperties(PropertyPlaceholderConfigurer ppc) {
    // Now how do I access results.max? 
    }
}

그러나 내가 관심있는 부동산에 어떻게 접근하는지는 확실하지 않습니다 ppc.


1
약간 다른 시나리오 인 stackoverflow.com/questions/310271/… 에도 불구하고 본질적으로 동일한 질문을했습니다 . 지금까지 아무도 대답 할 수 없었습니다.
스펜서 Kormos

Spring 3.1부터는 PropertyPlaceholderConfigurer더 이상 권장 클래스가 아닙니다. PropertySourcesPlaceholderConfigurer대신 선호하십시오 . 어쨌든 더 짧은 XML 정의를 사용할 수 있습니다 <context:property-placeholder />.
Michael Piefel

답변:


292

EL 지원을 사용하여 Spring 3 에서이 작업을 수행 할 수 있습니다. 예:

@Value("#{systemProperties.databaseName}")
public void setDatabaseName(String dbName) { ... }

@Value("#{strategyBean.databaseKeyGenerator}")
public void setKeyGenerator(KeyGenerator kg) { ... }

systemProperties내재 된 오브젝트이며 strategyBeanBean 이름입니다.

Properties객체 에서 속성을 가져 오려고 할 때 작동하는 또 하나의 예 입니다. 또한 @Value필드에 적용 할 수 있음을 보여줍니다 .

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

여기입니다 블로그 게시물 내가 좀 더 정보를 원하시면 이것에 대해 썼다는.


8
systemProperties단순히 System.getProperties()? 스프링 빈에 자신의 속성을 주입하려면 <bean id="appProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">다음과 같은 것을 사용하여 다른 빈에 값을 읽어야합니다.@Value("#{appProperties.databaseName}")
Dónal

11
당신은 또한 표현 $ {db.doStuff}에 자리를 사용할 수있는 최대의 대답에서 참고해야합니다, 당신은 단지 placeholderConfigurer 인 PropertiesFactoryBean을 필요로하지 않습니다
gtrak

9
util : properties를 사용하여 고유 한 속성을 추가 할 수 있습니다. 예 : <util : properties id = "config"location = "classpath : /spring/environment.properties"/> 값을 얻는 방법은 편집 된 답변을 참조하십시오. (이것은 아마도 Don에게 도움이 되기에는 너무 늦었다는 것을 알고 있지만, 다른 사람들은 희망적으로 도움이 될 것입니다.)

2
appname-servlet.xml 파일에서 util : properties를 사용할 때만 작동했습니다. 내 applicationContext.xml (Spring MVC가 아닌)에 정의 된 propertyConfigurer를 사용하면 작동하지 않습니다.
Asaf Mesika

좀 더 자세한 내용은이 SOF 질문도 확인하십시오. stackoverflow.com/questions/6425795/…
arcseldon

143

개인적으로 나는 문서 에서 봄 3.0의 새로운 방법을 좋아합니다 .

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

게터 나 세터가 없습니다!

구성을 통해 속성을로드하는 경우 :

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

내 기쁨을 더하기 위해 IntelliJ에서 EL 표현식을 클릭하여 제어 할 수 있으며 속성 정의가 나타납니다!

완전히 비 XML 버전도 있습니다 .

@PropertySource("classpath:propertyFile.properties")
public class AppConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

9
p : 접두사 속성을 사용하려면 네임 스페이스 uri xmlns : p = " springframework.org/schema/p "를 추가하십시오 .
shane lee

3
왜이 메소드는 테스트 컨텍스트에서 작동하지만 기본 컨텍스트에서는 작동하지 않습니까?
luksmir

9
한숨, 나는 주석 전용 접근 방식을 만들기 위해 시간을 보냈고 마법의 정적 bean PropertySauceYadaYada 의이 답변을 읽은 후에 만 ​​무엇이 누락되었는지 발견했습니다. 봄 사랑!
Kranach

@ barrymac 안녕 배리, U @Value (# {...})와 @Value ($ {...})의 차이점을 알고 있습니까? 감사합니다
Kim

1
이것은 나를 위해 작동합니다. 한 가지 팁 : 주석 @Component가 필요합니다.
yaki_nuka

121

새로운 주석이 @Value봄 3.0.0M3은 . 표현뿐만 아니라 자리 표시 자도 @Value지원#{...}${...}


20
+1 예제가 도움이된다면 -Value (value = "# { '$ {server.env}'}") 또는 간단히 @Value ( "# { '$ {server.env}'}")입니다
Somu

31

<context:property-placeholder ... /> PropertyPlaceholderConfigurer와 동등한 XML입니다.

예 : applicationContext.xml

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

컴포넌트 클래스

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

1
나를 위해, 이것은 자동 배선을 통해 활성화 된 경우에만 작동했습니다. <context:component-scan base-package="com.company.package" />참고 용 ApplicationContext으로 웹 컨텍스트가 아닌을 통해 스프링을 사용하고 있습니다.
Mustafa

15

다른 대안은 아래에 표시된 appProperties Bean을 추가하는 것입니다.

<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>

검색 할 때이 Bean을 java.util.Propertiesresults.max 에서 값을 읽는 이름 이 지정된 특성을 포함하는app.properties . 이 Bean은 @Resource 어노테이션을 통해 모든 클래스에 java.util.Properties의 인스턴스로 종속성을 주입 할 수 있습니다.

개인적으로 appProperties에 의해 노출되는 속성을 정확하게 제한하고 app.properties를 두 번 읽을 필요가 없으므로이 솔루션을 제안합니다 (다른 제안보다).


나에게도 효과가 있습니다. 그러나 @Value 주석을 통해 PropertyPlaceholderConfigurer에서 속성을 액세스 할 수있는 다른 방법이 있습니까 (여러 congif XML 파일에서 여러 PropertyPlaceholderConfigurer를 사용하는 경우)?
Czar

9

프로덕션 용 파일과 개발 용 재정의 파일 (배포되지 않음)의 두 가지 속성 파일이 필요합니다.

자동 배선 할 수있는 Properties Bean과 PropertyConfigurer를 모두 갖기 위해 다음과 같이 작성할 수 있습니다.

<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>

PropertyConfigurer에서 특성 Bean을 참조하십시오.

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

7

주석 3을 사용하여 빈에 속성 상수를 직접 주입 할 수있는 Spring 3을 얻기 전에 동일한 작업을 수행하는 PropertyPlaceholderConfigurer 빈의 하위 클래스를 작성했습니다. 따라서 속성 설정자를 마크 업할 수 있고 Spring은 다음과 같이 빈에 속성을 자동 와이어 링합니다.

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

주석은 다음과 같습니다.

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

PropertyAnnotationAndPlaceholderConfigurer는 다음과 같습니다.

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);
                    }
                }
            }
        }
    }

}

취향에 따라 자유롭게 수정하십시오



7

수업에 주석을 달 수도 있습니다.

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

그리고 다음과 같은 변수가 있습니다 :

@Autowired
private Environment env;

이제 다음과 같은 방법으로 모든 속성에 액세스 할 수 있습니다.

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

7

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

Spring의 "PropertyPlaceholderConfigurer"클래스를 사용하여 값을 주입하는 새로운 방법입니다. 다른 방법은 전화하는 것입니다

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

참고 : @Value의 경우 static propertyField를 사용할 수 없습니다. 정적 이 아닌 것이어야하며, 그렇지 않으면 null을 반환합니다. 이를 수정하기 위해 정적 필드에 대해 비 정적 설정자가 작성되고 @Value가 해당 설정자 위에 적용됩니다.


7

언급했듯이 @Value작업은 스프링 EL을 가질 수 있으므로 매우 유연합니다.

다음은 도움이 될만한 몇 가지 예입니다.

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

또 다른이를 얻기 위해 setA로부터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;

기본 유형에 대한 값을 설정할 수도 있습니다.

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

정적 메소드를 호출 할 수 있습니다.

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

당신은 논리를 가질 수 있습니다

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

5

가능한 해결책은 동일한 특성 파일에서 읽는 두 번째 Bean을 선언하는 것입니다.

<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"/>

'appProperties'라는 이름의 Bean은 java.util.Properties 유형이며 위에 표시된 @Resource attruibute를 사용하여 종속성을 주입 할 수 있습니다.


4

Spring 2.5를 사용하지 않으면 각 속성에 대해 bean을 정의하고 한정자를 사용하여 주입 할 수 있습니다. 이처럼 :

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

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

읽을 수는 없지만 작업을 완료합니다.


2

스프링 빈에 프로퍼티 값 자동 연결 :

대부분의 사람들은 @Autowired를 사용하여 Spring이 애플리케이션 컨텍스트를로드 할 때 한 객체를 다른 객체에 주입하도록 지시 할 수 있다는 것을 알고 있습니다. 덜 알려진 정보는 @Value 어노테이션을 사용하여 특성 파일의 값을 Bean 속성에 삽입 할 수도 있다는 것입니다. 자세한 내용은이 게시물을 참조하십시오 ...

Spring 3.0의 새로운 것들 || 자동 배선 빈 값 || 스프링의 자동 배선 속성 값


2

나를 위해, 그것은 @Lucky의 대답이었습니다.

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

에서 선장 디버그 페이지

그게 내 문제를 해결했다. Spring은 ApplicationContext 기반 응용 프로그램을 명령 줄에서 실행하고 SO에 대한 여러 의견으로 판단하여 Spring은 MVC 기반 응용 프로그램과 다르게 연결합니다.


1

Bean에 속성을 삽입하는 가장 편리한 방법은 setter 메소드라고 생각합니다.

예:

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;
    }
}

빈 XML 정의 :

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

모든 명명 된 property방법setProperty(value) 대해 호출됩니다.

이 방법은 하나의 구현을 기반으로 둘 이상의 Bean이 필요한 경우 특히 유용합니다.

예를 들어 xml에 하나 이상의 Bean을 정의하면 다음과 같습니다.

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

그런 다음 다음과 같은 코드를 작성하십시오.

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

인쇄합니다

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

따라서 귀하의 경우 다음과 같아야합니다.

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

0

구성에 대한 유연성이 더 필요한 경우 Settings4jPlaceholderConfigurer를 시도하십시오. http://settings4j.sourceforge.net/currentrelease/configSpringPlaceholder.html

우리의 응용 프로그램에서 우리는 다음을 사용합니다.

  • PreProd 및 Prod-System을 구성하기위한 환경 설정
  • "mvn jetty : run"에 대한 환경 설정 및 JNDI 환경 변수 (JNDI가 환경 설정을 겹쳐 씁니다)
  • 단위 테스트의 시스템 속성 (@BeforeClass 주석)

키-값 소스를 먼저 확인하는 기본 순서는 http://settings4j.sourceforge.net/currentrelease/configDefault.html에 설명되어 있습니다.

그것은의 (의 log4j.xml에 대한 정확한)를 settings4j.xml 사용자 정의 할 수 있습니다 클래스 패스.

의견을 보내주세요 : settings4j-user@lists.sourceforge.net

친절한 인사로,
Harald


-1

Spring의 "PropertyPlaceholderConfigurer"클래스 사용

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> 

특성 파일

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.