Mastering Spring’s @Autowired: Advanced Usage, Qualifiers, and Common Pitfalls
This article explores the default behavior of Spring's @Autowired annotation, how to resolve bean name conflicts, use @Qualifier and @Primary, apply @Autowired on constructors, methods, parameters, and collections, and troubleshoot common issues such as missing annotations, filter injection, component scanning, and circular dependencies.
Preface
While reviewing other developers' code I discovered several interesting usages of the
@Autowiredannotation in Spring, which prompted a deeper investigation and a comprehensive guide.
1. Default Autowiring
In Spring,
@Autowiredperforms automatic injection based on type (
byType) by default. The
requiredattribute is true, meaning injection is mandatory unless set to false.
<code>package com.sue.cache.service;
import org.springframework.stereotype.Service;
@Service
public class TestService1 {
public void test1() {}
}
package com.sue.cache.service;
import org.springframework.stereotype.Service;
@Service
public class TestService2 {
@Autowired
private TestService1 testService1;
public void test2() {}
}
</code>2. Multiple Beans of the Same Type
When more than one bean of the same type exists, Spring cannot decide which one to inject, leading to
ConflictingBeanDefinitionException. This occurs because Spring derives bean names from class names (e.g.,
testService1) and bean names must be unique.
<code>package com.sue.cache.service.test;
import org.springframework.stereotype.Service;
@Service
public class TestService1 {
public void test1() {}
}
</code>Attempting to start the application results in a conflict error.
Spring does not allow two beans with the same name; the first letter of the class name is used as the default bean name.
One way to create two beans of the same type is to define them manually in a configuration class and remove the
@Serviceannotation from the class.
<code>public class TestService1 {
public void test1() {}
}
@Configuration
public class TestConfig {
@Bean("test1")
public TestService1 test1() { return new TestService1(); }
@Bean("test2")
public TestService1 test2() { return new TestService1(); }
}
</code>3. @Qualifier and @Primary
When multiple candidates exist, you can switch from
byTypeto
byNameby using
@Qualifierto specify the bean name.
<code>@Service
public class UserService {
@Autowired
@Qualifier("user1")
private IUser user;
}
</code>Alternatively, mark one bean with
@Primaryso that it is chosen automatically.
<code>@Primary
@Service
public class User1 implements IUser {
@Override
public void say() {}
}
</code>@Qualifier works together with @Autowired to select a bean by its name.
4. Scope of @Autowired
The annotation can be placed on five target types: fields, constructors, methods, parameters, and other annotations.
4.1 Field
<code>@Service
public class UserService {
@Autowired
private IUser user;
}
</code>4.2 Constructor
<code>@Service
public class UserService {
private IUser user;
@Autowired
public UserService(IUser user) {
this.user = user;
System.out.println("user:" + user);
}
}
</code>Adding @Autowired on a constructor still uses Spring’s autowiring mechanism, not pure constructor injection.
4.3 Method
<code>@Service
public class UserService {
@Autowired
public void test(IUser user) {
user.say();
}
}
</code>Spring invokes such methods once during startup, which can be used for initialization.
4.4 Parameter
<code>@Service
public class UserService {
@Autowired
public UserService(@Autowired IUser user) {
this.user = user;
System.out.println("user:" + user);
}
}
</code>4.5 Annotation
Other annotation targets are rarely used and omitted here.
5. Advanced @Autowired
@Autowired can also inject collections of beans of the same type.
<code>@Service
public class UserService {
@Autowired
private List<IUser> userList;
@Autowired
private Set<IUser> userSet;
@Autowired
private Map<String, IUser> userMap;
public void test() {
System.out.println("userList:" + userList);
System.out.println("userSet:" + userSet);
System.out.println("userMap:" + userMap);
}
}
</code>Calling an endpoint that triggers
test()prints all injected beans, demonstrating that Spring aggregates them automatically.
6. Does @Autowired Always Succeed?
6.1 Missing Stereotype Annotation
If a class lacks
@Component,
@Service,
@Controller, etc., Spring will not manage it, and
@Autowiredwill have no effect.
<code>public class UserService {
@Autowired
private IUser user;
}
</code>6.2 Injection in Filters or Listeners
Filters and listeners are initialized before Spring’s MVC dispatcher, so beans are not yet available for injection, causing startup failures.
To inject a bean in a filter, obtain the application context manually:
<code>public class UserFilter implements Filter {
private IUser user;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
this.user = (IUser) ctx.getBean("user1");
user.say();
}
}
</code>6.3 Component Scan Misses the Bean
If
@ComponentScandoes not cover the package containing a bean, Spring cannot discover it, and
@Autowiredwill fail. Using
@SpringBootApplicationincludes a default component scan.
6.4 Circular Dependencies
Spring can resolve circular dependencies for singleton beans via setter injection, but prototype beans or proxy‑based beans may still cause failures.
7. @Autowired vs. @Resource
Both perform dependency injection, but they differ in semantics and usage:
@Autowired defaults to
byTypeinjection; @Resource defaults to
byName.
@Autowired has a single
requiredattribute; @Resource offers
nameand
typeamong other attributes.
To achieve name‑based injection with @Autowired you need @Qualifier; @Resource can use the
nameattribute directly.
@Autowired can be applied to constructors, methods, parameters, fields, and other annotations; @Resource works on classes, fields, and methods.
@Autowired is Spring‑specific, while @Resource is defined by JSR‑250 and supported by many frameworks.
The injection order for @Autowired differs from that of @Resource, as illustrated by the accompanying diagrams.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.