From 6deccf123d047b03a228ff1a12649c4936aad1cf Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 17 Jan 2017 15:32:24 +0100 Subject: [PATCH] Reference documentation for Groovy bean definition DSL Issue: SPR-15153 (cherry picked from commit 2047f8d) --- .../groovy/GroovyBeanDefinitionReader.java | 20 ++-- src/asciidoc/core-beans.adoc | 96 ++++++++++++++++++- 2 files changed, 101 insertions(+), 15 deletions(-) diff --git a/spring-beans-groovy/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java b/spring-beans-groovy/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java index bafdd9fb54..657ac3808b 100644 --- a/spring-beans-groovy/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java +++ b/spring-beans-groovy/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -303,7 +303,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp Collection constructorArgs = null; if (!ObjectUtils.isEmpty(args)) { int index = args.length; - Object lastArg = args[index-1]; + Object lastArg = args[index - 1]; if (lastArg instanceof Closure) { callable = (Closure) lastArg; index--; @@ -456,14 +456,14 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp * @return the bean definition wrapper */ private GroovyBeanDefinitionWrapper invokeBeanDefiningMethod(String beanName, Object[] args) { - boolean hasClosureArgument = args[args.length - 1] instanceof Closure; + boolean hasClosureArgument = (args[args.length - 1] instanceof Closure); if (args[0] instanceof Class) { - Class beanClass = (args[0] instanceof Class ? (Class) args[0] : args[0].getClass()); + Class beanClass = (Class) args[0]; if (args.length >= 1) { if (hasClosureArgument) { - if (args.length-1 != 1) { + if (args.length - 1 != 1) { this.currentBeanDefinition = new GroovyBeanDefinitionWrapper( - beanName, beanClass, resolveConstructorArguments(args,1,args.length-1)); + beanName, beanClass, resolveConstructorArguments(args, 1, args.length - 1)); } else { this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, beanClass); @@ -471,7 +471,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp } else { this.currentBeanDefinition = new GroovyBeanDefinitionWrapper( - beanName, beanClass, resolveConstructorArguments(args,1,args.length)); + beanName, beanClass, resolveConstructorArguments(args, 1, args.length)); } } @@ -483,7 +483,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp else if (args[0] instanceof Map) { // named constructor arguments if (args.length > 1 && args[1] instanceof Class) { - List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length-1 : args.length); + List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length); this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class)args[1], constructorArgs); Map namedArgs = (Map)args[0]; for (Object o : namedArgs.keySet()) { @@ -519,12 +519,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp this.currentBeanDefinition.getBeanDefinition().setAbstract(true); } else { - List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length-1 : args.length); + List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length); currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, null, constructorArgs); } if (hasClosureArgument) { - Closure callable = (Closure)args[args.length-1]; + Closure callable = (Closure) args[args.length - 1]; callable.setDelegate(this); callable.setResolveStrategy(Closure.DELEGATE_FIRST); callable.call(new Object[]{currentBeanDefinition}); diff --git a/src/asciidoc/core-beans.adoc b/src/asciidoc/core-beans.adoc index 129aa3ce3b..3eef906efc 100644 --- a/src/asciidoc/core-beans.adoc +++ b/src/asciidoc/core-beans.adoc @@ -4,6 +4,7 @@ [[beans-introduction]] == Introduction to the Spring IoC container and beans + This chapter covers the Spring Framework implementation of the Inversion of Control (IoC) footnote:[See pass:specialcharacters,macros[<>] ] principle. IoC is also known as __dependency injection__ (DI). It is a process whereby objects define @@ -44,6 +45,7 @@ among them, are reflected in the __configuration metadata__ used by a container. [[beans-basics]] == Container overview + The interface `org.springframework.context.ApplicationContext` represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the aforementioned beans. The container gets its instructions on what objects to @@ -290,6 +292,44 @@ locations, for example, through "${...}" placeholders that are resolved against system properties at runtime. ==== +The import directive is a feature provided by the beans namespace itself. Further +configuration features beyond plain bean definitions are available in a selection +of XML namespaces provided by Spring, e.g. the "context" and the "util" namespace. + + +[[groovy-bean-definition-dsl]] +==== The Groovy Bean Definition DSL + +As a further example for externalized configuration metadata, bean definitions can also +be expressed in Spring's Groovy Bean Definition DSL, as known from the Grails framework. +Typically, such configuration will live in a ".groovy" file with a structure as follows: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + beans { + dataSource(BasicDataSource) { + driverClassName = "org.hsqldb.jdbcDriver" + url = "jdbc:hsqldb:mem:grailsDB" + username = "sa" + password = "" + settings = [mynew:"setting"] + } + sessionFactory(SessionFactory) { + dataSource = dataSource + } + myService(MyService) { + nestedBean = { AnotherBean bean -> + dataSource = dataSource + } + } + } +---- + +This configuration style is largely equivalent to XML bean definitions and even +supports Spring's XML configuration namespaces. It also allows for importing XML +bean definition files through an "importBeans" directive. + [[beans-factory-client]] @@ -305,8 +345,7 @@ The `ApplicationContext` enables you to read bean definitions and access them as [subs="verbatim,quotes"] ---- // create and configure beans - ApplicationContext context = - new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"}); + ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml"); // retrieve configured instance PetStoreService service = context.getBean("petStore", PetStoreService.class); @@ -315,12 +354,46 @@ The `ApplicationContext` enables you to read bean definitions and access them as List userList = service.getUsernameList(); ---- -You use `getBean()` to retrieve instances of your beans. The `ApplicationContext` +With Groovy configuration, bootstrapping looks very similar, just a different context +implementation class which is Groovy-aware (but also understands XML bean definitions): + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy"); +---- + +The most flexible variant is `GenericApplicationContext` in combination with reader +delegates, e.g. with `XmlBeanDefinitionReader` for XML files: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + GenericApplicationContext context = new GenericApplicationContext(); + new XmlBeanDefinitionReader(ctx).loadBeanDefinitions("services.xml", "daos.xml"); + context.refresh(); +---- + +Or with `GroovyBeanDefinitionReader` for Groovy files: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + GenericApplicationContext context = new GenericApplicationContext(); + new GroovyBeanDefinitionReader(ctx).loadBeanDefinitions("services.groovy", "daos.groovy"); + context.refresh(); +---- + +Such reader delegates can be mixed and matched on the same `ApplicationContext`, +reading bean definitions from diverse configuration sources, if desired. + +You can then use `getBean` to retrieve instances of your beans. The `ApplicationContext` interface has a few other methods for retrieving beans, but ideally your application code should never use them. Indeed, your application code should have no calls to the `getBean()` method at all, and thus no dependency on Spring APIs at all. For example, -Spring's integration with web frameworks provides for dependency injection for various -web framework classes such as controllers and JSF-managed beans. +Spring's integration with web frameworks provides dependency injection for various web +framework components such as controllers and JSF-managed beans, allowing you to declare +a dependency on a specific bean through metadata (e.g. an autowiring annotation). @@ -497,6 +570,8 @@ If you are using Java-configuration, the `@Bean` annotation can be used to provi see <> for details. **** + + [[beans-factory-class]] === Instantiating beans @@ -7131,6 +7206,7 @@ method that returns `true` or `false`. For example, here is the actual See the {api-spring-framework}/context/annotation/Conditional.html[ `@Conditional` javadocs] for more detail. + [[beans-java-combining]] ==== Combining Java and XML configuration @@ -7403,6 +7479,7 @@ certain profile of bean definitions in situation A, and a different profile in situation B. Let's first see how we can update our configuration to reflect this need. + [[beans-definition-profiles-java]] ==== @Profile @@ -7572,6 +7649,7 @@ The `spring-bean.xsd` has been constrained to allow such elements only as the last ones in the file. This should help provide flexibility without incurring clutter in the XML files. + [[beans-definition-profiles-enable]] ==== Activating a profile @@ -7618,6 +7696,7 @@ Declaratively, `spring.profiles.active` may accept a comma-separated list of pro -Dspring.profiles.active="profile1,profile2" ---- + [[beans-definition-profiles-default]] ==== Default profile @@ -7648,6 +7727,8 @@ profile is enabled, the _default_ profile will not apply. The name of the default profile can be changed using `setDefaultProfiles()` on the `Environment` or declaratively using the `spring.profiles.default` property. + + [[beans-property-source-abstraction]] === PropertySource abstraction @@ -7725,6 +7806,8 @@ any `foo` property in any other `PropertySource`. The API exposes a number of methods that allow for precise manipulation of the set of property sources. + + === @PropertySource The {api-spring-framework}/context/annotation/PropertySource.html[`@PropertySource`] @@ -7782,6 +7865,7 @@ as a default. If no default is specified and a property cannot be resolved, an `IllegalArgumentException` will be thrown. + === Placeholder resolution in statements Historically, the value of placeholders in elements could be resolved only against @@ -7804,6 +7888,8 @@ property is defined, as long as it is available in the `Environment`: ---- + + [[context-load-time-weaver]] == Registering a LoadTimeWeaver