scriptfactorypostprocessor.java
来自「有关此类编程有心德的高手 希望能够多多给予指教」· Java 代码 · 共 512 行 · 第 1/2 页
JAVA
512 行
}
}
public Object postProcessBeforeInstantiation(Class beanClass, String beanName) {
// We only apply special treatment to ScriptFactory implementations here.
if (!ScriptFactory.class.isAssignableFrom(beanClass)) {
return null;
}
RootBeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName);
String scriptFactoryBeanName = SCRIPT_FACTORY_NAME_PREFIX + beanName;
String scriptedObjectBeanName = SCRIPTED_OBJECT_NAME_PREFIX + beanName;
prepareScriptBeans(bd, scriptFactoryBeanName, scriptedObjectBeanName);
long refreshCheckDelay = resolveRefreshCheckDelay(bd);
if (refreshCheckDelay >= 0) {
ScriptFactory scriptFactory =
(ScriptFactory) this.scriptBeanFactory.getBean(scriptFactoryBeanName, ScriptFactory.class);
ScriptSource scriptSource =
getScriptSource(scriptFactoryBeanName, scriptFactory.getScriptSourceLocator());
Class[] interfaces = scriptFactory.getScriptInterfaces();
RefreshableScriptTargetSource ts =
new RefreshableScriptTargetSource(this.scriptBeanFactory, scriptedObjectBeanName, scriptSource);
ts.setRefreshCheckDelay(refreshCheckDelay);
return createRefreshableProxy(ts, interfaces);
}
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
* into a ScriptFactory definition and a scripted object definition.
* @param bd the original bean definition in the main BeanFactory
* @param scriptFactoryBeanName the name of the internal ScriptFactory bean
* @param scriptedObjectBeanName the name of the internal scripted object bean
*/
protected void prepareScriptBeans(
RootBeanDefinition 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 =
(ScriptFactory) this.scriptBeanFactory.getBean(scriptFactoryBeanName, ScriptFactory.class);
ScriptSource scriptSource =
getScriptSource(scriptFactoryBeanName, scriptFactory.getScriptSourceLocator());
Class[] interfaces = scriptFactory.getScriptInterfaces();
Class[] scriptedInterfaces = interfaces;
if (scriptFactory.requiresConfigInterface() && !bd.getPropertyValues().isEmpty()) {
Class configInterface = createConfigInterface(bd, interfaces);
scriptedInterfaces = (Class[]) ObjectUtils.addObjectToArray(interfaces, configInterface);
}
RootBeanDefinition objectBd = createScriptedObjectBeanDefinition(
bd, scriptFactoryBeanName, scriptSource, scriptedInterfaces);
long refreshCheckDelay = resolveRefreshCheckDelay(bd);
if (refreshCheckDelay >= 0) {
objectBd.setSingleton(false);
}
this.scriptBeanFactory.registerBeanDefinition(scriptedObjectBeanName, objectBd);
}
}
}
/**
* 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.
* @param beanDefinition the BeanDefinition to check
* @return the refresh check delay
*/
protected long resolveRefreshCheckDelay(BeanDefinition beanDefinition) {
long refreshCheckDelay = this.defaultRefreshCheckDelay;
Object attributeValue = beanDefinition.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();
scriptBd.setBeanClassName(bd.getBeanClassName());
scriptBd.getConstructorArgumentValues().addArgumentValues(bd.getConstructorArgumentValues());
return scriptBd;
}
/**
* Obtain a ScriptSource for the given bean, lazily creating it
* if not cached already.
* @param beanName the name of the scripted bean
* @param scriptSourceLocator the script source locator associated with the bean
* @return the corresponding ScriptSource instance
* @see #convertToScriptSource
*/
protected ScriptSource getScriptSource(String beanName, String scriptSourceLocator) {
synchronized (this.scriptSourceCache) {
ScriptSource scriptSource = (ScriptSource) this.scriptSourceCache.get(beanName);
if (scriptSource == null) {
scriptSource = convertToScriptSource(scriptSourceLocator, this.resourceLoader);
this.scriptSourceCache.put(beanName, scriptSource);
}
return scriptSource;
}
}
/**
* 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 definition, defining setter
* methods for the defined property values as well as an init method and
* a destroy method (if defined).
* <p>This implementation creates the interface via CGLIB's InterfaceMaker,
* determining the property types from the given interfaces (as far as possible).
* @param bd the bean definition (property values etc) 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(RootBeanDefinition bd, Class[] interfaces) {
InterfaceMaker maker = new InterfaceMaker();
PropertyValue[] pvs = bd.getPropertyValues().getPropertyValues();
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]);
}
if (bd.getInitMethodName() != null) {
Signature signature = new Signature(bd.getInitMethodName(), Type.VOID_TYPE, new Type[0]);
maker.add(signature, new Type[0]);
}
if (bd.getDestroyMethodName() != null) {
Signature signature = new Signature(bd.getDestroyMethodName(), Type.VOID_TYPE, new Type[0]);
maker.add(signature, new Type[0]);
}
return maker.create();
}
/**
* Create a composite interface Class for the given interfaces,
* implementing the given interfaces in one single Class.
* <p>The default implementation builds a JDK proxy class
* for the given interfaces.
* @param interfaces the interfaces to merge
* @return the merged interface as Class
* @see java.lang.reflect.Proxy#getProxyClass
*/
protected Class createCompositeInterface(Class[] interfaces) {
return ClassUtils.createCompositeInterface(interfaces, this.beanClassLoader);
}
/**
* 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
* @param scriptFactoryBeanName the name of the internal ScriptFactory bean
* @param scriptSource the ScriptSource for the scripted bean
* @param interfaces the interfaces that the scripted bean is supposed to implement
* @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.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(this.beanClassLoader);
}
/**
* Destroy the inner bean factory (used for scripts) on shutdown.
*/
public void destroy() {
this.scriptBeanFactory.destroySingletons();
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?