⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 servicelocatorfactorybean.java

📁 spring api 源代码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
	 * Set the exception class that the service locator should throw if service
	 * lookup failed. The specified exception class must have a constructor
	 * with one of the following parameter types: <code>(String, Throwable)</code>
	 * or <code>(Throwable)</code> or <code>(String)</code>.
	 * <p>If not specified, subclasses of Spring's BeansException will be thrown,
	 * for example NoSuchBeanDefinitionException. As those are unchecked, the
	 * caller does not need to handle them, so it might be acceptable that
	 * Spring exceptions get thrown as long as they are just handled generically.
	 * @see #determineServiceLocatorExceptionConstructor(Class)
	 * @see #createServiceLocatorException(java.lang.reflect.Constructor, org.springframework.beans.BeansException)
	 * @see org.springframework.beans.BeansException
	 * @see org.springframework.beans.factory.NoSuchBeanDefinitionException
	 */
	public void setServiceLocatorExceptionClass(Class serviceLocatorExceptionClass) {
		if (serviceLocatorExceptionClass != null && !Exception.class.isAssignableFrom(serviceLocatorExceptionClass)) {
			throw new IllegalArgumentException(
					"serviceLocatorException [" + serviceLocatorExceptionClass.getName() + "] is not a subclass of Exception");
		}
		this.serviceLocatorExceptionConstructor =
				determineServiceLocatorExceptionConstructor(serviceLocatorExceptionClass);
	}

	/**
	 * Set mappings between service ids (passed into the service locator)
	 * and bean names (in the bean factory). Service ids that are not defined
	 * here will be treated as bean names as-is.
	 * <p>The empty string as service id key defines the mapping for <code>null</code> and
	 * empty string, and for factory methods without parameter. If not defined,
	 * a single matching bean will be retrieved from the bean factory.
	 * @param serviceMappings mappings between service ids and bean names,
	 * with service ids as keys as bean names as values
	 */
	public void setServiceMappings(Properties serviceMappings) {
		this.serviceMappings = serviceMappings;
	}

	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		if (!(beanFactory instanceof ListableBeanFactory)) {
			throw new FatalBeanException(
					"ServiceLocatorFactoryBean needs to run in a BeanFactory that is a ListableBeanFactory");
		}
		this.beanFactory = (ListableBeanFactory) beanFactory;
	}

	public void afterPropertiesSet() {
		if (this.serviceLocatorInterface == null) {
			throw new IllegalArgumentException("serviceLocatorInterface is required");
		}

		// Create service locator proxy.
		this.proxy = Proxy.newProxyInstance(
				this.serviceLocatorInterface.getClassLoader(),
				new Class[] {this.serviceLocatorInterface},
				new ServiceLocatorInvocationHandler());
	}


	/**
	 * Determine the constructor to use for the given service locator exception
	 * class. Only called in case of a custom service locator exception.
	 * <p>The default implementation looks for a constructor with one of the
	 * following parameter types: <code>(String, Throwable)</code>
	 * or <code>(Throwable)</code> or <code>(String)</code>.
	 * @param exceptionClass the exception class
	 * @return the constructor to use
	 * @see #setServiceLocatorExceptionClass
	 */
	protected Constructor determineServiceLocatorExceptionConstructor(Class exceptionClass) {
		try {
			return exceptionClass.getConstructor(new Class[] {String.class, Throwable.class});
		}
		catch (NoSuchMethodException ex) {
			try {
				return exceptionClass.getConstructor(new Class[] {Throwable.class});
			}
			catch (NoSuchMethodException ex2) {
				try {
					return exceptionClass.getConstructor(new Class[] {String.class});
				}
				catch (NoSuchMethodException ex3) {
					throw new IllegalArgumentException(
							"serviceLocatorException [" + exceptionClass.getName() +
							"] neither has a (String, Throwable) constructor nor a (String) constructor");
				}
			}
		}
	}

	/**
	 * Create a service locator exception for the given cause.
	 * Only called in case of a custom service locator exception.
	 * <p>The default implementation can handle all variations of
	 * message and exception arguments.
	 * @param exceptionConstructor the constructor to use
	 * @param cause the cause of the service lookup failure
	 * @return the service locator exception to throw
	 * @see #setServiceLocatorExceptionClass
	 */
	protected Exception createServiceLocatorException(Constructor exceptionConstructor, BeansException cause) {
		Class[] paramTypes = exceptionConstructor.getParameterTypes();
		Object[] args = new Object[paramTypes.length];
		for (int i = 0; i < paramTypes.length; i++) {
			if (paramTypes[i].equals(String.class)) {
				args[i] = cause.getMessage();
			}
			else if (paramTypes[i].isInstance(cause)) {
				args[i] = cause;
			}
		}
		return (Exception) BeanUtils.instantiateClass(exceptionConstructor, args);
	}


	public Object getObject() {
		return this.proxy;
	}

	public Class getObjectType() {
		return this.serviceLocatorInterface;
	}

	public boolean isSingleton() {
		return true;
	}


	/**
	 * Invocation handler that delegates service locator calls to the bean factory.
	 */
	private class ServiceLocatorInvocationHandler implements InvocationHandler {

		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object service;
            if (Object.class.equals(method.getDeclaringClass())) {
                service = invokeStandardObjectMethod(method, args);
            } else {
                service = invokeServiceLocatorMethod(method, args);
            }
            return service;
        }

        public String toString() {
            return "Service locator: " + serviceLocatorInterface.getName();
        }


        private Object invokeServiceLocatorMethod(Method method, Object[] args) throws Exception {
            Class serviceLocatorMethodReturnType = getServiceLocatorMethodReturnType(method);
            try {
                String beanName = tryGetBeanName(args);
                if (StringUtils.hasLength(beanName)) {
                    // Service locator for a specific bean name.
                    return beanFactory.getBean(beanName, serviceLocatorMethodReturnType);
                }
                else {
                    // Service locator for a bean type.
                    return BeanFactoryUtils.beanOfTypeIncludingAncestors(beanFactory, serviceLocatorMethodReturnType);
                }
            }
            catch (BeansException ex) {
                if (serviceLocatorExceptionConstructor != null) {
                    throw createServiceLocatorException(serviceLocatorExceptionConstructor, ex);
                }
                throw ex;
            }
        }

        /**
         * Check whether a service id was passed in.
         */
        private String tryGetBeanName(Object[] args) {
            String beanName = "";
            if (args != null && args.length == 1 && args[0] != null) {
                beanName = args[0].toString();
            }
            // Look for explicit serviceId-to-beanName mappings.
            if (serviceMappings != null) {
                String mappedName = serviceMappings.getProperty(beanName);
                if (mappedName != null) {
                    beanName = mappedName;
                }
            }
            return beanName;
        }

        private Class getServiceLocatorMethodReturnType(Method method) throws NoSuchMethodException {
            Class[] paramTypes = method.getParameterTypes();
            Method interfaceMethod = serviceLocatorInterface.getMethod(method.getName(), paramTypes);
            Class serviceLocatorReturnType = interfaceMethod.getReturnType();

            // Check whether the method is a valid service locator.
            if (paramTypes.length > 1 || void.class.equals(serviceLocatorReturnType)) {
                throw new UnsupportedOperationException(
                        "May only call methods with signature '<type> xxx()' or '<type> xxx(<idtype> id)' " +
                        "on factory interface, but tried to call: " + interfaceMethod);
            }
            return serviceLocatorReturnType;
        }

        /**
         * It's normal to get here for non service locator interface method calls
         *(toString, equals, etc.). Simply apply the call to the invocation handler object.
         */
        private Object invokeStandardObjectMethod(Method method, Object[] args) throws Throwable {
            try {
                return method.invoke(this, args);
            }
            catch (InvocationTargetException invEx) {
                throw invEx.getTargetException();
            }
        }

    }

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -