SPR-6268: Add proxy-target-class to <lang:groovy/>
This commit is contained in:
parent
5bfeb34b89
commit
64fd0b081d
|
|
@ -70,9 +70,10 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
private static final String SCRIPT_INTERFACES_ATTRIBUTE = "script-interfaces";
|
||||
|
||||
private static final String REFRESH_CHECK_DELAY_ATTRIBUTE = "refresh-check-delay";
|
||||
|
||||
private static final String CUSTOMIZER_REF_ATTRIBUTE = "customizer-ref";
|
||||
|
||||
private static final String PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class";
|
||||
|
||||
private static final String CUSTOMIZER_REF_ATTRIBUTE = "customizer-ref";
|
||||
|
||||
/**
|
||||
* The {@link org.springframework.scripting.ScriptFactory} class that this
|
||||
|
|
@ -80,7 +81,6 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
*/
|
||||
private final String scriptFactoryClassName;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance of this parser, creating bean definitions for the
|
||||
* supplied {@link org.springframework.scripting.ScriptFactory} class.
|
||||
|
|
@ -90,7 +90,6 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
this.scriptFactoryClassName = scriptFactoryClassName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses the dynamic object element and returns the resulting bean definition.
|
||||
* Registers a {@link ScriptFactoryPostProcessor} if needed.
|
||||
|
|
@ -110,7 +109,8 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||
bd.setBeanClassName(this.scriptFactoryClassName);
|
||||
bd.setSource(parserContext.extractSource(element));
|
||||
|
||||
bd.setAttribute(ScriptFactoryPostProcessor.LANGUAGE_ATTRIBUTE, element.getLocalName());
|
||||
|
||||
// Determine bean scope.
|
||||
String scope = element.getAttribute(SCOPE_ATTRIBUTE);
|
||||
if (StringUtils.hasLength(scope)) {
|
||||
|
|
@ -123,8 +123,7 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
// Only "byType" and "byName" supported, but maybe other default inherited...
|
||||
if (autowireMode == GenericBeanDefinition.AUTOWIRE_AUTODETECT) {
|
||||
autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE;
|
||||
}
|
||||
else if (autowireMode == GenericBeanDefinition.AUTOWIRE_CONSTRUCTOR) {
|
||||
} else if (autowireMode == GenericBeanDefinition.AUTOWIRE_CONSTRUCTOR) {
|
||||
autowireMode = GenericBeanDefinition.AUTOWIRE_NO;
|
||||
}
|
||||
bd.setAutowireMode(autowireMode);
|
||||
|
|
@ -134,31 +133,34 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
bd.setDependencyCheck(parserContext.getDelegate().getDependencyCheck(dependencyCheck));
|
||||
|
||||
// Retrieve the defaults for bean definitions within this parser context
|
||||
BeanDefinitionDefaults beanDefinitionDefaults =
|
||||
parserContext.getDelegate().getBeanDefinitionDefaults();
|
||||
BeanDefinitionDefaults beanDefinitionDefaults = parserContext.getDelegate().getBeanDefinitionDefaults();
|
||||
|
||||
// Determine init method and destroy method.
|
||||
String initMethod = element.getAttribute(INIT_METHOD_ATTRIBUTE);
|
||||
if (StringUtils.hasLength(initMethod)) {
|
||||
bd.setInitMethodName(initMethod);
|
||||
}
|
||||
else if (beanDefinitionDefaults.getInitMethodName() != null) {
|
||||
} else if (beanDefinitionDefaults.getInitMethodName() != null) {
|
||||
bd.setInitMethodName(beanDefinitionDefaults.getInitMethodName());
|
||||
}
|
||||
|
||||
String destroyMethod = element.getAttribute(DESTROY_METHOD_ATTRIBUTE);
|
||||
if (StringUtils.hasLength(destroyMethod)) {
|
||||
bd.setDestroyMethodName(destroyMethod);
|
||||
}
|
||||
else if (beanDefinitionDefaults.getDestroyMethodName() != null) {
|
||||
} else if (beanDefinitionDefaults.getDestroyMethodName() != null) {
|
||||
bd.setDestroyMethodName(beanDefinitionDefaults.getDestroyMethodName());
|
||||
}
|
||||
|
||||
// Attach any refresh metadata.
|
||||
String refreshCheckDelay = element.getAttribute(REFRESH_CHECK_DELAY_ATTRIBUTE);
|
||||
if (StringUtils.hasText(refreshCheckDelay)) {
|
||||
bd.setAttribute(
|
||||
ScriptFactoryPostProcessor.REFRESH_CHECK_DELAY_ATTRIBUTE, new Long(refreshCheckDelay));
|
||||
bd.setAttribute(ScriptFactoryPostProcessor.REFRESH_CHECK_DELAY_ATTRIBUTE, new Long(refreshCheckDelay));
|
||||
}
|
||||
|
||||
// Attach any proxy target class metadata.
|
||||
String proxyTargetClass = element.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE);
|
||||
if (StringUtils.hasText(proxyTargetClass)) {
|
||||
Boolean flag = new Boolean(proxyTargetClass);
|
||||
bd.setAttribute(ScriptFactoryPostProcessor.PROXY_TARGET_CLASS_ATTRIBUTE, flag);
|
||||
}
|
||||
|
||||
// Add constructor arguments.
|
||||
|
|
@ -168,14 +170,13 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
if (element.hasAttribute(SCRIPT_INTERFACES_ATTRIBUTE)) {
|
||||
cav.addIndexedArgumentValue(constructorArgNum++, element.getAttribute(SCRIPT_INTERFACES_ATTRIBUTE));
|
||||
}
|
||||
|
||||
|
||||
// This is used for Groovy. It's a bean reference to a customizer bean.
|
||||
if (element.hasAttribute(CUSTOMIZER_REF_ATTRIBUTE)) {
|
||||
String customizerBeanName = element.getAttribute(CUSTOMIZER_REF_ATTRIBUTE);
|
||||
if (!StringUtils.hasText(customizerBeanName)) {
|
||||
parserContext.getReaderContext().error("Attribute 'customizer-ref' has empty value", element);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
cav.addIndexedArgumentValue(constructorArgNum++, new RuntimeBeanReference(customizerBeanName));
|
||||
}
|
||||
}
|
||||
|
|
@ -197,15 +198,12 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
if (hasScriptSource && !elements.isEmpty()) {
|
||||
readerContext.error("Only one of 'script-source' and 'inline-script' should be specified.", element);
|
||||
return null;
|
||||
}
|
||||
else if (hasScriptSource) {
|
||||
} else if (hasScriptSource) {
|
||||
return element.getAttribute(SCRIPT_SOURCE_ATTRIBUTE);
|
||||
}
|
||||
else if (!elements.isEmpty()) {
|
||||
} else if (!elements.isEmpty()) {
|
||||
Element inlineElement = (Element) elements.get(0);
|
||||
return "inline:" + DomUtils.getTextValue(inlineElement);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
readerContext.error("Must specify either 'script-source' or 'inline-script'.", element);
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.springframework.scripting.config;
|
|||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
|
@ -31,6 +32,8 @@ public class ScriptingDefaultsParser implements BeanDefinitionParser {
|
|||
|
||||
private static final String REFRESH_CHECK_DELAY_ATTRIBUTE = "refresh-check-delay";
|
||||
|
||||
private static final String PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class";
|
||||
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinition bd =
|
||||
|
|
@ -39,6 +42,10 @@ public class ScriptingDefaultsParser implements BeanDefinitionParser {
|
|||
if (StringUtils.hasText(refreshCheckDelay)) {
|
||||
bd.getPropertyValues().add("defaultRefreshCheckDelay", new Long(refreshCheckDelay));
|
||||
}
|
||||
String proxyTargetClass = element.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE);
|
||||
if (StringUtils.hasText(proxyTargetClass)) {
|
||||
bd.getPropertyValues().add("defaultProxyTargetClass", new TypedStringValue(proxyTargetClass, Boolean.class));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
|
|||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionValidationException;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
|
|
@ -135,8 +136,8 @@ import org.springframework.util.StringUtils;
|
|||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
|
||||
implements BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware, DisposableBean, Ordered {
|
||||
public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements
|
||||
BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware, DisposableBean, Ordered {
|
||||
|
||||
/**
|
||||
* The {@link org.springframework.core.io.Resource}-style prefix that denotes
|
||||
|
|
@ -146,19 +147,26 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
*/
|
||||
public static final String INLINE_SCRIPT_PREFIX = "inline:";
|
||||
|
||||
public static final String REFRESH_CHECK_DELAY_ATTRIBUTE =
|
||||
Conventions.getQualifiedAttributeName(ScriptFactoryPostProcessor.class, "refreshCheckDelay");
|
||||
public static final String REFRESH_CHECK_DELAY_ATTRIBUTE = Conventions.getQualifiedAttributeName(
|
||||
ScriptFactoryPostProcessor.class, "refreshCheckDelay");
|
||||
|
||||
public static final String PROXY_TARGET_CLASS_ATTRIBUTE = Conventions.getQualifiedAttributeName(
|
||||
ScriptFactoryPostProcessor.class, "proxyTargetClass");
|
||||
|
||||
public static final String LANGUAGE_ATTRIBUTE = Conventions.getQualifiedAttributeName(
|
||||
ScriptFactoryPostProcessor.class, "language");
|
||||
|
||||
private static final String SCRIPT_FACTORY_NAME_PREFIX = "scriptFactory.";
|
||||
|
||||
private static final String SCRIPTED_OBJECT_NAME_PREFIX = "scriptedObject.";
|
||||
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private long defaultRefreshCheckDelay = -1;
|
||||
|
||||
private boolean defaultProxyTargetClass = false;
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
private ConfigurableBeanFactory beanFactory;
|
||||
|
|
@ -170,7 +178,6 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
/** Map from bean name String to ScriptSource object */
|
||||
private final Map<String, ScriptSource> scriptSourceCache = new HashMap<String, ScriptSource>();
|
||||
|
||||
|
||||
/**
|
||||
* Set the delay between refresh checks, in milliseconds.
|
||||
* Default is -1, indicating no refresh checks at all.
|
||||
|
|
@ -183,14 +190,22 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
this.defaultRefreshCheckDelay = defaultRefreshCheckDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag to signal that refreshable proxies should be created to proxy the target class not its interfaces.
|
||||
* @param defaultProxyTargetClass the flag value to set
|
||||
*/
|
||||
public void setDefaultProxyTargetClass(boolean defaultProxyTargetClass) {
|
||||
this.defaultProxyTargetClass = defaultProxyTargetClass;
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
if (!(beanFactory instanceof ConfigurableBeanFactory)) {
|
||||
throw new IllegalStateException("ScriptFactoryPostProcessor doesn't work with a BeanFactory " +
|
||||
"which does not implement ConfigurableBeanFactory: " + beanFactory.getClass());
|
||||
throw new IllegalStateException("ScriptFactoryPostProcessor doesn't work with a BeanFactory "
|
||||
+ "which does not implement ConfigurableBeanFactory: " + beanFactory.getClass());
|
||||
}
|
||||
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
|
||||
|
||||
|
|
@ -217,7 +232,6 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class predictBeanType(Class beanClass, String beanName) {
|
||||
// We only apply special treatment to ScriptFactory implementations here.
|
||||
|
|
@ -233,18 +247,15 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
prepareScriptBeans(bd, scriptFactoryBeanName, scriptedObjectBeanName);
|
||||
|
||||
ScriptFactory scriptFactory = this.scriptBeanFactory.getBean(scriptFactoryBeanName, ScriptFactory.class);
|
||||
ScriptSource scriptSource =
|
||||
getScriptSource(scriptFactoryBeanName, scriptFactory.getScriptSourceLocator());
|
||||
ScriptSource scriptSource = getScriptSource(scriptFactoryBeanName, scriptFactory.getScriptSourceLocator());
|
||||
Class[] interfaces = scriptFactory.getScriptInterfaces();
|
||||
|
||||
Class scriptedType = scriptFactory.getScriptedObjectType(scriptSource);
|
||||
if (scriptedType != null) {
|
||||
return scriptedType;
|
||||
}
|
||||
else if (!ObjectUtils.isEmpty(interfaces)) {
|
||||
} else if (!ObjectUtils.isEmpty(interfaces)) {
|
||||
return (interfaces.length == 1 ? interfaces[0] : createCompositeInterface(interfaces));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (bd.isSingleton()) {
|
||||
Object bean = this.scriptBeanFactory.getBean(scriptedObjectBeanName);
|
||||
if (bean != null) {
|
||||
|
|
@ -252,15 +263,14 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof BeanCreationException &&
|
||||
((BeanCreationException) ex).getMostSpecificCause() instanceof BeanCurrentlyInCreationException) {
|
||||
} catch (Exception ex) {
|
||||
if (ex instanceof BeanCreationException
|
||||
&& ((BeanCreationException) ex).getMostSpecificCause() instanceof BeanCurrentlyInCreationException) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Could not determine scripted object type for bean '" + beanName + "': " + ex.getMessage());
|
||||
logger.trace("Could not determine scripted object type for bean '" + beanName + "': "
|
||||
+ ex.getMessage());
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not determine scripted object type for bean '" + beanName + "'", ex);
|
||||
}
|
||||
|
|
@ -283,8 +293,7 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
prepareScriptBeans(bd, scriptFactoryBeanName, scriptedObjectBeanName);
|
||||
|
||||
ScriptFactory scriptFactory = this.scriptBeanFactory.getBean(scriptFactoryBeanName, ScriptFactory.class);
|
||||
ScriptSource scriptSource =
|
||||
getScriptSource(scriptFactoryBeanName, scriptFactory.getScriptSourceLocator());
|
||||
ScriptSource scriptSource = getScriptSource(scriptFactoryBeanName, scriptFactory.getScriptSourceLocator());
|
||||
boolean isFactoryBean = false;
|
||||
try {
|
||||
Class scriptedObjectType = scriptFactory.getScriptedObjectType(scriptSource);
|
||||
|
|
@ -292,19 +301,25 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
if (scriptedObjectType != null) {
|
||||
isFactoryBean = FactoryBean.class.isAssignableFrom(scriptedObjectType);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanCreationException(
|
||||
beanName, "Could not determine scripted object type for " + scriptFactory, ex);
|
||||
} catch (Exception ex) {
|
||||
throw new BeanCreationException(beanName, "Could not determine scripted object type for " + scriptFactory,
|
||||
ex);
|
||||
}
|
||||
|
||||
long refreshCheckDelay = resolveRefreshCheckDelay(bd);
|
||||
if (refreshCheckDelay >= 0) {
|
||||
Class[] interfaces = scriptFactory.getScriptInterfaces();
|
||||
RefreshableScriptTargetSource ts = new RefreshableScriptTargetSource(
|
||||
this.scriptBeanFactory, scriptedObjectBeanName, scriptFactory, scriptSource, isFactoryBean);
|
||||
RefreshableScriptTargetSource ts = new RefreshableScriptTargetSource(this.scriptBeanFactory,
|
||||
scriptedObjectBeanName, scriptFactory, scriptSource, isFactoryBean);
|
||||
boolean proxyTargetClass = resolveProxyTargetClass(bd);
|
||||
String language = (String) bd.getAttribute(LANGUAGE_ATTRIBUTE);
|
||||
if (proxyTargetClass && (language==null || !language.equals("groovy"))) {
|
||||
throw new BeanDefinitionValidationException(
|
||||
"Cannot use proxyTargetClass=true with script beans where language is not groovy (found "
|
||||
+ language + ")");
|
||||
}
|
||||
ts.setRefreshCheckDelay(refreshCheckDelay);
|
||||
return createRefreshableProxy(ts, interfaces);
|
||||
return createRefreshableProxy(ts, interfaces, proxyTargetClass);
|
||||
}
|
||||
|
||||
if (isFactoryBean) {
|
||||
|
|
@ -313,7 +328,6 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
return this.scriptBeanFactory.getBean(scriptedObjectBeanName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the script beans in the internal BeanFactory that this
|
||||
* post-processor uses. Each original bean definition will be split
|
||||
|
|
@ -322,18 +336,18 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
* @param scriptFactoryBeanName the name of the internal ScriptFactory bean
|
||||
* @param scriptedObjectBeanName the name of the internal scripted object bean
|
||||
*/
|
||||
protected void prepareScriptBeans(
|
||||
BeanDefinition bd, String scriptFactoryBeanName, String scriptedObjectBeanName) {
|
||||
protected void prepareScriptBeans(BeanDefinition bd, String scriptFactoryBeanName, String scriptedObjectBeanName) {
|
||||
|
||||
// Avoid recreation of the script bean definition in case of a prototype.
|
||||
synchronized (this.scriptBeanFactory) {
|
||||
if (!this.scriptBeanFactory.containsBeanDefinition(scriptedObjectBeanName)) {
|
||||
|
||||
this.scriptBeanFactory.registerBeanDefinition(
|
||||
scriptFactoryBeanName, createScriptFactoryBeanDefinition(bd));
|
||||
ScriptFactory scriptFactory = this.scriptBeanFactory.getBean(scriptFactoryBeanName, ScriptFactory.class);
|
||||
ScriptSource scriptSource =
|
||||
getScriptSource(scriptFactoryBeanName, scriptFactory.getScriptSourceLocator());
|
||||
this.scriptBeanFactory.registerBeanDefinition(scriptFactoryBeanName,
|
||||
createScriptFactoryBeanDefinition(bd));
|
||||
ScriptFactory scriptFactory = this.scriptBeanFactory
|
||||
.getBean(scriptFactoryBeanName, ScriptFactory.class);
|
||||
ScriptSource scriptSource = getScriptSource(scriptFactoryBeanName,
|
||||
scriptFactory.getScriptSourceLocator());
|
||||
Class<?>[] interfaces = scriptFactory.getScriptInterfaces();
|
||||
|
||||
Class<?>[] scriptedInterfaces = interfaces;
|
||||
|
|
@ -342,8 +356,8 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
scriptedInterfaces = ObjectUtils.addObjectToArray(interfaces, configInterface);
|
||||
}
|
||||
|
||||
BeanDefinition objectBd = createScriptedObjectBeanDefinition(
|
||||
bd, scriptFactoryBeanName, scriptSource, scriptedInterfaces);
|
||||
BeanDefinition objectBd = createScriptedObjectBeanDefinition(bd, scriptFactoryBeanName, scriptSource,
|
||||
scriptedInterfaces);
|
||||
long refreshCheckDelay = resolveRefreshCheckDelay(bd);
|
||||
if (refreshCheckDelay >= 0) {
|
||||
objectBd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
|
|
@ -369,18 +383,31 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
Object attributeValue = beanDefinition.getAttribute(REFRESH_CHECK_DELAY_ATTRIBUTE);
|
||||
if (attributeValue instanceof Number) {
|
||||
refreshCheckDelay = ((Number) attributeValue).longValue();
|
||||
}
|
||||
else if (attributeValue instanceof String) {
|
||||
} else if (attributeValue instanceof String) {
|
||||
refreshCheckDelay = Long.parseLong((String) attributeValue);
|
||||
}
|
||||
else if (attributeValue != null) {
|
||||
throw new BeanDefinitionStoreException(
|
||||
"Invalid refresh check delay attribute [" + REFRESH_CHECK_DELAY_ATTRIBUTE +
|
||||
"] with value [" + attributeValue + "]: needs to be of type Number or String");
|
||||
} else if (attributeValue != null) {
|
||||
throw new BeanDefinitionStoreException("Invalid refresh check delay attribute ["
|
||||
+ REFRESH_CHECK_DELAY_ATTRIBUTE + "] with value [" + attributeValue
|
||||
+ "]: needs to be of type Number or String");
|
||||
}
|
||||
return refreshCheckDelay;
|
||||
}
|
||||
|
||||
protected boolean resolveProxyTargetClass(BeanDefinition beanDefinition) {
|
||||
boolean proxyTargetClass = this.defaultProxyTargetClass;
|
||||
Object attributeValue = beanDefinition.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE);
|
||||
if (attributeValue instanceof Boolean) {
|
||||
proxyTargetClass = ((Boolean) attributeValue).booleanValue();
|
||||
} else if (attributeValue instanceof String) {
|
||||
proxyTargetClass = new Boolean((String) attributeValue);
|
||||
} else if (attributeValue != null) {
|
||||
throw new BeanDefinitionStoreException("Invalid refresh check delay attribute ["
|
||||
+ REFRESH_CHECK_DELAY_ATTRIBUTE + "] with value [" + attributeValue
|
||||
+ "]: needs to be of type Number or String");
|
||||
}
|
||||
return proxyTargetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ScriptFactory bean definition based on the given script definition,
|
||||
* extracting only the definition data that is relevant for the ScriptFactory
|
||||
|
|
@ -425,13 +452,12 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
* @param resourceLoader the ResourceLoader to use (if necessary)
|
||||
* @return the ScriptSource instance
|
||||
*/
|
||||
protected ScriptSource convertToScriptSource(
|
||||
String beanName, String scriptSourceLocator, ResourceLoader resourceLoader) {
|
||||
protected ScriptSource convertToScriptSource(String beanName, String scriptSourceLocator,
|
||||
ResourceLoader resourceLoader) {
|
||||
|
||||
if (scriptSourceLocator.startsWith(INLINE_SCRIPT_PREFIX)) {
|
||||
return new StaticScriptSource(scriptSourceLocator.substring(INLINE_SCRIPT_PREFIX.length()), beanName);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return new ResourceScriptSource(resourceLoader.getResource(scriptSourceLocator));
|
||||
}
|
||||
}
|
||||
|
|
@ -457,7 +483,7 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
String propertyName = pv.getName();
|
||||
Class propertyType = BeanUtils.findPropertyType(propertyName, interfaces);
|
||||
String setterName = "set" + StringUtils.capitalize(propertyName);
|
||||
Signature signature = new Signature(setterName, Type.VOID_TYPE, new Type[] {Type.getType(propertyType)});
|
||||
Signature signature = new Signature(setterName, Type.VOID_TYPE, new Type[] { Type.getType(propertyType) });
|
||||
maker.add(signature, new Type[0]);
|
||||
}
|
||||
if (bd instanceof AbstractBeanDefinition) {
|
||||
|
|
@ -498,8 +524,8 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
* @return the extracted ScriptFactory bean definition
|
||||
* @see org.springframework.scripting.ScriptFactory#getScriptedObject
|
||||
*/
|
||||
protected BeanDefinition createScriptedObjectBeanDefinition(
|
||||
BeanDefinition bd, String scriptFactoryBeanName, ScriptSource scriptSource, Class[] interfaces) {
|
||||
protected BeanDefinition createScriptedObjectBeanDefinition(BeanDefinition bd, String scriptFactoryBeanName,
|
||||
ScriptSource scriptSource, Class[] interfaces) {
|
||||
|
||||
GenericBeanDefinition objectBd = new GenericBeanDefinition(bd);
|
||||
objectBd.setFactoryBeanName(scriptFactoryBeanName);
|
||||
|
|
@ -518,23 +544,27 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces
|
|||
* @return the generated proxy
|
||||
* @see RefreshableScriptTargetSource
|
||||
*/
|
||||
protected Object createRefreshableProxy(TargetSource ts, Class[] interfaces) {
|
||||
protected Object createRefreshableProxy(TargetSource ts, Class[] interfaces, boolean proxyTargetClass) {
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
proxyFactory.setTargetSource(ts);
|
||||
ClassLoader classLoader = this.beanClassLoader;
|
||||
|
||||
if (interfaces == null) {
|
||||
interfaces = ClassUtils.getAllInterfacesForClass(ts.getTargetClass(), this.beanClassLoader);
|
||||
}
|
||||
proxyFactory.setInterfaces(interfaces);
|
||||
if (proxyTargetClass) {
|
||||
classLoader = null; // Force use of Class.getClassLoader()
|
||||
proxyFactory.setProxyTargetClass(proxyTargetClass);
|
||||
}
|
||||
|
||||
DelegatingIntroductionInterceptor introduction = new DelegatingIntroductionInterceptor(ts);
|
||||
introduction.suppressInterface(TargetSource.class);
|
||||
proxyFactory.addAdvice(introduction);
|
||||
|
||||
return proxyFactory.getProxy(this.beanClassLoader);
|
||||
return proxyFactory.getProxy(classLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroy the inner bean factory (used for scripts) on shutdown.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -30,28 +30,49 @@
|
|||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="groovy" type="customizableScriptType">
|
||||
<xsd:element name="groovy">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A Spring bean backed by a Groovy class definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="customizableScriptType">
|
||||
<xsd:attributeGroup ref="defaultableAttributes"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="jruby" type="dynamicScriptType">
|
||||
<xsd:element name="jruby">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A Spring bean backed by a JRuby class definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="dynamicScriptType">
|
||||
<xsd:attributeGroup ref="vanillaScriptAttributes"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="bsh" type="dynamicScriptType">
|
||||
<xsd:element name="bsh">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A Spring bean backed by a BeanShell script.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="dynamicScriptType">
|
||||
<xsd:attributeGroup ref="vanillaScriptAttributes"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<!-- Script Types -->
|
||||
|
|
@ -77,7 +98,6 @@
|
|||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="defaultableAttributes"/>
|
||||
<xsd:attribute name="script-source" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.core.io.Resource"><![CDATA[
|
||||
|
|
@ -185,7 +205,7 @@
|
|||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:attributeGroup name="defaultableAttributes">
|
||||
<xsd:attributeGroup name="vanillaScriptAttributes">
|
||||
<xsd:attribute name="refresh-check-delay" type="xsd:long">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
|
|
@ -196,4 +216,18 @@
|
|||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="defaultableAttributes">
|
||||
<xsd:attribute name="proxy-target-class" type="xsd:boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Flag to tell the bean factory that if this bean is proxied it should be done using the target class type,
|
||||
not its interfaces. A refreshable script is normally proxied, so often this is useful in conjunction with
|
||||
refresh-check-delay. Defaults to false requiring no additional library dependencies, but hiding behaviour in the
|
||||
bean that is not defined in an interface.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="vanillaScriptAttributes"></xsd:attributeGroup>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
</xsd:schema>
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.lang.reflect.Field;
|
|||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.target.dynamic.AbstractRefreshableTargetSource;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
|
@ -32,7 +33,10 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|||
public class ScriptingDefaultsTests extends TestCase {
|
||||
|
||||
private static final String CONFIG =
|
||||
"org/springframework/scripting/config/scriptingDefaultsTests.xml";
|
||||
"org/springframework/scripting/config/scriptingDefaultsTests.xml";
|
||||
|
||||
private static final String PROXY_CONFIG =
|
||||
"org/springframework/scripting/config/scriptingDefaultsProxyTargetClassTests.xml";
|
||||
|
||||
|
||||
public void testDefaultRefreshCheckDelay() throws Exception {
|
||||
|
|
@ -73,4 +77,10 @@ public class ScriptingDefaultsTests extends TestCase {
|
|||
assertEquals(otherBean, testBean.getOtherBean());
|
||||
}
|
||||
|
||||
public void testDefaultProxyTargetClass() {
|
||||
ApplicationContext context = new ClassPathXmlApplicationContext(PROXY_CONFIG);
|
||||
Object testBean = context.getBean("testBean");
|
||||
assertTrue(AopUtils.isCglibProxy(testBean));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2002-2011 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.scripting.groovy;
|
||||
|
||||
import org.springframework.scripting.ConfigurableMessenger;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class ConcreteMessenger implements ConfigurableMessenger {
|
||||
|
||||
private String message;
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,7 +16,13 @@
|
|||
|
||||
package org.springframework.scripting.groovy;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import groovy.lang.DelegatingMetaClass;
|
||||
import groovy.lang.GroovyObject;
|
||||
|
||||
|
|
@ -178,8 +184,7 @@ public class GroovyScriptFactoryTests {
|
|||
try {
|
||||
new ClassPathXmlApplicationContext("org/springframework/scripting/groovy/groovyBrokenContext.xml");
|
||||
fail("Should throw exception for broken script file");
|
||||
}
|
||||
catch (NestedRuntimeException ex) {
|
||||
} catch (NestedRuntimeException ex) {
|
||||
assertTrue("Wrong root cause: " + ex, ex.contains(ScriptCompilationException.class));
|
||||
}
|
||||
}
|
||||
|
|
@ -194,12 +199,12 @@ public class GroovyScriptFactoryTests {
|
|||
script.suggestedClassName();
|
||||
mock.setReturnValue("someName");
|
||||
mock.replay();
|
||||
GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX + badScript);
|
||||
GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX
|
||||
+ badScript);
|
||||
try {
|
||||
factory.getScriptedObject(script, new Class[]{});
|
||||
factory.getScriptedObject(script, new Class[] {});
|
||||
fail("Must have thrown a ScriptCompilationException (no public no-arg ctor in scripted class).");
|
||||
}
|
||||
catch (ScriptCompilationException expected) {
|
||||
} catch (ScriptCompilationException expected) {
|
||||
assertTrue(expected.contains(InstantiationException.class));
|
||||
}
|
||||
mock.verify();
|
||||
|
|
@ -215,12 +220,12 @@ public class GroovyScriptFactoryTests {
|
|||
script.suggestedClassName();
|
||||
mock.setReturnValue("someName");
|
||||
mock.replay();
|
||||
GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX + badScript);
|
||||
GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX
|
||||
+ badScript);
|
||||
try {
|
||||
factory.getScriptedObject(script, new Class[]{});
|
||||
factory.getScriptedObject(script, new Class[] {});
|
||||
fail("Must have thrown a ScriptCompilationException (no oublic no-arg ctor in scripted class).");
|
||||
}
|
||||
catch (ScriptCompilationException expected) {
|
||||
} catch (ScriptCompilationException expected) {
|
||||
assertTrue(expected.contains(IllegalAccessException.class));
|
||||
}
|
||||
mock.verify();
|
||||
|
|
@ -254,8 +259,7 @@ public class GroovyScriptFactoryTests {
|
|||
try {
|
||||
new GroovyScriptFactory(null);
|
||||
fail("Must have thrown exception by this point.");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -264,8 +268,7 @@ public class GroovyScriptFactoryTests {
|
|||
try {
|
||||
new GroovyScriptFactory("");
|
||||
fail("Must have thrown exception by this point.");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -274,8 +277,7 @@ public class GroovyScriptFactoryTests {
|
|||
try {
|
||||
new GroovyScriptFactory("\n ");
|
||||
fail("Must have thrown exception by this point.");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,8 +286,7 @@ public class GroovyScriptFactoryTests {
|
|||
try {
|
||||
new ClassPathXmlApplicationContext("lwspBadGroovyContext.xml", getClass());
|
||||
fail("Must have thrown a BeanCreationException ('inline:' prefix was preceded by whitespace");
|
||||
}
|
||||
catch (BeanCreationException expected) {
|
||||
} catch (BeanCreationException expected) {
|
||||
assertTrue(expected.contains(FileNotFoundException.class));
|
||||
}
|
||||
}
|
||||
|
|
@ -312,12 +313,12 @@ public class GroovyScriptFactoryTests {
|
|||
try {
|
||||
factory.getScriptedObject(null, null);
|
||||
fail("Must have thrown a NullPointerException as per contract ('null' ScriptSource supplied");
|
||||
}
|
||||
catch (NullPointerException expected) {
|
||||
} catch (NullPointerException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore // see http://build.springframework.org/browse/SPR-TRUNKQUICK-908
|
||||
@Ignore
|
||||
// see http://build.springframework.org/browse/SPR-TRUNKQUICK-908
|
||||
@Test
|
||||
public void testResourceScriptFromTag() throws Exception {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass());
|
||||
|
|
@ -375,6 +376,32 @@ public class GroovyScriptFactoryTests {
|
|||
assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger));
|
||||
}
|
||||
|
||||
@Test
|
||||
// Test for SPR-6268
|
||||
public void testRefreshableFromTagProxyTargetClass() throws Exception {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd-proxy-target-class.xml",
|
||||
getClass());
|
||||
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("refreshableMessenger"));
|
||||
|
||||
Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger");
|
||||
|
||||
assertTrue(AopUtils.isAopProxy(messenger));
|
||||
assertTrue(messenger instanceof Refreshable);
|
||||
assertEquals("Hello World!", messenger.getMessage());
|
||||
|
||||
assertTrue(ctx.getBeansOfType(ConcreteMessenger.class).values().contains(messenger));
|
||||
}
|
||||
|
||||
@Test
|
||||
// Test for SPR-6268
|
||||
public void testProxyTargetClassNotAllowedIfNotGroovy() throws Exception {
|
||||
try {
|
||||
new ClassPathXmlApplicationContext("jruby-with-xsd-proxy-target-class.xml", getClass());
|
||||
} catch (BeanCreationException e) {
|
||||
assertTrue(e.getMessage().contains("Cannot use proxyTargetClass=true"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnonymousScriptDetected() throws Exception {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass());
|
||||
|
|
@ -404,8 +431,7 @@ public class GroovyScriptFactoryTests {
|
|||
try {
|
||||
ctx.getBean("bean3");
|
||||
fail("Should have thrown BeanCreationException");
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
} catch (BeanCreationException ex) {
|
||||
// expected
|
||||
assertTrue(ex.contains(UnsatisfiedDependencyException.class));
|
||||
}
|
||||
|
|
@ -424,8 +450,7 @@ public class GroovyScriptFactoryTests {
|
|||
private void testMetaClass(final String xmlFile) {
|
||||
// expect the exception we threw in the custom metaclass to show it got invoked
|
||||
try {
|
||||
ApplicationContext ctx =
|
||||
new ClassPathXmlApplicationContext(xmlFile);
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext(xmlFile);
|
||||
Calculator calc = (Calculator) ctx.getBean("delegatingCalculator");
|
||||
calc.add(1, 2);
|
||||
fail("expected IllegalStateException");
|
||||
|
|
@ -454,7 +479,6 @@ public class GroovyScriptFactoryTests {
|
|||
assertEquals("test", result);
|
||||
}
|
||||
|
||||
|
||||
public static class TestCustomizer implements GroovyObjectCustomizer {
|
||||
|
||||
public void customize(GroovyObject goo) {
|
||||
|
|
@ -462,8 +486,7 @@ public class GroovyScriptFactoryTests {
|
|||
public Object invokeMethod(Object arg0, String mName, Object[] arg2) {
|
||||
if (mName.indexOf("Missing") != -1) {
|
||||
throw new IllegalStateException("Gotcha");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return super.invokeMethod(arg0, mName, arg2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,5 @@ package org.springframework.scripting.groovy;
|
|||
|
||||
import org.springframework.scripting.ConfigurableMessenger
|
||||
|
||||
class GroovyMessenger implements ConfigurableMessenger {
|
||||
|
||||
def String message;
|
||||
class GroovyMessenger extends ConcreteMessenger {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<?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:aop="http://www.springframework.org/schema/aop"
|
||||
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/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd">
|
||||
|
||||
<lang:groovy id="refreshableMessenger" refresh-check-delay="5000" proxy-target-class="true"
|
||||
script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
|
||||
<lang:property name="message" value="Hello World!" />
|
||||
</lang:groovy>
|
||||
|
||||
</beans>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?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:aop="http://www.springframework.org/schema/aop"
|
||||
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/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd">
|
||||
|
||||
<lang:defaults proxy-target-class="true"/>
|
||||
|
||||
<lang:jruby id="refreshableMessenger" refresh-check-delay="1000"
|
||||
script-source="classpath:org/springframework/scripting/jruby/Messenger.rb"
|
||||
script-interfaces="org.springframework.scripting.Messenger">
|
||||
<lang:property name="message" value="Hello World!"/>
|
||||
</lang:jruby>
|
||||
|
||||
</beans>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?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.xsd
|
||||
http://www.springframework.org/schema/lang
|
||||
http://www.springframework.org/schema/lang/spring-lang-3.1.xsd"
|
||||
default-autowire="byName"
|
||||
default-init-method="startup"
|
||||
default-destroy-method="shutdown">
|
||||
|
||||
<lang:defaults refresh-check-delay="5000" proxy-target-class="true"/>
|
||||
|
||||
<lang:groovy id="testBean" name="/url" script-source="classpath:org/springframework/scripting/config/TestBean.groovy"/>
|
||||
|
||||
</beans>
|
||||
Loading…
Reference in New Issue