Sping Bean 查找异常

本文内容如有错误、不足之处,欢迎技术爱好者们一同探讨,在本文下面讨论区留言,感谢。

简介

Spring 在对 Bean 进行依赖查找过程中,经常碰到一些异常,通过针对这些异常的发生场景,可以加深对 Spring 框架的理解和学习。

异常清单
异常类型触发条件场景举例
NoSuchBeanDefinitionExceptionBean 不存在 IoC 容器内BeanFactory#getBean ObjectFactory#getObject
NoUniqueBeanDefinitionException类型依赖查找时,IoC 容器存在多个 Bean 实例BeanFactory#getBean(Class)
BeanInstantiationException当 Bean 所对应的类型非具体类时BeanFactory#getBean
BeanCreationException当 Bean 初始化过程中Bean 初始化方法执行异常 时
BeanDefinitionStoreException当 BeanDefinition 配置元信息非法 时XML 配置资源无法打开时
异常介绍
NoSuchBeanDefinitionException

没有对应 Bean 的定义异常

public class NoSuchBeanDefinitionException extends BeansException {
	@Nullable
	private final String beanName;

	@Nullable
	private final ResolvableType resolvableType;

	public NoSuchBeanDefinitionException(String name) {
		super("No bean named '" + name + "' available");
		this.beanName = name;
		this.resolvableType = null;
	}

	public NoSuchBeanDefinitionException(String name, String message) {
		super("No bean named '" + name + "' available: " + message);
		this.beanName = name;
		this.resolvableType = null;
	}

	public NoSuchBeanDefinitionException(Class<?> type) {
		this(ResolvableType.forClass(type));
	}

	public NoSuchBeanDefinitionException(Class<?> type, String message) {
		this(ResolvableType.forClass(type), message);
	}

	public NoSuchBeanDefinitionException(ResolvableType type) {
		super("No qualifying bean of type '" + type + "' available");
		this.beanName = null;
		this.resolvableType = type;
	}

	public NoSuchBeanDefinitionException(ResolvableType type, String message) {
		super("No qualifying bean of type '" + type + "' available: " + message);
		this.beanName = null;
		this.resolvableType = type;
	}


	@Nullable
	public String getBeanName() {
		return this.beanName;
	}

	@Nullable
	public Class<?> getBeanType() {
		return (this.resolvableType != null ? this.resolvableType.resolve() : null);
	}

	@Nullable
	public ResolvableType getResolvableType() {
		return this.resolvableType;
	}

	public int getNumberOfBeansFound() {
		return 0;
	}

}

通过源码可以发现,此异常继承 BeansExpectionResolvableType 类承担了大部分功能,通过类名可以初步判断 ResolvableType 功能是,获取 Bean 的类型。事实上 ResolvableType 是封装 JavaType 类,可以根据自身、方法来获取类型。说白了就是可以让使用者在任何时候通过任何方法知道自身身处何地。

触发条件:当应用需要找这么一个 Bean 从容器中,找不到时,容器将会抛出此异常。这里有两种方式查找,通过名称和通过类型查找。

NoUniqueBeanDefinitionException

存在不唯一的 Bean 定义异常

NoUniqueBeanDefinitionException 继承 NoSuchBeanDefinitionException

public class NoUniqueBeanDefinitionException extends NoSuchBeanDefinitionException {

	private final int numberOfBeansFound;

	@Nullable
	private final Collection<String> beanNamesFound;

	public NoUniqueBeanDefinitionException(Class<?> type, int numberOfBeansFound, String message) {
		super(type, message);
		this.numberOfBeansFound = numberOfBeansFound;
		this.beanNamesFound = null;
	}

	public NoUniqueBeanDefinitionException(Class<?> type, Collection<String> beanNamesFound) {
		super(type, "expected single matching bean but found " + beanNamesFound.size() + ": " +
				StringUtils.collectionToCommaDelimitedString(beanNamesFound));
		this.numberOfBeansFound = beanNamesFound.size();
		this.beanNamesFound = beanNamesFound;
	}

	public NoUniqueBeanDefinitionException(Class<?> type, String... beanNamesFound) {
		this(type, Arrays.asList(beanNamesFound));
	}

	public NoUniqueBeanDefinitionException(ResolvableType type, Collection<String> beanNamesFound) {
		super(type, "expected single matching bean but found " + beanNamesFound.size() + ": " +
				StringUtils.collectionToCommaDelimitedString(beanNamesFound));
		this.numberOfBeansFound = beanNamesFound.size();
		this.beanNamesFound = beanNamesFound;
	}

	public NoUniqueBeanDefinitionException(ResolvableType type, String... beanNamesFound) {
		this(type, Arrays.asList(beanNamesFound));
	}

	@Override
	public int getNumberOfBeansFound() {
		return this.numberOfBeansFound;
	}

	@Nullable
	public Collection<String> getBeanNamesFound() {
		return this.beanNamesFound;
	}

}

