提交 8d6406bb 编写于 作者: J Juergen Hoeller

Groovy-based bean definitions

Formerly known as the Grails BeanBuilder, now in Spring proper. Based on https://github.com/spring-projects/spring-framework/pull/355 but heavily refactored and restructured.

Issue: SPR-7123
上级 bb8cf277
......@@ -13,6 +13,7 @@ configure(allprojects) { project ->
version = qualifyVersionIfNecessary(version)
ext.aspectjVersion = "1.8.0.M1"
ext.groovyVersion = "1.8.9"
ext.hsqldbVersion = "1.8.0.10"
ext.junitVersion = "4.11"
ext.slf4jVersion = "1.6.1"
......@@ -20,6 +21,7 @@ configure(allprojects) { project ->
apply plugin: "propdeps"
apply plugin: "java"
apply plugin: 'groovy'
apply plugin: "test-source-set-dependencies"
apply from: "${gradleScriptDir}/ide.gradle"
......@@ -50,9 +52,13 @@ configure(allprojects) { project ->
}
compileTestJava {
sourceCompatibility=1.8
targetCompatibility=1.8
compileTestJava.options.compilerArgs += "-parameters"
sourceCompatibility=1.7
targetCompatibility=1.7
}
compileGroovy {
sourceCompatibility=1.6
targetCompatibility=1.6
}
sourceSets.test.resources.srcDirs = ["src/test/resources", "src/test/java"]
......@@ -68,9 +74,9 @@ configure(allprojects) { project ->
repositories {
maven { url "http://repo.spring.io/libs-release" }
maven { url "http://repo.spring.io/milestone" } // for AspectJ 1.8.0.M1
maven { url "https://repository.apache.org/content/repositories/releases" } // tomcat 8 RC3
maven { url "https://repository.apache.org/content/repositories/snapshots" } // tomcat-websocket-* snapshots
maven { url "https://maven.java.net/content/repositories/releases" } // javax.websocket, tyrus
maven { url "https://repository.apache.org/content/repositories/releases" } // tomcat 8 RC3
maven { url "https://repository.apache.org/content/repositories/snapshots" } // tomcat-websocket-* snapshots
maven { url "https://maven.java.net/content/repositories/releases" } // javax.websocket, tyrus
}
dependencies {
......@@ -153,7 +159,6 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
project("spring-build-src") {
description = "Exposes gradle buildSrc for IDE support"
apply plugin: "groovy"
dependencies {
compile gradleApi()
......@@ -249,6 +254,12 @@ project("spring-core") {
include "org/springframework/objenesis/**"
}
}
compileTestJava {
sourceCompatibility=1.8
targetCompatibility=1.8
compileTestJava.options.compilerArgs += "-parameters"
}
}
project("spring-beans") {
......@@ -263,6 +274,26 @@ project("spring-beans") {
}
}
project('spring-beans-groovy') {
description 'Groovy Bean Definitions'
merge.into = project(":spring-beans")
dependencies {
compile(project(":spring-core"))
compile "org.codehaus.groovy:groovy-all:${groovyVersion}"
}
// this module's Java and Groovy sources need to be compiled together
compileJava.enabled=false
sourceSets {
main {
groovy {
srcDir 'src/main/java'
}
}
}
}
project("spring-aop") {
description = "Spring AOP"
......@@ -322,7 +353,7 @@ project("spring-context") {
optional("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
optional("org.eclipse.persistence:javax.persistence:2.0.0")
optional("org.beanshell:bsh:2.0b4")
optional("org.codehaus.groovy:groovy-all:1.8.9")
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
optional("org.jruby:jruby:1.7.2")
optional("joda-time:joda-time:2.2")
optional("org.slf4j:slf4j-api:${slf4jVersion}")
......@@ -827,7 +858,6 @@ configure(rootProject) {
description = "Spring Framework"
apply plugin: "docbook-reference"
apply plugin: "groovy"
// apply plugin: "detect-split-packages"
apply from: "${gradleScriptDir}/jdiff.gradle"
......
......@@ -3,6 +3,7 @@ rootProject.name = "spring"
include "spring-aop"
include "spring-aspects"
include "spring-beans"
include "spring-beans-groovy"
include "spring-context"
include "spring-context-support"
include "spring-core"
......
/*
* Copyright 2002-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.groovy
import groovy.xml.StreamingMarkupBuilder
import org.springframework.beans.factory.config.BeanDefinitionHolder
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate
import org.w3c.dom.Element
/**
* Used by GroovyBeanDefinitionReader to read a Spring XML namespace expression
* in the Groovy DSL.
*
* @author Jeff Brown
* @author Juergen Hoeller
* @since 4.0
*/
@groovy.transform.PackageScope
class GroovyDynamicElementReader extends GroovyObjectSupport {
private final String rootNamespace
private final Map<String, String> xmlNamespaces
private final BeanDefinitionParserDelegate delegate
private final GroovyBeanDefinitionWrapper beanDefinition
protected final boolean decorating;
private boolean callAfterInvocation = true
public GroovyDynamicElementReader(String namespace, Map<String, String> namespaceMap,
BeanDefinitionParserDelegate delegate, GroovyBeanDefinitionWrapper beanDefinition, boolean decorating) {
super();
this.rootNamespace = namespace
this.xmlNamespaces = namespaceMap
this.delegate = delegate
this.beanDefinition = beanDefinition;
this.decorating = decorating;
}
@Override
public Object invokeMethod(String name, Object args) {
if (name.equals("doCall")) {
def callable = args[0]
callable.resolveStrategy = Closure.DELEGATE_FIRST
callable.delegate = this
def result = callable.call()
if (this.callAfterInvocation) {
afterInvocation()
this.callAfterInvocation = false
}
return result
}
else {
StreamingMarkupBuilder builder = new StreamingMarkupBuilder();
def myNamespace = this.rootNamespace
def myNamespaces = this.xmlNamespaces
def callable = {
for (namespace in myNamespaces) {
mkp.declareNamespace([(namespace.key):namespace.value])
}
if (args && (args[-1] instanceof Closure)) {
args[-1].resolveStrategy = Closure.DELEGATE_FIRST
args[-1].delegate = builder
}
delegate."$myNamespace"."$name"(*args)
}
callable.resolveStrategy = Closure.DELEGATE_FIRST
callable.delegate = builder
def writable = builder.bind(callable)
def sw = new StringWriter()
writable.writeTo(sw)
Element element = this.delegate.readerContext.readDocumentFromString(sw.toString()).documentElement
this.delegate.initDefaults(element)
if (this.decorating) {
BeanDefinitionHolder holder = this.beanDefinition.beanDefinitionHolder;
holder = this.delegate.decorateIfRequired(element, holder, null)
this.beanDefinition.setBeanDefinitionHolder(holder)
}
else {
def beanDefinition = this.delegate.parseCustomElement(element)
if (beanDefinition) {
this.beanDefinition.setBeanDefinition(beanDefinition)
}
}
if (this.callAfterInvocation) {
afterInvocation()
this.callAfterInvocation = false
}
return element
}
}
/**
* Hook that subclass or anonymous classes can overwrite to implement custom behavior
* after invocation completes.
*/
protected void afterInvocation() {
// NOOP
}
}
/*
* Copyright 2002-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.groovy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import groovy.lang.GroovyObjectSupport;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.util.CollectionUtils;
/**
* Internal wrapper for a Spring BeanDefinition, allowing for Groovy-style
* property access within a {@link GroovyBeanDefinitionReader} closure.
*
* @author Jeff Brown
* @author Juergen Hoeller
* @since 4.0
*/
class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
private static final String PARENT = "parent";
private static final String AUTOWIRE = "autowire";
private static final String CONSTRUCTOR_ARGS = "constructorArgs";
private static final String FACTORY_BEAN = "factoryBean";
private static final String FACTORY_METHOD = "factoryMethod";
private static final String INIT_METHOD = "initMethod";
private static final String DESTROY_METHOD = "destroyMethod";
private static final String SINGLETON = "singleton";
private static final List<String> dynamicProperties = new ArrayList<String>(8);
static {
dynamicProperties.add(PARENT);
dynamicProperties.add(AUTOWIRE);
dynamicProperties.add(CONSTRUCTOR_ARGS);
dynamicProperties.add(FACTORY_BEAN);
dynamicProperties.add(FACTORY_METHOD);
dynamicProperties.add(INIT_METHOD);
dynamicProperties.add(DESTROY_METHOD);
dynamicProperties.add(SINGLETON);
}
private String beanName;
private Class<?> clazz;
private Collection<?> constructorArgs;
private AbstractBeanDefinition definition;
private BeanWrapper definitionWrapper;
private String parentName;
public GroovyBeanDefinitionWrapper(String beanName) {
this.beanName = beanName;
}
public GroovyBeanDefinitionWrapper(String beanName, Class<?> clazz) {
this.beanName = beanName;
this.clazz = clazz;
}
public GroovyBeanDefinitionWrapper(String beanName, Class<?> clazz, Collection<?> constructorArgs) {
this.beanName = beanName;
this.clazz = clazz;
this.constructorArgs = constructorArgs;
}
public String getBeanName() {
return this.beanName;
}
public void setBeanDefinition(AbstractBeanDefinition definition) {
this.definition = definition;
}
public AbstractBeanDefinition getBeanDefinition() {
if (this.definition == null) {
this.definition = createBeanDefinition();
}
return this.definition;
}
protected AbstractBeanDefinition createBeanDefinition() {
AbstractBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(this.clazz);
if (!CollectionUtils.isEmpty(this.constructorArgs)) {
ConstructorArgumentValues cav = new ConstructorArgumentValues();
for (Object constructorArg : this.constructorArgs) {
cav.addGenericArgumentValue(constructorArg);
}
bd.setConstructorArgumentValues(cav);
}
if (this.parentName != null) {
bd.setParentName(this.parentName);
}
this.definitionWrapper = new BeanWrapperImpl(bd);
return bd;
}
public void setBeanDefinitionHolder(BeanDefinitionHolder holder) {
this.definition = (AbstractBeanDefinition) holder.getBeanDefinition();
this.beanName = holder.getBeanName();
}
public BeanDefinitionHolder getBeanDefinitionHolder() {
return new BeanDefinitionHolder(getBeanDefinition(), getBeanName());
}
public void setParent(Object obj) {
if (obj == null) {
throw new IllegalArgumentException("Parent bean cannot be set to a null runtime bean reference!");
}
if (obj instanceof String) {
this.parentName = (String) obj;
}
else if (obj instanceof RuntimeBeanReference) {
this.parentName = ((RuntimeBeanReference) obj).getBeanName();
}
else if (obj instanceof GroovyBeanDefinitionWrapper) {
this.parentName = ((GroovyBeanDefinitionWrapper) obj).getBeanName();
}
getBeanDefinition().setParentName(this.parentName);
getBeanDefinition().setAbstract(false);
}
public GroovyBeanDefinitionWrapper addProperty(String propertyName, Object propertyValue) {
if (propertyValue instanceof GroovyBeanDefinitionWrapper) {
propertyValue = ((GroovyBeanDefinitionWrapper) propertyValue).getBeanDefinition();
}
getBeanDefinition().getPropertyValues().add(propertyName, propertyValue);
return this;
}
public Object getProperty(String property) {
if (this.definitionWrapper.isReadableProperty(property)) {
return this.definitionWrapper.getPropertyValue(property);
}
else if (dynamicProperties.contains(property)) {
return null;
}
return super.getProperty(property);
}
public void setProperty(String property, Object newValue) {
if (PARENT.equals(property)) {
setParent(newValue);
}
else {
AbstractBeanDefinition bd = getBeanDefinition();
if (AUTOWIRE.equals(property)) {
if ("byName".equals(newValue)) {
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
}
else if ("byType".equals(newValue)) {
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
}
else if ("constructor".equals(newValue)) {
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
}
else if (Boolean.TRUE.equals(newValue)) {
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
}
}
// constructorArgs
else if (CONSTRUCTOR_ARGS.equals(property) && newValue instanceof List) {
ConstructorArgumentValues cav = new ConstructorArgumentValues();
List args = (List) newValue;
for (Object arg : args) {
cav.addGenericArgumentValue(arg);
}
bd.setConstructorArgumentValues(cav);
}
// factoryBean
else if (FACTORY_BEAN.equals(property)) {
if (newValue != null) {
bd.setFactoryBeanName(newValue.toString());
}
}
// factoryMethod
else if (FACTORY_METHOD.equals(property)) {
if (newValue != null)
bd.setFactoryMethodName(newValue.toString());
}
// initMethod
else if (INIT_METHOD.equals(property)) {
if (newValue != null) {
bd.setInitMethodName(newValue.toString());
}
}
// destroyMethod
else if (DESTROY_METHOD.equals(property)) {
if (newValue != null) {
bd.setDestroyMethodName(newValue.toString());
}
}
// singleton property
else if (SINGLETON.equals(property)) {
bd.setScope(Boolean.TRUE.equals(newValue) ?
BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE);
}
else if (this.definitionWrapper.isWritableProperty(property)) {
this.definitionWrapper.setPropertyValue(property, newValue);
}
else {
super.setProperty(property, newValue);
}
}
}
}
/**
*
* Support package for Groovy-based bean definitions.
*
*/
package org.springframework.beans.factory.groovy;
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -259,6 +259,18 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
return null;
}
/**
* Get the raw property value, if any.
* @param propertyName the name to search for
* @return the raw property value, or {@code null}
* @see #getPropertyValue(String)
* @see PropertyValue#getValue()
*/
public Object get(String propertyName) {
PropertyValue pv = getPropertyValue(propertyName);
return (pv != null ? pv.getValue() : null);
}
@Override
public PropertyValues changesSince(PropertyValues old) {
MutablePropertyValues changes = new MutablePropertyValues();
......
......@@ -324,6 +324,13 @@ public class BeanDefinitionParserDelegate {
}
/**
* Initialize the default settings assuming a {@code null} parent delegate.
*/
public void initDefaults(Element root) {
initDefaults(root, null);
}
/**
* Initialize the default lazy-init, autowire, dependency check settings,
* init-method, destroy-method and merge settings. Support nested 'beans'
......@@ -337,16 +344,6 @@ public class BeanDefinitionParserDelegate {
this.readerContext.fireDefaultsRegistered(this.defaults);
}
/**
* Initialize the default settings assuming a {@code null} parent delegate.
* @deprecated in Spring 3.1 in favor of
* {@link #initDefaults(Element, BeanDefinitionParserDelegate)}
*/
@Deprecated
public void initDefaults(Element root) {
initDefaults(root, null);
}
/**
* Populate the given DocumentDefaultsDefinition instance with the default lazy-init,
* autowire, dependency check settings, init-method, destroy-method and merge settings.
......@@ -1454,7 +1451,7 @@ public class BeanDefinitionParserDelegate {
return finalDefinition;
}
private BeanDefinitionHolder decorateIfRequired(
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(node);
......
......@@ -135,7 +135,7 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createHelper(this.readerContext, root, parent);
this.delegate = createDelegate(this.readerContext, root, parent);
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
......@@ -144,10 +144,10 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
this.delegate = parent;
}
protected BeanDefinitionParserDelegate createHelper(
protected BeanDefinitionParserDelegate createDelegate(
XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, environment);
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, this.environment);
delegate.initDefaults(root, parentDelegate);
return delegate;
}
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -381,13 +381,13 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
* @param resource the resource descriptor for the XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
* @see #doLoadDocument
* @see #registerBeanDefinitions
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource);
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
......@@ -415,6 +415,20 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
}
}
/**
* Actually load the specified document using the configured DocumentLoader.
* @param inputSource the SAX InputSource to read from
* @param resource the resource descriptor for the XML file
* @return the DOM Document
* @throws Exception when thrown from the DocumentLoader
* @see #setDocumentLoader
* @see DocumentLoader#loadDocument
*/
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
/**
* Gets the validation mode for the specified {@link Resource}. If no explicit
......@@ -508,12 +522,20 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
/**
* Create the {@link XmlReaderContext} to pass over to the document reader.
*/
protected XmlReaderContext createReaderContext(Resource resource) {
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
/**
* Lazily create a default NamespaceHandlerResolver, if not set before.
* @see #createDefaultNamespaceHandlerResolver()
*/
public NamespaceHandlerResolver getNamespaceHandlerResolver() {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, this.namespaceHandlerResolver);
return this.namespaceHandlerResolver;
}
/**
......
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2013 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.
......@@ -16,6 +16,12 @@
package org.springframework.beans.factory.xml;
import java.io.StringReader;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.beans.factory.parsing.ReaderContext;
......@@ -83,4 +89,14 @@ public class XmlReaderContext extends ReaderContext {
return generatedName;
}
public Document readDocumentFromString(String documentContent) {
InputSource is = new InputSource(new StringReader(documentContent));
try {
return this.reader.doLoadDocument(is, getResource());
}
catch (Exception ex) {
throw new BeanDefinitionStoreException("Failed to read XML document", ex);
}
}
}
/*
* Copyright 2002-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.support;
import groovy.lang.GroovyObject;
import groovy.lang.GroovySystem;
import groovy.lang.MetaClass;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
/**
* An {@link org.springframework.context.ApplicationContext} implementation that extends
* {@link GenericApplicationContext} and implements {@link GroovyObject} such that beans
* can be retrieved with the dot de-reference syntax instead of using {@link #getBean}.
*
* <p>Consider this as the equivalent of {@link GenericXmlApplicationContext} for
* Groovy bean definitions. The main difference is that, within a Groovy script,
* the context can be used with an inline bean definition closure like as follows:
*
* <pre>import org.hibernate.SessionFactory
* import org.apache.commons.dbcp.BasicDataSource
*
* def context = new GenericGroovyApplicationContext()
* context.reader.beans {
* dataSource(BasicDataSource) { // <--- invokeMethod
* driverClassName = "org.hsqldb.jdbcDriver"
* url = "jdbc:hsqldb:mem:grailsDB"
* username = "sa" // <-- setProperty
* password = ""
* settings = [mynew:"setting"]
* }
* sessionFactory(SessionFactory) {
* dataSource = dataSource // <-- getProperty for retrieving references
* }
* myService(MyService) {
* nestedBean = { AnotherBean bean -> // <-- setProperty with closure for nested bean
* dataSource = dataSource
* }
* }
* }
* context.refresh()</pre>
*
* <p>Alternatively, load a Groovy bean definition script like the following
* from an external resource (e.g. an "applicationContext.groovy" file):
*
* <pre>import org.hibernate.SessionFactory
* import org.apache.commons.dbcp.BasicDataSource
*
* 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
* }
* }
* }</pre>
*
* <p>With the following Java code creating the {@code GenericGroovyApplicationContext}
* (potentially using Ant-style '*'/'**' location patterns):
*
* <pre>GenericGroovyApplicationContext context = new GenericGroovyApplicationContext();
* context.load("org/myapp/applicationContext.groovy");
* context.refresh();</pre>
*
* <p>Or even more concise, provided that no extra configuration is needed:
*
* <pre>ApplicationContext context = new GenericGroovyApplicationContext("org/myapp/applicationContext.groovy");</pre>
*
* @author Juergen Hoeller
* @author Jeff Brown
* @since 4.0
* @see org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader
*/
public class GenericGroovyApplicationContext extends GenericApplicationContext implements GroovyObject {
private final GroovyBeanDefinitionReader reader = new GroovyBeanDefinitionReader(this);
private final BeanWrapper contextWrapper = new BeanWrapperImpl(this);
private MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass());
/**
* Create a new GenericGroovyApplicationContext that needs to be
* {@link #load loaded} and then manually {@link #refresh refreshed}.
*/
public GenericGroovyApplicationContext() {
}
/**
* Create a new GenericGroovyApplicationContext, loading bean definitions
* from the given resources and automatically refreshing the context.
* @param resources the resources to load from
*/
public GenericGroovyApplicationContext(Resource... resources) {
load(resources);
refresh();
}
/**
* Create a new GenericGroovyApplicationContext, loading bean definitions
* from the given resource locations and automatically refreshing the context.
* @param resourceLocations the resources to load from
*/
public GenericGroovyApplicationContext(String... resourceLocations) {
load(resourceLocations);
refresh();
}
/**
* Create a new GenericGroovyApplicationContext, loading bean definitions
* from the given resource locations and automatically refreshing the context.
* @param relativeClass class whose package will be used as a prefix when
* loading each specified resource name
* @param resourceNames relatively-qualified names of resources to load
*/
public GenericGroovyApplicationContext(Class<?> relativeClass, String... resourceNames) {
load(relativeClass, resourceNames);
refresh();
}
/**
* Exposes the underlying {@link GroovyBeanDefinitionReader} for convenient access
* to the {@code loadBeanDefinition} methods on it as well as the ability
* to specify an inline Groovy bean definition closure.
* @see GroovyBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource...)
* @see GroovyBeanDefinitionReader#loadBeanDefinitions(String...)
*/
public final GroovyBeanDefinitionReader getReader() {
return this.reader;
}
/**
* Delegates the given environment to underlying {@link GroovyBeanDefinitionReader}.
* Should be called before any call to {@code #load}.
*/
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(getEnvironment());
}
/**
* Load bean definitions from the given Groovy scripts.
* @param resources one or more resources to load from
*/
public void load(Resource... resources) {
this.reader.loadBeanDefinitions(resources);
}
/**
* Load bean definitions from the given Groovy scripts.
* @param resourceLocations one or more resource locations to load from
*/
public void load(String... resourceLocations) {
this.reader.loadBeanDefinitions(resourceLocations);
}
/**
* Load bean definitions from the given Groovy scripts.
* @param relativeClass class whose package will be used as a prefix when
* loading each specified resource name
* @param resourceNames relatively-qualified names of resources to load
*/
public void load(Class<?> relativeClass, String... resourceNames) {
Resource[] resources = new Resource[resourceNames.length];
for (int i = 0; i < resourceNames.length; i++) {
resources[i] = new ClassPathResource(resourceNames[i], relativeClass);
}
this.load(resources);
}
// IMPLEMENTATION OF THE GROOVYOBJECT INTERFACE
public void setMetaClass(MetaClass metaClass) {
this.metaClass = metaClass;
}
public MetaClass getMetaClass() {
return this.metaClass;
}
public Object invokeMethod(String name, Object args) {
return this.metaClass.invokeMethod(this, name, args);
}
public void setProperty(String property, Object newValue) {
if (newValue instanceof BeanDefinition) {
registerBeanDefinition(property, (BeanDefinition) newValue);
}
else {
this.metaClass.setProperty(this, property, newValue);
}
}
public Object getProperty(String property) {
if (containsBean(property)) {
return getBean(property);
}
else if (this.contextWrapper.isReadableProperty(property)) {
return this.contextWrapper.getPropertyValue(property);
}
throw new NoSuchBeanDefinitionException(property);
}
}
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -45,10 +45,9 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
/**
* Create a new GenericXmlApplicationContext that needs to be
* {@linkplain #load loaded} and then manually {@link #refresh refreshed}.
* {@link #load loaded} and then manually {@link #refresh refreshed}.
*/
public GenericXmlApplicationContext() {
reader.setEnvironment(this.getEnvironment());
}
/**
......@@ -83,6 +82,15 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
refresh();
}
/**
* Exposes the underlying {@link XmlBeanDefinitionReader} for additional
* configuration facilities and {@code loadBeanDefinition} variations.
*/
public final XmlBeanDefinitionReader getReader() {
return this.reader;
}
/**
* Set whether to use XML validation. Default is {@code true}.
*/
......@@ -91,14 +99,13 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
}
/**
* {@inheritDoc}
* <p>Delegates the given environment to underlying {@link XmlBeanDefinitionReader}.
* Should be called before any call to {@link #load}.
* Delegates the given environment to underlying {@link XmlBeanDefinitionReader}.
* Should be called before any call to {@code #load}.
*/
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(this.getEnvironment());
this.reader.setEnvironment(getEnvironment());
}
/**
......
/*
* Copyright 2002-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.groovy
import org.springframework.beans.factory.NoSuchBeanDefinitionException
import org.springframework.context.support.GenericGroovyApplicationContext
/**
* @author Jeff Brown
*/
class GroovyApplicationContextDynamicBeanPropertyTests extends GroovyTestCase {
void testAccessDynamicBeanProperties() {
def ctx = new GenericGroovyApplicationContext();
ctx.reader.loadBeanDefinitions("org/springframework/context/groovy/applicationContext.groovy");
ctx.refresh()
def framework = ctx.framework
assertNotNull 'could not find framework bean', framework
assertEquals 'Grails', framework
}
void testAccessingNonExistentBeanViaDynamicProperty() {
def ctx = new GenericGroovyApplicationContext();
ctx.reader.loadBeanDefinitions("org/springframework/context/groovy/applicationContext.groovy");
ctx.refresh()
def err = shouldFail(NoSuchBeanDefinitionException) {
ctx.someNonExistentBean
}
assertEquals "No bean named 'someNonExistentBean' is defined", err
}
}
/*
* Copyright 2002-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.groovy;
import junit.framework.TestCase;
import org.springframework.context.support.GenericGroovyApplicationContext;
/**
* @author Jeff Brown
* @author Juergen Hoeller
*/
public class GroovyApplicationContextTests extends TestCase {
public void testLoadingConfigFile() {
GenericGroovyApplicationContext ctx = new GenericGroovyApplicationContext(
"org/springframework/context/groovy/applicationContext.groovy");
Object framework = ctx.getBean("framework");
assertNotNull("could not find framework bean", framework);
assertEquals("Grails", framework);
}
public void testLoadingMultipleConfigFiles() {
GenericGroovyApplicationContext ctx = new GenericGroovyApplicationContext(
"org/springframework/context/groovy/applicationContext2.groovy",
"org/springframework/context/groovy/applicationContext.groovy");
Object framework = ctx.getBean("framework");
assertNotNull("could not find framework bean", framework);
assertEquals("Grails", framework);
Object company = ctx.getBean("company");
assertNotNull("could not find company bean", company);
assertEquals("SpringSource", company);
}
public void testLoadingMultipleConfigFilesWithRelativeClass() {
GenericGroovyApplicationContext ctx = new GenericGroovyApplicationContext();
ctx.load(GroovyApplicationContextTests.class, "applicationContext2.groovy", "applicationContext.groovy");
ctx.refresh();
Object framework = ctx.getBean("framework");
assertNotNull("could not find framework bean", framework);
assertEquals("Grails", framework);
Object company = ctx.getBean("company");
assertNotNull("could not find company bean", company);
assertEquals("SpringSource", company);
}
}
package org.springframework.context.groovy
beans {
framework String, 'Grails'
foo String, 'hello'
}
package org.springframework.context.groovy
beans {
company String, 'SpringSource'
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="foo" class="java.lang.String">
<constructor-arg value="hello"/>
</bean>
</beans>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册