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 + -
显示快捷键?