触发条件:通过类型去查找,如果在 IOC 容器中注入了多个相同类型的 BeanBeanDefinitionbeanName 不同,由于类型相同则会抛出此异常。例如:在 IOC 中注入多个 String 类型的 Bean , 有名叫“张三”的 Bean,有名叫“李四”的 Bean,此时通过 String 这个类型去容器中获取,则无法区分 “张三”,“李四”,解决办法就是在主要使用的 Bean 上,标注@primary

BeanInstantiationException

Bean 是一个非正常类(抽象类或接口)异常

public class BeanInstantiationException extends FatalBeanException {

	private final Class<?> beanClass;

	// 构造器,用来获取进行构造类的名称
	@Nullable
	private final Constructor<?> constructor;

	// 构造方法
	@Nullable
	private final Method constructingMethod;

	public BeanInstantiationException(Class<?> beanClass, String msg) {
		this(beanClass, msg, null);
	}

	public BeanInstantiationException(Class<?> beanClass, String msg, @Nullable Throwable cause) {
		super("Failed to instantiate [" + beanClass.getName() + "]: " + msg, cause);
		this.beanClass = beanClass;
		this.constructor = null;
		this.constructingMethod = null;
	}

	public BeanInstantiationException(Constructor<?> constructor, String msg, @Nullable Throwable cause) {
		super("Failed to instantiate [" + constructor.getDeclaringClass().getName() + "]: " + msg, cause);
		this.beanClass = constructor.getDeclaringClass();
		this.constructor = constructor;
		this.constructingMethod = null;
	}

	public BeanInstantiationException(Method constructingMethod, String msg, @Nullable Throwable cause) {
		super("Failed to instantiate [" + constructingMethod.getReturnType().getName() + "]: " + msg, cause);
		this.beanClass = constructingMethod.getReturnType();
		this.constructor = null;
		this.constructingMethod = constructingMethod;
	}

	public Class<?> getBeanClass() {
		return this.beanClass;
	}

	@Nullable
	public Constructor<?> getConstructor() {
		return this.constructor;
	}

	@Nullable
	public Method getConstructingMethod() {
		return this.constructingMethod;
	}

}

触发条件:试图通过抽象类或接口进行注入时。

BeanCreationException

创建异常,创建过程中出现的异常

public class BeanCreationException extends FatalBeanException {

	@Nullable
	private final String beanName;

	// 资源说明,用来说明具体异常导致的原因
	@Nullable
	private final String resourceDescription;

	// 异常原因
	@Nullable
	private List<Throwable> relatedCauses;

	public BeanCreationException(String msg) {
		super(msg);
		this.beanName = null;
		this.resourceDescription = null;
	}

	public BeanCreationException(String msg, Throwable cause) {
		super(msg, cause);
		this.beanName = null;
		this.resourceDescription = null;
	}

	public BeanCreationException(String beanName, String msg) {
		super("Error creating bean with name '" + beanName + "': " + msg);
		this.beanName = beanName;
		this.resourceDescription = null;
	}

	public BeanCreationException(String beanName, String msg, Throwable cause) {
		this(beanName, msg);
		initCause(cause);
	}

	public BeanCreationException(@Nullable String resourceDescription, @Nullable String beanName, String msg) {
		super("Error creating bean with name '" + beanName + "'" +
				(resourceDescription != null ? " defined in " + resourceDescription : "") + ": " + msg);
		this.resourceDescription = resourceDescription;
		this.beanName = beanName;
		this.relatedCauses = null;
	}

	public BeanCreationException(@Nullable String resourceDescription, String beanName, String msg, Throwable cause) {
		this(resourceDescription, beanName, msg);
		initCause(cause);
	}

	@Nullable
	public String getResourceDescription() {
		return this.resourceDescription;
	}

	@Nullable
	public String getBeanName() {
		return this.beanName;
	}

	public void addRelatedCause(Throwable ex) {
		if (this.relatedCauses == null) {
			this.relatedCauses = new ArrayList<>();
		}
		this.relatedCauses.add(ex);
	}

	@Nullable
	public Throwable[] getRelatedCauses() {
		if (this.relatedCauses == null) {
			return null;
		}
		return this.relatedCauses.toArray(new Throwable[0]);
	}


	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder(super.toString());
		if (this.relatedCauses != null) {
			for (Throwable relatedCause : this.relatedCauses) {
				sb.append("\nRelated cause: ");
				sb.append(relatedCause);
			}
		}
		return sb.toString();
	}

	@Override
	public void printStackTrace(PrintStream ps) {
		synchronized (ps) {
			super.printStackTrace(ps);
			if (this.relatedCauses != null) {
				for (Throwable relatedCause : this.relatedCauses) {
					ps.println("Related cause:");
					relatedCause.printStackTrace(ps);
				}
			}
		}
	}

	@Override
	public void printStackTrace(PrintWriter pw) {
		synchronized (pw) {
			super.printStackTrace(pw);
			if (this.relatedCauses != null) {
				for (Throwable relatedCause : this.relatedCauses) {
					pw.println("Related cause:");
					relatedCause.printStackTrace(pw);
				}
			}
		}
	}

	@Override
	public boolean contains(@Nullable Class<?> exClass) {
		if (super.contains(exClass)) {
			return true;
		}
		if (this.relatedCauses != null) {
			for (Throwable relatedCause : this.relatedCauses) {
				if (relatedCause instanceof NestedRuntimeException &&
						((NestedRuntimeException) relatedCause).contains(exClass)) {
					return true;
				}
			}
		}
		return false;
	}
}

