Статьи

Spring EL — Конфигурация среды и чистый XML

Я хотел бы поделиться советами Spring EL (SpEL), которые я использовал для 1) дружественной аннотации, модульной конфигурации среды 2) более чистой конфигурации XML. Это далеко не исчерпывающий учебник, просто пара полезных советов.

Цель

Я использовал аннотации Spring 2.5, когда они только появились, но мне было сложно понять, как использовать возможности внешней настройки Spring в системе с аннотациями. Это был не только я; Spring 2.5 оставил виртуальную пустоту между разработкой на основе аннотаций и этой превосходной внешней конфигурацией. Весенние люди поняли это и создали SpEL, чтобы заполнить этот пробел. За последние пару недель я смог использовать SpEL для настройки своего приложения. Я знал, что SpEL был хорош, но до моего первого реального использования я не понимал, насколько он хорош.

Помимо возможности добавления конкретной конфигурации среды в аннотации, я обнаружил некоторые дополнительные преимущества:

  1. более богатая опция конфигурации на основе объектов (вместо конфигурации на основе строк)
  2. уменьшенный размер файла XML.

Экологические проблемы

Как вы вводите специфические для среды значения в мире, управляемом аннотациями? Нам нужно было настроить специфичные для среды URL, другие строки и некоторые прокси в моих контроллерах и Daos. Мы создали файл «spring-environment.xml», который содержал все эти вещи, и позволили изменять этот файл для каждой среды. Вот как выглядит наша XML-конфигурация:

<util:map id="foo">
  <entry key="urlTemplate">
     <value>http://somwhere.com/foo?bar=baz&amp;bap={replaceMe}</value>
  </entry>
  <entry key="proxy" value-ref="proxy1" />
</util:map>
  

Аннотированный код, который использовал его, выглядел примерно так:

@Repository
public class HttpFooDAO extends HttpRetriever implements FooDao {

  @Autowired
  public HttpFooDAO(
    @Value("#{foo.urlTemplate"} String urlTemplate,
    @Value("#{foo.proxy}") Proxy proxy )
      super(urlTemplate, proxy);
  )

  public Foo getFoo(String me){
    String s = super.retrieve(me);
    // custom parser
  }
}

Модульность

Зачем использовать <util: map>?

Изначально мы думали о создании констант и отдельных бинов. Мы решили использовать <util: map> по двум причинам:

  1. Spring не реализует константы как первоклассные граждане.
  2. <util: map> позволил нам сконфигурировать вопросы конфигурации

До весны 3.0 я работал над проектами, в которых у нас были десятки строк конфигурации с кажущимися случайными проблемами. Мы могли бы создать несколько файлов свойств, но этот вариант был более сложным для оперативных людей. Внутрифайловое логическое разбиение стало возможным благодаря # комментариям и тщательному управлению, но для этого требовалось, чтобы все участники долгосрочного проекта придерживались соглашений, основанных на системе чести. Другими словами, со временем конвенции отошли на второй план.

В Spring 3.0 парадигма <util: map> позволила нам спроектировать модульность конфигурации в одном файле. Надеемся, что наш проект будет реализован через два года, и инженеры, которые улучшат свою систему, будут более склонны к более четким соглашениям.

Один файл на среду развертывания

We also built a number of other files to support production/qa/other environments. We had a simple shell script + maven profile to copy the right environment file into place before creating a .war file. (Note: It would have been nice to use maven alone without the shell script, but we ran into some problems moving files around with maven).

Object-based configuration

Did you notice that I slipped in a value-ref=»proxy1″? Using a Spring XML file anabled me to create environment specific beans rather than a collection environment specific String properties. That higher level configuration capability gave the flexibility to think of configuration in terms of objects rather than in terms of Strings. Grails gives that capability out of the box, and I built a Grails system last yea… object-based configuration simply feels more natural to me at this point.

Configuration simplification

Spring EL had another great benefit. You can build simple POJOs through SpEL which allow you to bypass icky XML. For example, that value-ref=»proxy1″ that I showed above had 13 lines of XML code without EL, compared with 4 lines of XML with EL.

Here’s what building a java.net Proxy looked like pre-EL:

  <bean id="myProxy" class="java.net.Proxy">
    <constructor-arg>
      <bean class="java.net.Proxy$Type" factory-method="valueOf">
         <constructor-arg value="HTTP" />
      </bean>
    </construcor-arg>
    <constructor-arg>
      <bean class="java.net.InetSocketAddress">
         <constructor-arg value="proxy.mycompany.com" />
         <constructor-arg value="1234" />
       </bean>
    </constructor-arg>
  </bean>

That icky XML was one reason why so many folks simply hated Spring. I didn’t like it either, but I lived with it until now. There are some EL tricks that allowed the following «simpler» configuration:

  <bean id="myProxy" class="java.net.Proxy">
    <constructor-arg value="#{T(java.net.Proxy$Type).HTTP} />
    <constructor-arg value="#{new java.net.InetSocketAddress('proxy.mycompany.com', 1234)}" />
  </bean>

That’s still not as short as plain old java code (or a groovy script), but it’s a lot better than the original XML. The syntax takes a bit of getting used to, but it allows me to have a clearer picture of how my application is configured by:

  1. providing a more concise picture of what this specific bean does
  2. allowing me to see more of my configuration on a single page, so that I can get a quicker holistic view of my application’s configuration.

Conclusion

I’m really happy with the incremental steps that Spring has taken over the years at improving configuration. I hope that these little tips helped. If you have more EL or configuration niceties, please let me know!

From http://www.jroller.com/Solomon/entry/spring_el_environmental_configuration_and