public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware, DisposableBean, Ordered
BeanPostProcessor
that
handles ScriptFactory
definitions,
replacing each factory with the actual scripted Java object generated by it.
This is similar to the
FactoryBean
mechanism, but is
specifically tailored for scripts and not built into Spring's core
container itself but rather implemented as an extension.
NOTE: The most important characteristic of this post-processor
is that constructor arguments are applied to the
ScriptFactory
instance
while bean property values are applied to the generated scripted object.
Typically, constructor arguments include a script source locator and
potentially script interfaces, while bean property values include
references and config values to inject into the scripted object itself.
The following ScriptFactoryPostProcessor
will automatically
be applied to the two
ScriptFactory
definitions below.
At runtime, the actual scripted objects will be exposed for
"bshMessenger" and "groovyMessenger", rather than the
ScriptFactory
instances. Both of
those are supposed to be castable to the example's Messenger
interfaces here.
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/> <bean id="bshMessenger" class="org.springframework.scripting.bsh.BshScriptFactory"> <constructor-arg value="classpath:mypackage/Messenger.bsh"/> <constructor-arg value="mypackage.Messenger"/> <property name="message" value="Hello World!"/> </bean> <bean id="groovyMessenger" class="org.springframework.scripting.groovy.GroovyScriptFactory"> <constructor-arg value="classpath:mypackage/Messenger.groovy"/> <property name="message" value="Hello World!"/> </bean>
NOTE: Please note that the above excerpt from a Spring
XML bean definition file uses just the <bean/>-style syntax
(in an effort to illustrate using the ScriptFactoryPostProcessor
itself).
In reality, you would never create a <bean/> definition for a
ScriptFactoryPostProcessor
explicitly; rather you would import the
tags from the 'lang'
namespace and simply create scripted
beans using the tags in that namespace... as part of doing so, a
ScriptFactoryPostProcessor
will implicitly be created for you.
The Spring reference documentation contains numerous examples of using
tags in the 'lang'
namespace; by way of an example, find below
a Groovy-backed bean defined using the 'lang:groovy'
tag.
<?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"> <!-- this is the bean definition for the Groovy-backed Messenger implementation --> <lang:groovy id="messenger" script-source="classpath:Messenger.groovy"> <lang:property name="message" value="I Can Do The Frug" /> </lang:groovy> <!-- an otherwise normal bean that will be injected by the Groovy-backed Messenger --> <bean id="bookingService" class="x.y.DefaultBookingService"> <property name="messenger" ref="messenger" /> </bean> </beans>
Modifier and Type | Field and Description |
---|---|
private java.lang.ClassLoader |
beanClassLoader |
private ConfigurableBeanFactory |
beanFactory |
private boolean |
defaultProxyTargetClass |
private long |
defaultRefreshCheckDelay |
static java.lang.String |
INLINE_SCRIPT_PREFIX
The
Resource -style prefix that denotes
an inline script. |
static java.lang.String |
LANGUAGE_ATTRIBUTE
The
language attribute. |
protected Log |
logger
Logger available to subclasses.
|
static java.lang.String |
PROXY_TARGET_CLASS_ATTRIBUTE
The
proxyTargetClass attribute. |
static java.lang.String |
REFRESH_CHECK_DELAY_ATTRIBUTE
The
refreshCheckDelay attribute. |
private ResourceLoader |
resourceLoader |
private static java.lang.String |
SCRIPT_FACTORY_NAME_PREFIX |
(package private) DefaultListableBeanFactory |
scriptBeanFactory |
private static java.lang.String |
SCRIPTED_OBJECT_NAME_PREFIX |
private java.util.Map<java.lang.String,ScriptSource> |
scriptSourceCache
Map from bean name String to ScriptSource object.
|
HIGHEST_PRECEDENCE, LOWEST_PRECEDENCE
Constructor and Description |
---|
ScriptFactoryPostProcessor() |
Modifier and Type | Method and Description |
---|---|
protected ScriptSource |
convertToScriptSource(java.lang.String beanName,
java.lang.String scriptSourceLocator,
ResourceLoader resourceLoader)
Convert the given script source locator to a ScriptSource instance.
|
protected java.lang.Class<?> |
createCompositeInterface(java.lang.Class<?>[] interfaces)
Create a composite interface Class for the given interfaces,
implementing the given interfaces in one single Class.
|
protected java.lang.Class<?> |
createConfigInterface(BeanDefinition bd,
java.lang.Class<?>[] interfaces)
Create a config interface for the given bean definition, defining setter
methods for the defined property values as well as an init method and
a destroy method (if defined).
|
protected java.lang.Object |
createRefreshableProxy(TargetSource ts,
java.lang.Class<?>[] interfaces,
boolean proxyTargetClass)
Create a refreshable proxy for the given AOP TargetSource.
|
protected BeanDefinition |
createScriptedObjectBeanDefinition(BeanDefinition bd,
java.lang.String scriptFactoryBeanName,
ScriptSource scriptSource,
java.lang.Class<?>[] interfaces)
Create a bean definition for the scripted object, based on the given script
definition, extracting the definition data that is relevant for the scripted
object (that is, everything but bean class and constructor arguments).
|
protected BeanDefinition |
createScriptFactoryBeanDefinition(BeanDefinition bd)
Create a ScriptFactory bean definition based on the given script definition,
extracting only the definition data that is relevant for the ScriptFactory
(that is, only bean class and constructor arguments).
|
void |
destroy()
Destroy the inner bean factory (used for scripts) on shutdown.
|
int |
getOrder()
Get the order value of this object.
|
protected ScriptSource |
getScriptSource(java.lang.String beanName,
java.lang.String scriptSourceLocator)
Obtain a ScriptSource for the given bean, lazily creating it
if not cached already.
|
java.lang.Object |
postProcessBeforeInstantiation(java.lang.Class<?> beanClass,
java.lang.String beanName)
Apply this BeanPostProcessor before the target bean gets instantiated.
|
PropertyValues |
postProcessProperties(PropertyValues pvs,
java.lang.Object bean,
java.lang.String beanName)
Post-process the given property values before the factory applies them
to the given bean, without any need for property descriptors.
|
java.lang.Class<?> |
predictBeanType(java.lang.Class<?> beanClass,
java.lang.String beanName)
Predict the type of the bean to be eventually returned from this
processor's
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(java.lang.Class<?>, java.lang.String) callback. |
protected void |
prepareScriptBeans(BeanDefinition bd,
java.lang.String scriptFactoryBeanName,
java.lang.String scriptedObjectBeanName)
Prepare the script beans in the internal BeanFactory that this
post-processor uses.
|
protected boolean |
resolveProxyTargetClass(BeanDefinition beanDefinition) |
protected long |
resolveRefreshCheckDelay(BeanDefinition beanDefinition)
Get the refresh check delay for the given
ScriptFactory BeanDefinition . |
void |
setBeanClassLoader(java.lang.ClassLoader classLoader)
Callback that supplies the bean
class loader to
a bean instance. |
void |
setBeanFactory(BeanFactory beanFactory)
Callback that supplies the owning factory to a bean instance.
|
void |
setDefaultProxyTargetClass(boolean defaultProxyTargetClass)
Flag to signal that refreshable proxies should be created to proxy the target class not its interfaces.
|
void |
setDefaultRefreshCheckDelay(long defaultRefreshCheckDelay)
Set the delay between refresh checks, in milliseconds.
|
void |
setResourceLoader(ResourceLoader resourceLoader)
Set the ResourceLoader that this object runs in.
|
determineCandidateConstructors, getEarlyBeanReference, postProcessAfterInitialization, postProcessAfterInstantiation, postProcessBeforeInitialization, postProcessPropertyValues
public static final java.lang.String INLINE_SCRIPT_PREFIX
Resource
-style prefix that denotes
an inline script.
An inline script is a script that is defined right there in the (typically XML) configuration, as opposed to being defined in an external file.
public static final java.lang.String REFRESH_CHECK_DELAY_ATTRIBUTE
refreshCheckDelay
attribute.public static final java.lang.String PROXY_TARGET_CLASS_ATTRIBUTE
proxyTargetClass
attribute.public static final java.lang.String LANGUAGE_ATTRIBUTE
language
attribute.private static final java.lang.String SCRIPT_FACTORY_NAME_PREFIX
private static final java.lang.String SCRIPTED_OBJECT_NAME_PREFIX
protected final Log logger
private long defaultRefreshCheckDelay
private boolean defaultProxyTargetClass
@Nullable private java.lang.ClassLoader beanClassLoader
@Nullable private ConfigurableBeanFactory beanFactory
private ResourceLoader resourceLoader
final DefaultListableBeanFactory scriptBeanFactory
private final java.util.Map<java.lang.String,ScriptSource> scriptSourceCache
public void setDefaultRefreshCheckDelay(long defaultRefreshCheckDelay)
Note that an actual refresh will only happen when
the ScriptSource
indicates
that it has been modified.
ScriptSource.isModified()
public void setDefaultProxyTargetClass(boolean defaultProxyTargetClass)
defaultProxyTargetClass
- the flag value to setpublic void setBeanClassLoader(java.lang.ClassLoader classLoader)
BeanClassLoaderAware
class loader
to
a bean instance.
Invoked after the population of normal bean properties but
before an initialization callback such as
InitializingBean's
InitializingBean.afterPropertiesSet()
method or a custom init-method.
setBeanClassLoader
in interface BeanClassLoaderAware
classLoader
- the owning class loaderpublic void setBeanFactory(BeanFactory beanFactory)
BeanFactoryAware
Invoked after the population of normal bean properties
but before an initialization callback such as
InitializingBean.afterPropertiesSet()
or a custom init-method.
setBeanFactory
in interface BeanFactoryAware
beanFactory
- owning BeanFactory (never null
).
The bean can immediately call methods on the factory.BeanInitializationException
public void setResourceLoader(ResourceLoader resourceLoader)
ResourceLoaderAware
This might be a ResourcePatternResolver, which can be checked
through instanceof ResourcePatternResolver
. See also the
ResourcePatternUtils.getResourcePatternResolver
method.
Invoked after population of normal bean properties but before an init callback
like InitializingBean's afterPropertiesSet
or a custom init-method.
Invoked before ApplicationContextAware's setApplicationContext
.
setResourceLoader
in interface ResourceLoaderAware
resourceLoader
- the ResourceLoader object to be used by this objectResourcePatternResolver
,
ResourcePatternUtils.getResourcePatternResolver(org.springframework.core.io.ResourceLoader)
public int getOrder()
Ordered
Higher values are interpreted as lower priority. As a consequence,
the object with the lowest value has the highest priority (somewhat
analogous to Servlet load-on-startup
values).
Same order values will result in arbitrary sort positions for the affected objects.
getOrder
in interface Ordered
Ordered.HIGHEST_PRECEDENCE
,
Ordered.LOWEST_PRECEDENCE
@Nullable public java.lang.Class<?> predictBeanType(java.lang.Class<?> beanClass, java.lang.String beanName)
SmartInstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(java.lang.Class<?>, java.lang.String)
callback.
The default implementation returns null
.
predictBeanType
in interface SmartInstantiationAwareBeanPostProcessor
predictBeanType
in class InstantiationAwareBeanPostProcessorAdapter
beanClass
- the raw class of the beanbeanName
- the name of the beannull
if not predictablepublic PropertyValues postProcessProperties(PropertyValues pvs, java.lang.Object bean, java.lang.String beanName)
InstantiationAwareBeanPostProcessor
Implementations should return null
(the default) if they provide a custom
InstantiationAwareBeanPostProcessor.postProcessPropertyValues(org.springframework.beans.PropertyValues, java.beans.PropertyDescriptor[], java.lang.Object, java.lang.String)
implementation, and pvs
otherwise.
In a future version of this interface (with InstantiationAwareBeanPostProcessor.postProcessPropertyValues(org.springframework.beans.PropertyValues, java.beans.PropertyDescriptor[], java.lang.Object, java.lang.String)
removed),
the default implementation will return the given pvs
as-is directly.
postProcessProperties
in interface InstantiationAwareBeanPostProcessor
postProcessProperties
in class InstantiationAwareBeanPostProcessorAdapter
pvs
- the property values that the factory is about to apply (never null
)bean
- the bean instance created, but whose properties have not yet been setbeanName
- the name of the beannull
which proceeds with the existing properties
but specifically continues with a call to InstantiationAwareBeanPostProcessor.postProcessPropertyValues(org.springframework.beans.PropertyValues, java.beans.PropertyDescriptor[], java.lang.Object, java.lang.String)
(requiring initialized PropertyDescriptor
s for the current bean class)InstantiationAwareBeanPostProcessor.postProcessPropertyValues(org.springframework.beans.PropertyValues, java.beans.PropertyDescriptor[], java.lang.Object, java.lang.String)
public java.lang.Object postProcessBeforeInstantiation(java.lang.Class<?> beanClass, java.lang.String beanName)
InstantiationAwareBeanPostProcessor
If a non-null object is returned by this method, the bean creation process
will be short-circuited. The only further processing applied is the
BeanPostProcessor.postProcessAfterInitialization(java.lang.Object, java.lang.String)
callback from the configured
BeanPostProcessors
.
This callback will only be applied to bean definitions with a bean class. In particular, it will not be applied to beans with a factory method.
Post-processors may implement the extended
SmartInstantiationAwareBeanPostProcessor
interface in order
to predict the type of the bean object that they are going to return here.
The default implementation returns null
.
postProcessBeforeInstantiation
in interface InstantiationAwareBeanPostProcessor
postProcessBeforeInstantiation
in class InstantiationAwareBeanPostProcessorAdapter
beanClass
- the class of the bean to be instantiatedbeanName
- the name of the beannull
to proceed with default instantiationInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(java.lang.Object, java.lang.String)
,
AbstractBeanDefinition.hasBeanClass()
protected void prepareScriptBeans(BeanDefinition bd, java.lang.String scriptFactoryBeanName, java.lang.String scriptedObjectBeanName)
bd
- the original bean definition in the main BeanFactoryscriptFactoryBeanName
- the name of the internal ScriptFactory beanscriptedObjectBeanName
- the name of the internal scripted object beanprotected long resolveRefreshCheckDelay(BeanDefinition beanDefinition)
ScriptFactory
BeanDefinition
.
If the BeanDefinition
has a
metadata attribute
under the key REFRESH_CHECK_DELAY_ATTRIBUTE
which is a valid Number
type, then this value is used. Otherwise, the defaultRefreshCheckDelay
value is used.beanDefinition
- the BeanDefinition to checkprotected boolean resolveProxyTargetClass(BeanDefinition beanDefinition)
protected BeanDefinition createScriptFactoryBeanDefinition(BeanDefinition bd)
bd
- the full script bean definitionScriptFactory
protected ScriptSource getScriptSource(java.lang.String beanName, java.lang.String scriptSourceLocator)
beanName
- the name of the scripted beanscriptSourceLocator
- the script source locator associated with the beanconvertToScriptSource(java.lang.String, java.lang.String, org.springframework.core.io.ResourceLoader)
protected ScriptSource convertToScriptSource(java.lang.String beanName, java.lang.String scriptSourceLocator, ResourceLoader resourceLoader)
By default, supported locators are Spring resource locations (such as "file:C:/myScript.bsh" or "classpath:myPackage/myScript.bsh") and inline scripts ("inline:myScriptText...").
beanName
- the name of the scripted beanscriptSourceLocator
- the script source locatorresourceLoader
- the ResourceLoader to use (if necessary)protected java.lang.Class<?> createConfigInterface(BeanDefinition bd, @Nullable java.lang.Class<?>[] interfaces)
This implementation creates the interface via CGLIB's InterfaceMaker, determining the property types from the given interfaces (as far as possible).
bd
- the bean definition (property values etc) to create a
config interface forinterfaces
- the interfaces to check against (might define
getters corresponding to the setters we're supposed to generate)org.springframework.cglib.proxy.InterfaceMaker
,
BeanUtils.findPropertyType(java.lang.String, java.lang.Class<?>...)
protected java.lang.Class<?> createCompositeInterface(java.lang.Class<?>[] interfaces)
The default implementation builds a JDK proxy class for the given interfaces.
interfaces
- the interfaces to mergeProxy.getProxyClass(java.lang.ClassLoader, java.lang.Class<?>...)
protected BeanDefinition createScriptedObjectBeanDefinition(BeanDefinition bd, java.lang.String scriptFactoryBeanName, ScriptSource scriptSource, @Nullable java.lang.Class<?>[] interfaces)
bd
- the full script bean definitionscriptFactoryBeanName
- the name of the internal ScriptFactory beanscriptSource
- the ScriptSource for the scripted beaninterfaces
- the interfaces that the scripted bean is supposed to implementScriptFactory.getScriptedObject(org.springframework.scripting.ScriptSource, java.lang.Class<?>...)
protected java.lang.Object createRefreshableProxy(TargetSource ts, @Nullable java.lang.Class<?>[] interfaces, boolean proxyTargetClass)
ts
- the refreshable TargetSourceinterfaces
- the proxy interfaces (may be null
to
indicate proxying of all interfaces implemented by the target class)RefreshableScriptTargetSource
public void destroy()
destroy
in interface DisposableBean