Поддержка Spring для языков сценариев позволяет вам расширять ваши Java-приложения с помощью bean-компонентов, определенных на языке сценариев, например Groovy. Контейнер Spring прозрачно создает экземпляры, настраивает и устанавливает зависимости между этими поддерживаемыми языками. Бины, определенные в языке сценариев, таком как Groovy, имеют ряд полезных преимуществ, таких как возможность «обновлять» уже загруженные классы Groovy при изменении исходных файлов.
Groovy позволяет писать как классы, так и скриптлеты. Например, ниже приведен отличный скриптлет:
println 'Hello' // Groovy will create a full class for me behind the scenes
Эта статья посвящена тому, как настраивать и использовать такие скриптлеты в Spring из-за их различий с обычными классами Groovy. Он не охватывает более распространенный случай настройки обычных классов Groovy. Для ознакомления с основами поддержки Spring для языков сценариев и интеграции Groovy / Spring, пожалуйста, прочитайте Динамические языковые компоненты в Spring и Spring: Поддержка динамических языков .
Groovy: Скриплет против класса
Давайте сначала определим, что мы имеем в виду под скриптом Groovy. Вот скриптлет (определенный в файле Manners.groovy):
package groovyspring.scriptuser1 = new User(name: ‘Mr X’)user2 = new User(name: ‘Mr Y’)sayHiAndBye()def sayHiAndBye() {println “Hi, ${user1.name}”println “Bye, ${user2.name}”}
Вот эквивалентный класс:
package groovyspring.scriptclass Manners { def user1, user2 static main(args) { def m = new Manners() m.user1 = new User(name: ‘Mr X’) m.user2 = new User(name: ‘Mr Y’) m.sayHiAndBye() } def sayHiAndBye() { println "Hi, ${user1.name}" println "Bye, ${user2.name}" } }
Приведенный выше код подчеркивает некоторые различия между скриптлетом и классом:
- Скриплет поддерживается Binding и не должен явно объявлять переменные уровня экземпляра. При первом использовании переменные добавляются в привязку скрипта. Одним из важных отличий здесь является то, что Groovy не создает никаких методов получения / установки для таких переменных привязки. Spring-поиск для установщиков JavaBean завершится неудачно для привязки-свойств-свойств, когда он попытается установить зависимости.
- Groovy создает класс и main () для сценария за кулисами. Все операторы, которых нет ни в одном методе, (примерно) становятся частью main (), сгенерированного Groovy для скриптлета.
Весенний пример
Этот раздел добавляет Spring к примеру и показывает, как скрипты Groovy и Java-бины могут быть определены и подключены вместе.
Вот простой Java-бин, который понадобится нашему скриптлету в качестве зависимости:
package groovyspring.model;public class User { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }}
Вот наш скрипт Groovy, которому нужно вставить некоторые зависимости, которые он явно хочет найти, используя контекстную ссылку Spring:
package groovyspring.scriptimport groovyspring.model.Userdef sayHiAndBye() { println "Hi, ${user1.name}, ${user2.name}" println "Bye, ${springAppContext.getBean('user3').name}"}void setUser2(User user2) { binding.setVariable('user2', user2)}this // the scriplet needs to explicitly return a reference to itself to Spring
Этот скриптлет требует от Spring следующих зависимостей: user1, user2, user3 и springAppContext.
Есть несколько вариантов получения зависимостей из Spring в ваших скриптлетах:
- Использование явных методов получения / установки: когда Spring пытается внедрить зависимость, он использует отражение Java для поиска установщика JavaBean. Итак, простой вариант — предоставить в вашем скриптлете явные методы установки, а затем просто использовать нотацию <lang: property> для внедрения зависимости в ваш базовый bean-компонент.
- Использование универсального установщика GroovyObject: Все скрипты Groovy реализуют интерфейс GroovyObject, который предоставляет универсальный метод setProperty (). Его реализация помещает свойство в привязку скрипта. Здесь мы используем интерфейс GroovyObjectCustomizer Spring, чтобы помочь нам вызывать универсальный setter setProperty () вместо отдельных установщиков свойств, которые могут отсутствовать в скриптлетах, если не указано явно.
Вот наша реализация GroovyObjectCustomizer:
package groovyspring.script;import groovy.lang.GroovyObject;import org.springframework.context.*;import org.springframework.scripting.groovy.GroovyObjectCustomizer;import org.springframework.beans.BeansException;import java.util.List;public class ScriptletCustomizer implements GroovyObjectCustomizer, ApplicationContextAware { String[] bindingVars = null; ApplicationContext applicationContext = null; public void customize(GroovyObject groovyObject) { groovyObject.setProperty("springAppContext", applicationContext); for(String bindingVar : bindingVars) { groovyObject.setProperty(bindingVar, applicationContext.getBean(bindingVar)); } } public void setBindingVars(String[] bindingVars) { this.bindingVars = bindingVars; } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}
Что делает наш настройщик, так это то, что он помещает все зависимости скрипта в свою привязку с помощью GroovyObject # setProperty () и таким образом делает их доступными для обычного использования. Кроме того, он также делает контекст приложения доступным для нашего скриптлета с именем «springAppContext», чтобы он мог получать любые другие bean-компоненты из нужного им контекста.
Наконец, вот конфигурация Spring, которая связывает все эти бины Spring / Java вместе:
<?xml version="1.0" encoding="utf-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd"> <lang:groovy id="scriptlet1" script-source="classpath:groovyspring/script/Scriptlet1.groovy" customizer-ref="scripletCustomizer"> <lang:property name="user2" ref="user2"/> </lang:groovy> <bean id="user1" class="groovyspring.model.User"> <property name = "name" value = "Mr X"/> </bean> <bean id="user2" class="groovyspring.model.User"> <property name = "name" value = "Mr Y"/> </bean> <bean id="user3" class="groovyspring.model.User"> <property name = "name" value = "Mr Z"/> </bean> <bean id="scripletCustomizer" class="groovyspring.script.ScriptletCustomizer"> <property name="bindingVars" value="user1"/> </bean></beans>
Как можно видеть здесь, зависимость ‘user2’ вводится в скриптлет с использованием его явного набора setTser2 () и нотации <lang: property>, тогда как зависимость ‘user1’ вводится в скриптлет через наш собственный ScriptletCustomizer. ScriptletCustomizer внедряет ‘user1’ в скриптлет с помощью универсального метода setProperty () из groovy, а также вставляет контекстную ссылку Spring ‘springAppContext’, чтобы наш скриптлет мог замыкать любые дополнительные компоненты, которые ему нужны.
На этом статья заканчивается. Использование Binding скриптами groovy отличает их в том, что касается их интеграции, поскольку классы, сгенерированные Groovy для скриптов, не имеют никаких установщиков JavaBean для привязки переменных, и поэтому для настройки их зависимостей необходимы специальные средства.
Код для этой статьи можно скачать здесь .