触发条件:创建过程失败,抛出此异常。例如:Bean 初始化失败时,将抛出此异常。

BeanDefinitionStoreException

BeanDefinition 元信息获取失败异常

public class BeanDefinitionStoreException extends FatalBeanException {

	@Nullable
	private final String resourceDescription;

	@Nullable
	private final String beanName;

	public BeanDefinitionStoreException(String msg) {
		super(msg);
		this.resourceDescription = null;
		this.beanName = null;
	}

	public BeanDefinitionStoreException(String msg, @Nullable Throwable cause) {
		super(msg, cause);
		this.resourceDescription = null;
		this.beanName = null;
	}

	public BeanDefinitionStoreException(@Nullable String resourceDescription, String msg) {
		super(msg);
		this.resourceDescription = resourceDescription;
		this.beanName = null;
	}

	public BeanDefinitionStoreException(@Nullable String resourceDescription, String msg, @Nullable Throwable cause) {
		super(msg, cause);
		this.resourceDescription = resourceDescription;
		this.beanName = null;
	}

	public BeanDefinitionStoreException(@Nullable String resourceDescription, String beanName, String msg) {
		this(resourceDescription, beanName, msg, null);
	}

	public BeanDefinitionStoreException(
			@Nullable String resourceDescription, String beanName, String msg, @Nullable Throwable cause) {

		super("Invalid bean definition with name '" + beanName + "' defined in " + resourceDescription + ": " + msg,
				cause);
		this.resourceDescription = resourceDescription;
		this.beanName = beanName;
	}

	@Nullable
	public String getResourceDescription() {
		return this.resourceDescription;
	}

	@Nullable
	public String getBeanName() {
		return this.beanName;
	}

}

触发条件:无法获取到 Bean 定义元信息时,抛出此异常,例如:Bean 配置的 XML 文件无法打开时。

BeansException

通过前面异常源码,不难发现,所有异常都是继承 BeansException
BeansException 源码

public abstract class BeansException extends NestedRuntimeException {

	/**
	 * Create a new BeansException with the specified message.
	 * @param msg the detail message
	 */
	public BeansException(String msg) {
		super(msg);
	}

	/**
	 * Create a new BeansException with the specified message
	 * and root cause.
	 * @param msg the detail message
	 * @param cause the root cause
	 */
	public BeansException(@Nullable String msg, @Nullable Throwable cause) {
		super(msg, cause);
	}

}

通过代码,BeansException 继承 NestedRuntimeExceptionNestedRuntimeException 继承 RuntimeException
因此 BeansException 是一个运行时异常,属于非检测异常,这意味着 Spring 框架在调用某些可能抛出这些异常的方法时,不必像其他框架那样,进行 try-catch

结论

Spring 框架内部定义了一系列异常,每个异常针对单一的场景,因此可以学习到,日后写一些框架时,也要考虑到异常类的创建和处理。异常的主要作用是:输出一个错误信息,然后中止程序的执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring中,定时任务可以使用注解或XML配置来实现。当定时任务执行时,Spring会根据配置信息来查找对应的bean,并执行bean中的方法。然而,在某些情况下,当定时任务执行时可能会出现反射异常方法未找到的问题。 反射异常方法未找到的原因可能有多种,例如定时任务的配置信息错误、bean的名称或方法名称错误、bean未被正确定义或加载等等。当定时任务执行时,Spring无法找到对应的bean或方法,就会抛出反射异常方法未找到的错误。 解决该问题的方法有以下几个步骤: 1. 首先,检查定时任务的配置信息是否正确,确保时间表达式以及所执行的bean名称和方法名称正确无误。 2. 检查对应的bean是否已经正确定义并被Spring容器加载。可以通过注解或XML配置来定义bean,并确保其在Spring容器中被正确加载。 3. 确保所执行的方法在bean中正确定义,并且方法名称与配置信息中的名称一致。检查方法的参数和返回值是否与配置信息中的要求一致。 4. 如果定时任务是通过注解方式配置的,可以尝试使用XML配置方式来进行配置,以确保配置的正确性。 5. 如果仍然无法解决问题,可以使用日志调试工具来获取详细的错误信息,帮助定位具体的问题所在。 总之,出现定时任务Spring bean反射异常方法未找到的问题,通常是因为配置信息或代码定义的错误所导致的。通过仔细检查配置信息、bean的定义和加载情况以及方法的正确性,可以解决该问题并正常执行定时任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值