Подтвердить что ты не робот

Как программно разрешить компоновщик свойств в Spring

В настоящее время я работаю над веб-приложением на основе Spring 3.1.0.M1, на основе аннотаций, и у меня есть проблема с разрешением заполнителей свойств в одном конкретном месте моего приложения.

Вот история.

1) В моем контексте веб-приложения (загружен DispatcherServlet) у меня есть

MVC-config.xml:

<!-- Handles HTTP GET requests for /resources/version/**  -->
<resources mapping="/${app.resources.path}/**" location="/static/" cache-period="31556926"/> 

...

<!-- Web properties -->
<context:property-placeholder location="
    classpath:app.properties
    "/>

2) Внутри app.properties есть 2 свойства, среди прочих:

app.properties:

# Properties provided (filtered) by Maven itself
app.version: 0.1-SNAPSHOT
...

# Static resources mapping
app.resources.path: resources/${app.version}

3) У меня есть JSP-пользовательский тег в моих шаблонах JSP 2.1. Этот тег отвечает за полное построение пути ресурса в зависимости от настроек среды, версии приложения, Spring выбора темы и т.д. Специальный класс тега расширяет spring: класс реализации URL, поэтому его можно считать обычным тегом URL, но с некоторыми дополнительными знаниями о правильном пути.

Моя проблема заключается в том, что я не могу правильно получить ${app.resources.path} в моей реализации JSP-пользовательского тега. Пользовательские теги JSP управляются контейнером сервлета, а не Spring, и поэтому не участвуют в DI. Поэтому я не могу просто использовать обычный @Value ( "$ {app.resources.path}" ) и автоматически разрешить его с помощью Spring.

У меня есть экземпляр контекста веб-приложения, поэтому я должен программно разрешить свое свойство.

До сих пор я пытался:

ResourceTag.java:

// returns null
PropertyResolver resolver = getRequestContext().getWebApplicationContext().getBean(PropertyResolver.class);
resolver.getProperty("app.resources.path");


// returns null, its the same web context instance (as expected)
PropertyResolver resolver2 = WebApplicationContextUtils.getRequiredWebApplicationContext(pageContext.getServletContext()).getBean(PropertyResolver.class);
resolver2.getProperty("app.resources.path");


// throws NPE, resolver3 is null as StringValueResolver is not bound
StringValueResolver resolver3 = getRequestContext().getWebApplicationContext().getBean(StringValueResolver.class);
resolver3.resolveStringValue("app.resources.path");


// null, since context: property-placeholder does not register itself as PropertySource
Environment env = getRequestContext().getWebApplicationContext().getEnvironment();
env.getProperty("app.resources.path");

Итак, теперь я немного застрял в этом. Я знаю, что способность разрешать мой заполнитель где-то в контексте, я просто не знаю, как правильно это сделать.
Любая помощь или идеи для проверки высоко оценены.

4b9b3361

Ответ 1

Я думаю, вместо того, чтобы сосредоточиться на внутренней работе владельца контекста, вы можете просто определить новую утилиту: свойства, подобные этому:

<util:properties id="appProperties" location="classpath:app.properties" />

и в вашем коде, используйте его следующим образом:

Properties props = appContext.getBean("appProperties", Properties.class);

ИЛИ как это, где вы можете сделать DI:

@Value("#{appProperties['app.resources.path']}")

Ответ 2

Так как Spring 3.0.3 есть EmbeddedValueResolverAware, который будет работать так же, как упоминалось другим сообщением, которое использует вызов appContext.getBeanFactory().resolveEmbeddedValue("${prop}").

Чтобы решить проблему:

  • Сделайте свой класс для внедрения интерфейса EmbeddedValueResolverAware, и вы получите для него распознавание.

  • Затем вы сможете получить свойства, как показано в фрагменте кода:

    String propertyValue = resolver.resolveStringValue("${your.property.name}");
    

Затем ваш bean не должен зависеть от ApplicationContext для получения необходимых вам свойств.

Ответ 3

Начиная с версии 3.0, Spring хранит список String resolver в beanFactory. Вы можете использовать его следующим образом:

String value = appContext.getBeanFactory().resolveEmbeddedValue("${prop}");

В javadoc указан этот метод как для разрешения встроенных значений, таких как атрибуты аннотации, поэтому, возможно, мы обходим его использование, но оно работает.

Ответ 4

Один из вариантов - добавить PropertySource (здесь MapPropertySource для иллюстрации конфигурации в памяти) в ConfigurableEnvironment и попросить его разрешить свойства для вас.

public class Foo {

    @Autowired
    private ConfigurableEnvironment env;

    @PostConstruct
    public void setup() {
        env.getPropertySources()
           .addFirst(new MapPropertySource("my-propertysource", 
               ImmutableMap.<String, Object>of("your.property.name", "the value")));
        env.resolvePlaceholders("your.property.name");
    }
}

Необязательно аннотировать класс Foo с помощью @Configuration, чтобы получить возможность использования программной конфигурации в пользу XML.

Ответ 5

Существует еще одно возможное решение: создать тег-классы @Configurable через AspectJ и включить либо время компиляции, либо время загрузки. Затем я мог бы использовать обычные аннотации Spring @Value в моих пользовательских тегах. Но, действительно, я не хочу настраивать ткацкую инфраструктуру только из-за нескольких классов. Все еще ищет способ разрешить местозаполнитель через ApplicationContext.