Backend Development 7 min read

Why Changing @Resource Field Names Breaks Spring Bean Injection

This article explains how Spring's @Resource injection resolves beans by name first and then by type, why mismatched field names or bean registration order cause NoSuchBeanDefinitionException, and how to correctly configure DAO and CommonDAO beans to avoid injection failures.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Why Changing @Resource Field Names Breaks Spring Bean Injection

Problem Description

Using Spring 5.3.23, a basic configuration defines a DAO interface, its implementation CommonDAO , and registers a DAO bean in AppConfig . CommonService injects both DAO and CommonDAO with @Resource . The program runs without error when both beans are injected.

Issue Summary

Various modifications to the injection cause inconsistent behavior:

Injecting only CommonDAO results in NoSuchBeanDefinitionException .

Renaming the field from commonDAO to dao makes the injection succeed.

Changing the order of fields ( CommonDAO then DAO ) makes the injection fail again.

Altering the bean registration order in AppConfig also affects success.

Root Cause Analysis

The @Resource annotation is processed by CommonAnnotationBeanPostProcessor . It first attempts to locate a bean by the field name (bean name). If a bean with that name does not exist, it falls back to type‑based lookup.

<code>public class CommonAnnotationBeanPostProcessor {
  protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName) {
    Object resource;
    if (factory instanceof AutowireCapableBeanFactory) {
      AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
      DependencyDescriptor descriptor = element.getDependencyDescriptor();
      // If bean name not found, fall back to type match
      if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
        resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
      } else {
        // Bean name exists, resolve directly
        resource = beanFactory.resolveBeanByName(name, descriptor);
        autowiredBeanNames = Collections.singleton(name);
      }
    }
    return resource;
  }
}
</code>

The subsequent lookup process involves AbstractAutowireCapableBeanFactory and DefaultListableBeanFactory , which first try to find a bean by name in the singleton pool and, if not found, search by type using BeanFactoryUtils.beanNamesForTypeIncludingAncestors .

<code>public abstract class AbstractAutowireCapableBeanFactory {
  public Object resolveBeanByName(String name, DependencyDescriptor descriptor) {
    return getBean(name, descriptor.getDependencyType());
  }
}

public abstract class AbstractBeanFactory {
  public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    return doGetBean(name, requiredType, null, false);
  }
}

public class DefaultListableBeanFactory {
  public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
    @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    Object result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
    return result;
  }

  protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType,
    DependencyDescriptor descriptor) {
    String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());
    return ...;
  }
}
</code>

When CommonService injects DAO dao , the bean name dao matches the registered bean, so injection succeeds. For CommonDAO , there is no bean named commonDAO in the container; the processor therefore falls back to type lookup. If a DAO bean has already been created and stored in the singleton pool, the type lookup can succeed indirectly, which explains why certain registration orders work.

Thus, the injection failures are caused by the bean‑name‑first strategy of @Resource . Aligning the field name with the bean name (e.g., renaming the field to dao ) or ensuring the required bean is created earlier resolves the issue.

JavaSpringdependency injectionBeanresource-annotation
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.