📄 scriptfactorypostprocessor.java
字号:
public Object postProcessBeforeInstantiation(Class beanClass, String beanName) {
// We only apply special treatment to ScriptFactory implementations here.
if (!ScriptFactory.class.isAssignableFrom(beanClass)) {
return null;
}
String scriptedObjectBeanName = SCRIPTED_OBJECT_NAME_PREFIX + beanName;
// Avoid recreation of the script bean definition in case of a prototype.
if (!this.scriptBeanFactory.containsBeanDefinition(scriptedObjectBeanName)) {
RootBeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName);
String scriptFactoryBeanName = SCRIPT_FACTORY_NAME_PREFIX + beanName;
this.scriptBeanFactory.registerBeanDefinition(
scriptFactoryBeanName, createScriptFactoryBeanDefinition(bd));
ScriptFactory scriptFactory =
(ScriptFactory) this.scriptBeanFactory.getBean(scriptFactoryBeanName, ScriptFactory.class);
ScriptSource scriptSource =
convertToScriptSource(scriptFactory.getScriptSourceLocator(), this.resourceLoader);
Class[] interfaces = scriptFactory.getScriptInterfaces();
if (scriptFactory.requiresConfigInterface() && !bd.getPropertyValues().isEmpty()) {
PropertyValue[] pvs = bd.getPropertyValues().getPropertyValues();
Class configInterface = createConfigInterface(pvs, interfaces);
interfaces = (Class[]) ObjectUtils.addObjectToArray(interfaces, configInterface);
}
RootBeanDefinition objectBd = createScriptedObjectBeanDefinition(
bd, scriptFactoryBeanName, scriptSource, interfaces);
long refreshCheckDelay = resolveRefreshCheckDelay(bd);
if (refreshCheckDelay >= 0) {
objectBd.setSingleton(false);
}
this.scriptBeanFactory.registerBeanDefinition(scriptedObjectBeanName, objectBd);
if (refreshCheckDelay >= 0) {
RefreshableScriptTargetSource ts =
new RefreshableScriptTargetSource(this.scriptBeanFactory, scriptedObjectBeanName, scriptSource);
ts.setRefreshCheckDelay(refreshCheckDelay);
return createRefreshableProxy(ts, interfaces);
}
}
return this.scriptBeanFactory.getBean(scriptedObjectBeanName);
}
/**
* Get the refresh check delay for the given {@link ScriptFactory} {@link BeanDefinition}.
* If the {@link BeanDefinition} has a
* {@link org.springframework.core.AttributeAccessor metadata attribute}
* under the key {@link #REFRESH_CHECK_DELAY_ATTRIBUTE} which is a valid {@link Number}
* type, then this value is used. Otherwise, the the {@link #defaultRefreshCheckDelay}
* value is used.
* @return the refresh check delay
*/
protected long resolveRefreshCheckDelay(BeanDefinition bd) {
long refreshCheckDelay = this.defaultRefreshCheckDelay;
Object attributeValue = bd.getAttribute(REFRESH_CHECK_DELAY_ATTRIBUTE);
if (attributeValue instanceof Number) {
refreshCheckDelay = ((Number) attributeValue).longValue();
}
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");
}
return refreshCheckDelay;
}
/**
* 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).
* @param bd the full script bean definition
* @return the extracted ScriptFactory bean definition
* @see org.springframework.scripting.ScriptFactory
*/
protected RootBeanDefinition createScriptFactoryBeanDefinition(RootBeanDefinition bd) {
RootBeanDefinition scriptBd = new RootBeanDefinition(bd.getBeanClass());
scriptBd.getConstructorArgumentValues().addArgumentValues(bd.getConstructorArgumentValues());
return scriptBd;
}
/**
* Convert the given script source locator to a ScriptSource instance.
* <p>By default, supported locators are Spring resource locations
* (such as "file:C:/myScript.bsh" or "classpath:myPackage/myScript.bsh")
* and inline scripts ("inline:myScriptText...").
* @param scriptSourceLocator the script source locator
* @param resourceLoader the ResourceLoader to use (if necessary)
* @return the ScriptSource instance
*/
protected ScriptSource convertToScriptSource(String scriptSourceLocator, ResourceLoader resourceLoader) {
if (scriptSourceLocator.startsWith(INLINE_SCRIPT_PREFIX)) {
return new StaticScriptSource(scriptSourceLocator.substring(INLINE_SCRIPT_PREFIX.length()));
}
else {
return new ResourceScriptSource(resourceLoader.getResource(scriptSourceLocator));
}
}
/**
* Create a config interface for the given bean property values.
* <p>This implementation creates the interface via CGLIB's InterfaceMaker,
* determining the property types from the given interfaces (as far as possible).
* @param pvs the bean property values to create a config interface for
* @param interfaces the interfaces to check against (might define
* getters corresponding to the setters we're supposed to generate)
* @return the config interface
* @see net.sf.cglib.proxy.InterfaceMaker
* @see org.springframework.beans.BeanUtils#findPropertyType
*/
protected Class createConfigInterface(PropertyValue[] pvs, Class[] interfaces) {
Assert.notEmpty(pvs, "Property values must not be empty");
InterfaceMaker maker = new InterfaceMaker();
for (int i = 0; i < pvs.length; i++) {
String propertyName = pvs[i].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)});
maker.add(signature, new Type[0]);
}
return maker.create();
}
/**
* 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).
* @param bd the full script bean definition
* @return the extracted ScriptFactory bean definition
* @see org.springframework.scripting.ScriptFactory#getScriptedObject
*/
protected RootBeanDefinition createScriptedObjectBeanDefinition(
RootBeanDefinition bd, String scriptFactoryBeanName, ScriptSource scriptSource, Class[] interfaces) {
RootBeanDefinition objectBd = new RootBeanDefinition(bd);
objectBd.setBeanClass(null);
objectBd.setFactoryBeanName(scriptFactoryBeanName);
objectBd.setFactoryMethodName("getScriptedObject");
objectBd.getConstructorArgumentValues().clear();
objectBd.getConstructorArgumentValues().addIndexedArgumentValue(0, scriptSource);
objectBd.getConstructorArgumentValues().addIndexedArgumentValue(1, interfaces);
return objectBd;
}
/**
* Create a refreshable proxy for the given AOP TargetSource.
* @param ts the refreshable TargetSource
* @param interfaces the proxy interfaces (may be <code>null</code> to
* indicate proxying of all interfaces implemented by the target class)
* @return the generated proxy
* @see RefreshableScriptTargetSource
*/
protected Object createRefreshableProxy(TargetSource ts, Class[] interfaces) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTargetSource(ts);
if (interfaces == null) {
interfaces = ClassUtils.getAllInterfacesForClass(ts.getTargetClass());
}
proxyFactory.setInterfaces(interfaces);
DelegatingIntroductionInterceptor introduction = new DelegatingIntroductionInterceptor(ts);
introduction.suppressInterface(TargetSource.class);
proxyFactory.addAdvice(introduction);
return proxyFactory.getProxy();
}
/**
* Destroy the inner bean factory (used for scripts) on shutdown.
*/
public void destroy() {
this.scriptBeanFactory.destroySingletons();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -