Spring5: @ Autowired annotation, @ Resource annotation, and @ Service annotation, spring5 @ resource
What is annotation?
The traditional Spring method is to use the. xml file to inject beans or configure aop and things. This method has two disadvantages:
1. If all the content is configured in the. xml file, the. xml file will be very large. if you separate the. xml file as needed, there will be a lot of. xml files. In short, this will cause the readability and maintainability of the configuration file to become low.
2. switching between. java and. xml files during development is troublesome. At the same time, this inconsistency of thinking will also reduce the development efficiency.
To solve these two problems, Spring has introduced annotations. Through the "@ XXX" method, annotations are closely integrated with Java Beans, which greatly reduces the volume of configuration files, added the readability and cohesion of Java Beans.
In this article, we will talk about the three most important Spring annotations, namely @ Autowired, @ Resource, and @ Service. We hope to explain the usage of these three annotations in a limited space.
Do not use annotations
First, let's look at a Spring example without annotation. Based on this example, we will change it to the Annotation Version, so that we can see the difference between using and without annotation. First, we will define a tiger:
public class Tiger{ private String tigerName = "TigerKing"; public String toString() { return "TigerName:" + tigerName; }}
Define another monkey:
public class Monkey{ private String monkeyName = "MonkeyKing"; public String toString() { return "MonkeyName:" + monkeyName; }}
Define a zoo:
public class Zoo{ private Tiger tiger; private Monkey monkey; public void setTiger(Tiger tiger) { this.tiger = tiger; } public void setMonkey(Monkey monkey) { this.monkey = monkey; } public Tiger getTiger() { return tiger; } public Monkey getMonkey() { return monkey; } public String toString() { return tiger + "\n" + monkey; }}
The spring configuration file is written as follows:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd" default-autowire="byType"> <bean id="zoo" class="com.xrq.bean.Zoo" > <property name="tiger" ref="tiger" /> <property name="monkey" ref="monkey" /> </bean> <bean id="tiger" class="com.xrq.domain.Tiger" /> <bean id="monkey" class="com.xrq.domain.Monkey" /> </beans>
I am very familiar with it. I have to review it again.
@ Autowired
@ Autowired, as its name implies, is automatic assembly. It is used to eliminate the property in the getter/setter and bean attributes in the Java code. Of course, getter depends on individual needs. If private attributes need to be provided externally, they should be retained.
Therefore, the @ Autowired annotation is introduced. Let's take a look at how to write the spring configuration file:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 7 http://www.springframework.org/schema/context 8 http://www.springframework.org/schema/context/spring-context-4.2.xsd"> 9 10 <context:component-scan base-package="com.xrq" />11 12 <bean id="zoo" class="com.xrq.bean.Zoo" />13 <bean id="tiger" class="com.xrq.domain.Tiger" />14 <bean id="monkey" class="com.xrq.domain.Monkey" />15 16 </beans>
Note that the 10th rows must tell spring that I want to use annotations. There are many ways to tell, <context: component-scan base-package = "xxx"/> is the simplest method. spring automatically scans annotations in the xxx path.
We can see Row 3. Two tiger and monkey attributes should be injected in zoo, and no injection is required now. Again, Zoo. java is also very convenient. You can remove getter/setter:
public class Zoo{ @Autowired private Tiger tiger; @Autowired private Monkey monkey; public String toString() { return tiger + "\n" + monkey; }}
Here, the @ Autowired annotation means that when Spring discovers the @ Autowired annotation, it will automatically find the Bean that matches it in the Code context (the default value is type matching, and automatically inject it to the corresponding place.
The problem with the details is that if there are two properties in the bean, and the getter/setter of the attribute is removed in Zoo. java and the @ Autowired annotation is used to mark the two properties, what will happen? The answer is:Spring will search for the getter/setter attributes in Zoo. java based on the xml priority principle.The result is that an error is reported during bean initialization.
OK. If I remove the Lines 13 and 14 of the. xml file and run the file again, an exception will be thrown:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'Zoo': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xrq.domain.Tiger com.xrq.bean.Zoo.ttiger; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xrq.domain.Tiger] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:835) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) at com.xrq.test.MyTest.main(MyTest.java:13)Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xrq.domain.Tiger com.xrq.bean.Zoo.ttiger; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xrq.domain.Tiger] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:571) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ... 13 moreCaused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xrq.domain.Tiger] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:543) ... 15 more
Because the @ Autowired annotation is looking for a Bean, and the Bean definitions of Tiger and Monkey are removed, it is naturally not a Bean, and Spring containers cannot be found and can be well understood. So, if the property cannot be found, I don't want the Spring container to throw an exception, but display null, can I? Yes. In fact, the exception information also prompts that you can set the required attribute of @ Autowired annotation to false:
public class Zoo{ @Autowired(required = false) private Tiger tiger; @Autowired(required = false) private Monkey monkey; public String toString() { return tiger + "\n" + monkey; }}
At this time, the tiger and monkey attributes cannot be found. The Spring container does not throw the exception but considers the two attributes as null.
@ Autowired interface Injection
The above is relatively simple. We just inject a Java class. If there is an interface with multiple implementations, the Bean references the interface name. What should we do? For example, there is a Car interface:
public interface Car{ public String carName();}
Two implementation classes: BMW and Benz:
@Servicepublic class BMW implements Car{ public String carName() { return "BMW car"; }}
@Servicepublic class Benz implements Car{ public String carName() { return "Benz car"; }}
Write a CarFactory and reference the Car:
@Servicepublic class CarFactory{ @Autowired private Car car; public String toString() { return car.carName(); }}
Needless to say, there must be an error. The Car interface has two implementation classes, and Spring does not know which implementation class should be referenced. There are two solutions to this problem:
1. if you delete an implementation class, Spring will automatically go to the base-package to find the implementation class of the Car interface. It is found that the Car interface has only one implementation class and will directly reference this implementation class.
2. What should I do if there are multiple implementation classes? In this case, the @ Qualifier annotation can be used:
@Servicepublic class CarFactory{ @Autowired @Qualifier("BMW") private Car car; public String toString() { return car.carName(); }}
Note @ Qualifier AnnotationThe brackets should be the class name of the Car interface implementation class.I thought it was the bean name before, so I wrote "bMW" and the result was always an error.
@ Resource
Put the @ Resource annotation under @ Autowired, because they have very similar functions. This is a simple example. The difference between @ Resource and @ Autowired is illustrated later. Let's take a look at @ Resource and write Zoo. java directly:
@Servicepublic class Zoo{ @Resource(name = "tiger") private Tiger tiger; @Resource(type = Monkey.class) private Monkey monkey; public String toString() { return tiger + "\n" + monkey; }}
This is a detailed usage. Let's talk about the @ Resource assembly sequence:
1. @ Resource does not contain any content. By default, the bean is matched by the name attribute. If no content is found, the bean is matched by type.
2. If name or type is specified, the bean is matched based on the specified type.
3. If name and type are specified, the bean is matched based on the specified name and type. If any one of them does not match, an error is returned.
Then, differentiate the differences between @ Autowired and @ Resource Annotations:
1. @ Autowired performs bean matching by byType by default, and @ Resource performs bean matching by byName by default.
2. @ Autowired is the annotation of Spring, and @ Resource is the annotation of J2EE. Let's take a look at the package names of the two annotations when importing the annotation.
Spring is a third-party product. J2EE is a Java product. Therefore, we recommend that you use the @ Resource annotation to reduce the coupling between code and Spring.
@ Service
The above example can be simplified, because there are still 12 lines in the spring configuration file ~ In line 14, three beans are removed. The next step is to remove these three beans so that the spring configuration file contains only one automatically scanned tag, enhance Java code cohesion and further reduce configuration files.
To simplify the process, you can use @ Service. Let's take a look at the configuration file. Of course, all the files are deleted:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <context:component-scan base-package="com.xrq" /> </beans>
Is it really nice? At least I think so. OK. The following uses Zoo. java as an example. The rest of Monkey. java and Tiger. java are the same:
@Servicepublic class Zoo{ @Autowired private Tiger ttiger; @Autowired private Monkey mmonkey; public String toString() { return ttiger + "\n" + mmonkey; }}
In this way, the form of Zoo. java in the Spring container is "zoo", that is, you can get zoo. java through the getBean ("Zoo") method of ApplicationContext. The @ Service annotation actually does two things:
1. It is important to declare Zoo. java as a bean, because Zoo. java is a bean and other classes can use @ Autowired to automatically inject Zoo as a member variable.
2. the id of Zoo. java in bean is "zoo", that is, the class name and the first letter is lowercase.
If I don't want to use this form, I want to name Zoo. java in the Spring container "Zoo". Yes:
@Service@Scope("prototype")public class Zoo{ @Autowired private Monkey monkey; @Autowired private Tiger tiger; public String toString() { return "MonkeyName:" + monkey + "\nTigerName:" + tiger; }}
In this way, you can use the getBean ("zoo") method of ApplicationContext to obtain Zoo. java.
Here I have added a @ Scope annotation, which should be easy to understand. The bean generated by Spring is a singleton by default. If I don't want to use Singleton, configure the scope attribute in the bean in the xml file. The same is true for annotations. Configure @ Scope. The default value is "singleton", that is, singleton. "prototype" indicates that a new prototype is generated every time.
Additional details
At last, I added a detail of my findings. If the animal package has a Tiger and a domain package also has a Tiger, both of which are added with the @ Service annotation, then in Zoo. in java, even if the Tiger under the domain package is explicitly referenced, an error will still be reported during the program running.
Think about it. In fact, this is very easy to understand. Both Tiger are labeled with @ Service annotation, which means that the names of both beans are "tiger", so I am in Zoo. which Tiger is automatically assembled in java? Therefore, the Spring container will throw the BeanDefinitionStoreException, Caused:
Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'monkey' for bean class [com.xrq.domain.Monkey] conflicts with existing, non-compatible bean definition of same name and class [com.xrq.animal.Monkey]