Using Constructor Arguments
Constructor arguments can be defined using parameters to each method that reside between the class of the bean and the last closure:
bb.beans {
exampleBean(MyExampleBean, "firstArgument", 2) {
someProperty = [1,2,3]
}
}
Configuring the BeanDefinition (Using factory methods)
The first argument to the closure is a reference to the bean configuration instance, which you can use to configure factory methods and invoke any method on the
AbstractBeanDefinition class:
bb.beans {
exampleBean(MyExampleBean) { bean ->
bean.factoryMethod = "getInstance"
bean.singleton = false
someProperty = [1,2,3]
}
}
As an alternative you can also use the return value of the bean defining method to configure the bean:
bb.beans {
def example = exampleBean(MyExampleBean) {
someProperty = [1,2,3]
}
example.factoryMethod = "getInstance"
}
Using Factory beans
Spring defines the concept of factory beans and often a bean is created not from a class, but from one of these factories. In this case the bean has no class and instead you must pass the name of the factory bean to the bean:
bb.beans {
myFactory(ExampleFactoryBean) {
someProperty = [1,2,3]
}
myBean(myFactory) {
name = "blah"
}
}
Note in the example above instead of a class we pass a reference to the
myFactory
bean into the bean defining method. Another common task is provide the name of the factory method to call on the factory bean. This can be done using Groovy's named parameter syntax:
bb.beans {
myFactory(ExampleFactoryBean) {
someProperty = [1,2,3]
}
myBean(myFactory:"getInstance") {
name = "blah"
}
}
Here the
getInstance
method on the
ExampleFactoryBean
bean will be called in order to create the
myBean
bean.
Creating Bean References at Runtime
Sometimes you don't know the name of the bean to be created until runtime. In this case you can use a string interpolation to invoke a bean defining method dynamically:
def beanName = "example"
bb.beans {
"${beanName}Bean"(MyExampleBean) {
someProperty = [1,2,3]
}
}
In this case the
beanName
variable defined earlier is used when invoking a bean defining method.
Furthermore, because sometimes bean names are not known until runtime you may need to reference them by name when wiring together other beans. In this case using the
ref
method:
def beanName = "example"
bb.beans {
"${beanName}Bean"(MyExampleBean) {
someProperty = [1,2,3]
}
anotherBean(AnotherBean) {
example = ref("${beanName}Bean")
}
}
Here the example property of
AnotherBean
is set using a runtime reference to the
exampleBean
. The
ref
method can also be used to refer to beans from a parent
ApplicationContext
that is provided in the constructor of the
BeanBuilder
:
ApplicationContext parent = ...//
der bb = new BeanBuilder(parent)
bb.beans {
anotherBean(AnotherBean) {
example = ref("${beanName}Bean", true)
}
}
Here the second parameter
true
specifies that the reference will look for the bean in the parent context.
Using Anonymous (Inner) Beans
You can use anonymous inner beans by setting a property of the bean to a block that takes an argument that is the bean type:
bb.beans {
marge(Person.class) {
name = "marge"
husband = { Person p ->
name = "homer"
age = 45
props = [overweight:true, height:"1.8m"]
}
children = [bart, lisa]
}
bart(Person) {
name = "Bart"
age = 11
}
lisa(Person) {
name = "Lisa"
age = 9
}
}
In the above example we set the
marge
bean's husband property to a block that creates an inner bean reference. Alternatively if you have a factory bean you can ommit the type and just use passed bean definition instead to setup the factory:
bb.beans {
personFactory(PersonFactory.class)
marge(Person.class) {
name = "marge"
husband = { bean ->
bean.factoryBean = "personFactory"
bean.factoryMethod = "newInstance"
name = "homer"
age = 45
props = [overweight:true, height:"1.8m"]
}
children = [bart, lisa]
}
}
Abstract Beans and Parent Bean Definitions
To create an abstract bean definition define a bean that takes no class:
class HolyGrailQuest {
def start() { println "lets begin" }
}
class KnightOfTheRoundTable {
String name
String leader
KnightOfTheRoundTable(String n) {
this.name = n
}
HolyGrailQuest quest def embarkOnQuest() {
quest.start()
}
}def bb = new grails.spring.BeanBuilder()
bb.beans {
abstractBean {
leader = "Lancelot"
}
…
}
Here we define an abstract bean that sets that has a
leader
property with the value of
"Lancelot"
. Now to use the abstract bean set it as the parent of the child bean:
bb.beans {
…
quest(HolyGrailQuest)
knights(KnightOfTheRoundTable, "Camelot") { bean ->
bean.parent = abstractBean
quest = quest
}
}
When using a parent bean you must set the parent property of the bean before setting any other properties on the bean!
If you want an abstract bean that has a class you can do it this way:
def bb = new grails.spring.BeanBuilder()
bb.beans {
abstractBean(KnightOfTheRoundTable) { bean ->
bean.'abstract' = true
leader = "Lancelot"
}
quest(HolyGrailQuest)
knights("Camelot") { bean ->
bean.parent = abstractBean
quest = quest
}
}
In the above example we create an abstract bean of type
KnightOfTheRoundTable
and use the bean argument to set it to abstract. Later we define a knights bean that has no class, but inherits the class from the parent bean.
Using Spring Namespaces
Since Spring 2.0, users of Spring have been granted easier access to key features via XML namespaces. With BeanBuilder you can use any Spring namespace by first declaring it:
xmlns context:"http://www.springframework.org/schema/context"
And then invoking a method that matches the names of the Spring namespace tag and its associated attributes:
context.'component-scan'( 'base-package' :"my.company.domain" )
You can do some useful things with Spring namespaces, such as looking up a JNDI resource:
xmlns jee:"http://www.springframework.org/schema/jee"jee.'jndi-lookup'(id:"dataSource", 'jndi-name':"java:comp/env/myDataSource")
The example above will create a Spring bean with the identifier of
dataSource
by performing a JNDI lookup on the given JNDI name. With Spring namespaces you also get full access to all of the powerful AOP support in Spring from BeanBuilder. For example given the following two classes:
class Person {
int age;
String name; void birthday() {
++age;
}
}
class BirthdayCardSender {
List peopleSentCards = []
public void onBirthday(Person person) {
peopleSentCards << person
}
}
You can define an AOP aspect that uses a pointcut to detect whenever the
birthday()
method is called:
xmlns aop:"http://www.springframework.org/schema/aop"
fred(Person) {
name = "Fred"
age = 45
}birthdayCardSenderAspect(BirthdayCardSender)aop {
config("proxy-target-class":true) {
aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) {
after method:"onBirthday", pointcut: "execution(void ..Person.birthday()) and this(person)"
}
}
}