It’s been common in recent development to see @autowired in some parts of a project and @Resource in others. So this article focuses on the difference between these two annotations.

In common

Both @Resource and @AutoWired can be used as modifications to injected properties. If the interface has a single implementation class, the modifications of the two annotations are the same and can be replaced without affecting their use.

The difference between

@resource is a JDK native annotation, and @autowired is an annotation introduced by Spring2.5

@resource has two attributes: name and type. Spring resolves the name attribute of the @Resource annotation to the bean name, and the Type attribute to the bean type. So if the name attribute is used, the byName auto-injection policy is used, and if the Type attribute is used, the byType auto-injection policy is used. If neither name nor type attributes are specified, the byName automatic injection policy is used through reflection.

@autoWired will only inject based on type and will not match name. When it comes to type not being able to identify injected objects, you need to rely on the @qualifier or @primary annotations in combination.

Practice shows that

Java; open(), cooking(), close();

public interface Cook {
	
	/** * fire */
	String open(a);
  /** ** stir fry */
  String cooking(a);
  /** * Turn off the heat */
  String close(a);
}
Copy the code

Define the implementation class cooktomato.java

/** * service interface implementation class */
@Service
public class CookTomato implements Cook {
  @override
	public String open(a) {
		return "Turn on the range hood and fire before frying the tomatoes.";
	}
  @override
  public String cooking(a) {
		return "Stir-fried tomatoes.";
	}
  @override
  public String close(a) {
		return "Turn off the range hood and turn off the heat after frying the tomatoes."; }}Copy the code

Define the Controller class cookController.java and inject the Cook interface

/** * Controller layer */
@RestController
@RequestMapping("/cook")
public class CookController {
 
	@Resource
	private Cook cook;
	
	@RequestMapping("/open")
	public String open(a) {
		return cook.open();
	}
  
  @RequestMapping("/cooking")
	public String cooking(a) {
		return cook.cooking();
	}
  
  @RequestMapping("/close")
	public String close(a) {
		returncook.close(); }}Copy the code

When Spring Boot is up and running, all three interfaces return normal results.

But if we add an implementation class for the Cook interface

/** * service interface implementation class */
@Service
public class CookPatato implements Cook {
  @override
	public String open(a) {
		return "Turn on the range hood and fire before frying the potatoes.";
	}
  @override
  public String cooking(a) {
		return "Stir-fried potato shreds.";
	}
  @override
  public String close(a) {
		return "Turn off the range hood and turn off the heat after sauteing the potatoes."; }}Copy the code

When Spring Boot is started at this time, the console will report an error

The 2021-10-24 10:24:10. 5592-662 WARN [restartedMain] ConfigServletWebServerApplicationContext: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name'CookController': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.janeroad.annotation.service.Cook' available: expected single matching bean but found 2: CookTomato,CookPatato
Copy the code

We introduced Cook but the Spring framework found that there were two implementations that could not match the bean

Let’s change the code to something like this

@Resource(name="cookTomato")
	private Cook cook;
Copy the code

or

@Resource
@Qualifier("cookTomato")
	private Cook cook;
Copy the code

All of the above code does one thing: specify the Cook implementation class as the fried tomato implementation class, and when you start Spring Boot and ask the Controller interface, everything is fine!

What if instead of using the @resource annotation we use @Autowire?

Changing to @autowire based on the above changes will result in the following error

Description:
 
Field cook in com.janeroad.annotation.controller.CookController required a single bean, but 2 were found:
	- cookTomato: defined inFile [path name omitted here] -cookpatato: definedinFile [path name omitted here] Action: Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumedCopy the code

The error means that the CookController needs a bean but found two implementations

So we should use @primary as an error prompt and tell Spring to take precedence over the @primary modifier if there are more than one implementation bean; Or use @qualifier to mark the classes that need to be injected.

The modification method for @qualifier is the same as that for @resource. The same method is used to modify Cook injected into the Controller code, which is not repeated here

The @primary annotation decorates the implementation class, telling Spring that if there are more than one implementation class, the one decorated with the @primary annotation will be injected first.

So change CookTomato. Java to

/** * service interface implementation class */
@Service
@Primary
public class CookTomato implements Cook {
  @override
	public String open(a) {
		return "Turn on the range hood and fire before frying the tomatoes.";
	}
  @override
  public String cooking(a) {
		return "Stir-fried tomatoes.";
	}
  @override
  public String close(a) {
		return "Turn off the range hood and turn off the heat after frying the tomatoes."; }}Copy the code

When Spring Boot is started, you will find that everything on the calling interface is fine.

conclusion

The @autowired feature, while very powerful, has some drawbacks. For example, it is strongly coupled to Spring, and if you switch to another framework, the functionality will not work. The @Resource is provided by JSR-250, which is a Java standard supported by most frameworks.

In addition, there are scenarios where @Autowired doesn’t meet the requirements, but changing to @Resource does.

1. @autoWired defaults to byType auto-assembly, while @Resource defaults to byName auto-assembly.

2. @autoWired contains only one parameter: required, indicating whether automatic access is enabled. The default is true. The @resource contains seven parameters, the most important of which are name and type.

3. @autoWired needs to use @qualifier in conjunction with byName. @resource is automatically assembled with byName if name is specified, and byType if type is specified.

4. @AutoWired can be used with constructors, methods, parameters, member variables, and annotations, while @Resource can be used with classes, member variables, and methods.

5. @AutoWired is a Spring-defined annotation, while @Resource is a JSR-250 defined annotation.

6, the two assembly sequence is different

@Autowired

@Resource