An overview of the
IoC(IoC) is the core of Spring, which is a framework based on IoC container programming. Since Spring Boot develops Spring IoC based on annotations, this article covers IoC in a fully annotated manner.
The development of a system is inseparable from many classes. By integrating business logic, we organize so many classes for business expansion, and there are more or less dependent relationships between different classes. Instead of instantiating a class through the new keyword, we’re handing it over to IoC for unified management.
Why use IoC
concept
An IoC is an Inversion of Control in which Control is transferred from application code to an external container. This is an Inversion of Control.
Compare the traditional mode with the Spring mode
Traditional way:
It is the responsibility of the application to decide which implementation to use, at compile time.
Spring:
The calling class relies only on the interface, not the concrete implementation class, reducing coupling. Control is given to the container, which decides at run time to dynamically “inject” the specific implementation into the objects of the calling class. This is the fundamental reason for using IoC.
BeanFactory
The IoC container is a container that manages beans. In Spring’s definition, it requires all IoC containers to implement the BeanFactory interface, which is the top-level container interface. Here is the source code for the BeanFactory.
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, Class<? >typeToMatch) throws NoSuchBeanDefinitionException; @Nullable Class<? > getType(String name) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }Copy the code
There are many getBean methods in the source code. They are one of the most important methods in the Ioc container. We can get beans by type or name.
IsSingleton determines whether a Bean is a singleton. In IoC, the default Bean is a singleton, that is, getBean returns the same object.
If the isPrototype method returns true, the IoC container always returns a new Bean.
AnnotationConfigApplicationContext
It is an annotation-based IoC container, introduced so that we can visually demonstrate Spring Boot assembly and obtaining beans. Let’s show you how to manually assemble beans into the container and then get beans from the container.
1, create a User. Java
package com.example.acutator.entity;
public class User {
private int id;
private String username;
private String phone;
private String email;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' + ", phone='" + phone + '\'' + ", email='" + email + '\' ' +
'} '; }}Copy the code
2, create the AppConfig. Java
package com.example.acutator.config;
import com.example.acutator.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean(name = "user")
public User getUser() {
User user = new User();
user.setId(1);
user.setUsername("Zhang SAN Crazy");
user.setPhone("1129882512");
user.setEmail("[email protected]");
returnuser; }}Copy the code
3. Get the Bean from the startup class
@SpringBootApplication
public class AcutatorApplication {
public static void main(String[] args) {
SpringApplication.run(AcutatorApplication.class, args);
ApplicationContext applicationContext=new AnnotationConfigApplicationContext(AppConfig.class);
User user=applicationContext.getBean(User.class);
System.out.println("user info>>"+user); }}Copy the code
4. View the results
The 2019-09-29 17:07:25. 9148-250 the INFO [main] org. Apache. Catalina. Core. StandardEngine: Starting the Servlet engine: [Apache Tomcat/ 5.0.24] 2019-09-29 17:07:25.359 INFO 9148 -- [main] O.A.C.C.C. [Tomcat].[/] : Initializing Spring Embedded WebApplicationContext 2019-09-29 17:07:25.359 INFO 9148 -- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completedin1094 ms 17:07:25 2019-09-29. 9148-747 the INFO [main] O.S.S.C oncurrent. ThreadPoolTaskExecutor: Initializing ExecutorService'applicationTaskExecutor'The 2019-09-29 17:07:25. 9148-939 the INFO [main] O.S.B.A.E.W eb. EndpointLinksResolver: Exposing 14 endpoint(s) beneath base path'/actuator'The 17:07:26 2019-09-29. 9148-004 the INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: tomcat started on the port (s) : 8080 (http) with context path' 'The 2019-09-29 17:07:26. 9148-006 the INFO [main] c.e xample. Acutator. AcutatorApplication: Started AcutatorApplicationin2.076 seconds (JVM is runningfor2.85) the user info > > user {id = 1, the username ='Zhang SAN Crazy', phone='1129882512', email='[email protected]'} the 17:07:27 2019-09-29. 9148-803 the INFO/on (2) - 127.0.0.1 O.A.C.C.C. [Tomcat] [localhost]. / / : Initializing Spring DispatcherServlet'dispatcherServlet'The 17:07:27 2019-09-29. 9148-803 the INFO/on (2) - 127.0.0.1 O.S.W eb. Servlet. DispatcherServlet: Initializing the servlet'dispatcherServlet'The 17:07:27 2019-09-29. 9148-809 the INFO/on (2) - 127.0.0.1 O.S.W eb. Servlet. DispatcherServlet: Completed initializationin 6 ms
Copy the code
You can see that the User information we assembled has been printed out.
The @Configuration annotation class indicates that this is a Java Configuration file from which the Spring container will generate the IoC container to assemble the Bean.
@bean indicates that the Bean returned by the method will be assembled into the IoC container. If no name value is given, the default Bean name assembled into the container is the method name (getUser in this case).
AnnotationConfigApplicationContext class constructor to @ the Configuration notes, equivalent to load the Configuration information inside it, according to the Configuration information will Bean assembly to the IoC container. Of course, beans can also be fetched by name or type.
Auto-assembly Bean
Use AnnotationConfigApplicationContext experience in front of the head assembly, but developing so much class, if in this way to assembly, that will be how much trouble. So Spring provides annotations to assemble beans by scanning.
We will use the @Component and @ComponentScan annotations to complete the scanning assembly Bean.
Component: indicates that the class is marked to be scanned into the IoC container.
@ComponentScan: Means to scan our assembled beans with a scan sample strategy.
1, create Student. Java
There is an @Component annotation above the class name to indicate that it can be scanned
package com.example.acutator.entity;
import org.springframework.stereotype.Component;
@Component
public class Student {
private String num;
private String name;
private int score;
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"num='" + num + '\'' + ", name='" + name + '\'' + ", score=" + score + '}'; }}Copy the code
2, modifying AppConfig. Java
With scanning strategy: @ ComponentScan (” com. Example. Acutator. Entity “), on behalf of the scan the package all the classes below, all class names have @ the Component annotation will scan the assembly to the IoC container.
@Configuration
@ComponentScan("com.example.acutator.entity")
public class AppConfig {
@Bean(name = "user")
public User getUser() {
User user = new User();
user.setId(1);
user.setUsername("Zhang SAN Crazy");
user.setPhone("1129882512");
user.setEmail("[email protected]");
returnuser; }}Copy the code
3. Modify the startup class
Add Student object to print information
@SpringBootApplication
public class AcutatorApplication {
public static void main(String[] args) {
SpringApplication.run(AcutatorApplication.class, args);
ApplicationContext applicationContext=new AnnotationConfigApplicationContext(AppConfig.class);
// User user=applicationContext.getBean(User.class);
// System.out.println("user info>>"+user);
Student student=applicationContext.getBean(Student.class);
System.out.println("student info>>"+student); }}Copy the code
4. View the results
____ ____ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \ / _ ` | \ \ \ \ \ \ / ___) | | _) | | | | | | | (_ | |))))' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.8. RELEASE) the 2019-09-29 17:32:10. 14844-600 the INFO [main] c.e xample. Acutator. AcutatorApplication: Starting AcutatorApplication on XXW4VSPSAQE4OR2 with PID 14844 (D:\ideaProject2\acutator\target\classes started by Administrator in D:\ideaProject2\acutator) 2019-09-29 17:32:10.602 INFO 14844 -- [main] c.example.acutator.AcutatorApplication : No active profile set, falling back to default profiles: The default 17:32:11 2019-09-29. 14844-539 the INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: Tomcat initialized with port(s): 8080 (HTTP) 17:32:11 2019-09-29. 14844-559 the INFO [main] o.a pache, catalina. Core. StandardService: Starting the service [Tomcat] 2019-09-29 17:32:11. 560 INFO 14844 - [the main] org. Apache. Catalina. Core. StandardEngine: Starting Servlet engine: [main] O.A.C.C.C. [Tomcat].[/] : [Apache Tomcat/ 5.0.24] 2019-09-29 17:32:11.680 INFO 14844 -- [main] O.A.C.C.C. [Tomcat].[/] : Initializing Spring Embedded WebApplicationContext 2019-09-29 17:32:11.680 INFO 14844 -- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: Initialization Completed in 1447 MS 2019-09-29 17:32:12.082 INFO 14844 -- [main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'14844-2019-09-29 17:32:12. 267 INFO [main] O.S.B.A.E.W eb. EndpointLinksResolver: Exposing 14 endpoint(s) beneath base path '/actuator'14844-2019-09-29 17:32:12. 328 INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: tomcat is started on the port (s) : 8080 (http) with context path ''14844-2019-09-29 17:32:12. 330 INFO [main] c.e xample. Acutator. AcutatorApplication: Started AcutatorApplication in 2.018 seconds (JVM running for 2.761) student info>> student {num='null', name='null'score = 0} 17:32:14 2019-09-29. 14844-207 the INFO/on (2) - 127.0.0.1 O.A.C.C.C. [Tomcat] [localhost]. / / : Initializing Spring DispatcherServlet 'dispatcherServlet'14844-2019-09-29 17:32:14. 207 INFO/on (2) - 127.0.0.1 O.S.W eb. Servlet. The DispatcherServlet: Initializing the servlet'dispatcherServlet'14844-2019-09-29 17:32:14. 213 INFO/on (2) - 127.0.0.1 O.S.W eb. Servlet. The DispatcherServlet: Completed initialization in 6 msCopy the code
As you can see from the Student object information, we did not assign values during assembly, so we printed the default values.
Dependency injection
Dependency Injection and Inversion of Control are the same concept. When one role (perhaps a Java instance, caller) needs the assistance of another role (another Java instance, caller), in traditional programming, it is usually the caller who creates the instance of the caller. But in Spring, the job of creating the called is no longer done by the caller, so it is called inversion of control. The job of creating an instance of the called is usually done by the Spring container and then injecting the caller, hence the term dependency injection.
For example, people sometimes rely on animals to do some things for us, such as cats catching mice, dogs guarding the house and so on. Cats and dogs belong to animals. The following is a code to describe the logic of how humans rely on animals to do things.
1, establish Animal. Java
It is the interface of the animal, encapsulating a method, and we give it a method work
public interface Animal {
public void work();
}Copy the code
2, create Person. Java
It is the human top-level interface
public interface Person {
public void service();
public void setAnimal(Animal animal);
}Copy the code
Java to implement the Animal interface
package com.example.acutator.entity;
import org.springframework.stereotype.Component;
@Component
public class Dog implements Animal{
@Override
public void work() {
System.out.println(The dog is guarding the door.); }}Copy the code
4. Create BusinessPerson to implement the Person interface
package com.example.acutator.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class BusinessPerson implements Person{
@Autowired
private Animal animal=null;
@Override
public void service() {
this.animal.work();
}
@Override
public void setAnimal(Animal animal) { this.animal=animal; }}Copy the code
5. Start class tests
@SpringBootApplication
public class AcutatorApplication {
public static void main(String[] args) {
SpringApplication.run(AcutatorApplication.class, args);
ApplicationContext applicationContext=new AnnotationConfigApplicationContext(AppConfig.class);
// User user=applicationContext.getBean(User.class);
// System.out.println("user info>>"+user);
// Student student=applicationContext.getBean(Student.class);
// System.out.println("student info>>"+student); Person person=applicationContext.getBean(BusinessPerson.class); person.service(); }}Copy the code
6. Test results
____ ____ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \ / _ ` | \ \ \ \ \ \ / ___) | | _) | | | | | | | (_ | |))))' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.8. RELEASE) the 2019-09-30 08:49:24. 11792-093 the INFO [main] c.e xample. Acutator. AcutatorApplication: Starting AcutatorApplication on XXW4VSPSAQE4OR2 with PID 11792 (D:\ideaProject2\acutator\target\classes started by Administrator in D:\ideaProject2\acutator) 2019-09-30 08:49:24.101 INFO 11792 -- [main] c.example.acutator.AcutatorApplication : No active profile set, falling back to default profiles: The default 08:49:26 2019-09-30. 11792-992 the INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: Tomcat initialized with port(s): 8080 (HTTP) 08:49:27 2019-09-30. 11792-046 the INFO [main] o.a pache, catalina. Core. StandardService: Starting the service [Tomcat] 2019-09-30 08:49:27. 046 INFO 11792 - [the main] org. Apache. Catalina. Core. StandardEngine: Starting Servlet engine: [main] O.A.C.C.C. [Tomcat].[/] : Initializing Spring Embedded WebApplicationContext 2019-09-30 08:49:27.191 INFO 11792 -- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: Initialization Completed in 2972 MS 2019-09-30 08:49:27.948 INFO 11792 -- [main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'11792-2019-09-30 08:49:28. 236 INFO [main] O.S.B.A.E.W eb. EndpointLinksResolver: Exposing 14 endpoint(s) beneath base path '/actuator'11792-2019-09-30 08:49:28. 314 INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: tomcat is started on the port (s) : 8080 (http) with context path ''11792-2019-09-30 08:49:28. 331 INFO [main] c.e xample. Acutator. AcutatorApplication: Started AcutatorApplication in 5.185 seconds (JVM running for 6.756) *** [on(9)-127.0.0.1] O.A.C.C.C. [Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'11792-2019-09-30 08:49:30. 710 INFO/on (9) - 127.0.0.1 O.S.W eb. Servlet. The DispatcherServlet: Initializing the servlet'dispatcherServlet'11792-2019-09-30 08:49:30. 851 INFO/on (9) - 127.0.0.1 O.S.W eb. Servlet. The DispatcherServlet: Completed initialization in 141 msCopy the code
@autoWired it will find the corresponding Bean to inject based on the type of the property. The Dog class here is an animal, so the IoC container will inject an instance of Dog into BusinessPerson so that Dog can work for us. You can see the printed information in the test result, indicating that we successfully injected the dependency.
There is a problem here. As we mentioned earlier, the top interface of the IoC container is the BeanFactory, which can get beans in many ways, one of which is to get beans according to their type. In this case, the Animal implementation class only has Dog, but there is more than one kind of Animal. Is there a problem with getting beans by type? How does IoC know which type we’re going to inject into the caller instance? Please follow.
7, to create the Java
package com.example.acutator.entity;
import org.springframework.stereotype.Component;
@Component
public class Cat implements Animal {
@Override
public void work() {
System.out.println("*** The cat is catching the mouse ***"); }}Copy the code
8, abnormal
____ ____ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \ / _ ` | \ \ \ \ \ \ / ___) | | _) | | | | | | | (_ | |))))' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.8. RELEASE) the 2019-09-30 09:10:51. 10716-358 the INFO [main] c.e xample. Acutator. AcutatorApplication: Starting AcutatorApplication on XXW4VSPSAQE4OR2 with PID 10716 (D:\ideaProject2\acutator\target\classes started by Administrator in D:\ideaProject2\acutator) 2019-09-30 09:10:51.361 INFO 10716 -- [main] c.example.acutator.AcutatorApplication : No active profile set, falling back to default profiles: The default 09:10:52 2019-09-30. 10716-313 the INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: Tomcat initialized with port(s): 8080 (HTTP) 09:10:52 2019-09-30. 10716-329 the INFO [main] o.a pache, catalina. Core. StandardService: Starting the service [Tomcat] 2019-09-30 09:10:52. 329 INFO 10716 - [the main] org. Apache. Catalina. Core. StandardEngine: Starting Servlet engine: [Apache Tomcat/9.0.24] 2019-09-30 09:10:52.432 INFO 10716 -- [main] O.A.C.C.C. [Tomcat]. Initializing Spring Embedded WebApplicationContext 2019-09-30 09:10:52.432 INFO 10716 -- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: Initialization Completed in 1042 MS 2019-09-30 09:10:52.684 WARN 10716 -- [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'businessPerson': Unsatisfied dependency expressed through field 'animal'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.acutator.entity.Animal' available: expected single matching bean but found 2: Cat, dog 09:10:52 2019-09-30. 10716-687 the INFO [main] o.a pache, catalina. Core. StandardService: Stopping the service [Tomcat] 2019-09-30 09:10:52. 707 INFO 10716 - [the main] ConditionEvaluationReportLoggingListener: Error starting ApplicationContext. To display the conditions report re-run your application with 'debug'enabled. 2019-09-30 09:10:52. 783 ERROR 10716 - [the main] O.S.B.D.L oggingFailureAnalysisReporter: *************************** APPLICATION FAILED TO START *************************** Description: Field animal in com.example.acutator.entity.BusinessPerson required a single bean, but 2 were found: - cat: defined in file [D:\ideaProject2\acutator\target\classes\com\example\acutator\entity\Cat.class] - dog: defined in file [D:\ideaProject2\acutator\target\classes\com\example\acutator\entity\Dog.class] 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 consumed Process finished with exit codeCopy the code
When we create the Cat instance, the program throws an exception. This is because the IoC container doesn’t know what animal you want to inject when we inject it. Moving on, we’ll solve this problem.
Disambiguation of dependence
concept
The Spring IoC container’s confusion or confusion of injection references in injection dependencies due to multiple types of an instance is called ambiguity.
Methods a
Change the injected Animal property name to dog or cat
package com.example.acutator.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class BusinessPerson implements Person{
@Autowired
private Animal dog=null;
@Override
public void service() {
this.dog.work();
}
@Override
public void setAnimal(Animal animal) { this.dog=animal; }}Copy the code
The results of
____ ____ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \ / _ ` | \ \ \ \ \ \ / ___) | | _) | | | | | | | (_ | |))))' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.8. RELEASE) the 2019-09-30 09:15:05. 11684-128 the INFO [main] c.e xample. Acutator. AcutatorApplication: Starting AcutatorApplication on XXW4VSPSAQE4OR2 with PID 11684 (D:\ideaProject2\acutator\target\classes started by Administrator in D:\ideaProject2\acutator) 2019-09-30 09:15:05.130 INFO 11684 -- [main] c.example.acutator.AcutatorApplication : No active profile set, falling back to default profiles: The default 09:15:06 2019-09-30. 11684-081 the INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: Tomcat initialized with port(s): 8080 (HTTP) 09:15:06 2019-09-30. 11684-100 the INFO [main] o.a pache, catalina. Core. StandardService: Starting the service [Tomcat] 2019-09-30 09:15:06. 100 INFO 11684 - [the main] org. Apache. Catalina. Core. StandardEngine: Starting Servlet engine: [Apache Tomcat/ 5.0.24] 2019-09-30 09:15:06.211 INFO 11684 -- [main] O.A.C.C.C. [Tomcat].[/] : Initializing Spring Embedded WebApplicationContext 2019-09-30 09:15:06.211 INFO 11684 -- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: Reference: Initialization completed in 1647 MS 2019-09-30 09:15:06.566 INFO 11684 -- [main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'11684-2019-09-30 09:15:06. 756 INFO [main] O.S.B.A.E.W eb. EndpointLinksResolver: Exposing 14 endpoint(s) beneath base path '/actuator'11684-2019-09-30 09:15:06. 819 INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: tomcat is started on the port (s) : 8080 (http) with context path ''11684-2019-09-30 09:15:06. 821 INFO [main] c.e xample. Acutator. AcutatorApplication: Started AcutatorApplication in 2.011 seconds (JVM running for 2.758 [on(8)-127.0.0.1] O.A.C.C.C. [Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'11684-2019-09-30 09:15:08. 689 INFO/on (8) - 127.0.0.1 O.S.W eb. Servlet. The DispatcherServlet: Initializing the servlet'dispatcherServlet'11684-2019-09-30 09:15:08. 694 INFO/on (8) - 127.0.0.1 O.S.W eb. Servlet. The DispatcherServlet: Completed initialization in 5 msCopy the code
That’s when the system works. Why?
The reason:
Autowired provides the rule that first it will find the corresponding Bean by type, if the corresponding type is not unique, then it will match the property name with the Bean name, if there is a match, then it will use the Bean, if there is still no match, it will throw an exception.
The @Autowired annotation is also important to note that it must find the Bean by default. If you are not sure that the annotation attribute will exist and allow the annotation attribute to be null, you can configure the @Autowired attribute required to false
Way 2
Although method 1 can eliminate ambiguity, it is not logical to directly change animal to dog, a perfectly good animal, but we just change it to dog.
Here we use the @primary annotation to modify cat.java and add the annotation above the class name. It tells the IoC container that if multiple types of the same instance are found during injection, the one with @primary should be injected first. (Change dog property name back to animal)
package com.example.acutator.entity;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Component
@Primary
public class Cat implements Animal {
@Override
public void work() {
System.out.println("*** The cat is catching the mouse ***"); }}Copy the code
The results
/ \ \ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \ / _ ` | \ \ \ \ \ \ / ___) | | _) | | | | | | | (_ | |))))' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.8. RELEASE) the 2019-09-30 09:31:52. 14992-588 the INFO [main] c.e xample. Acutator. AcutatorApplication: Starting AcutatorApplication on XXW4VSPSAQE4OR2 with PID 14992 (D:\ideaProject2\acutator\target\classes started by Administrator in D:\ideaProject2\acutator) 2019-09-30 09:31:52.591 INFO 14992 -- [main] c.example.acutator.AcutatorApplication : No active profile set, falling back to default profiles: The default 09:31:53 2019-09-30. 14992-488 the INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: Tomcat initialized with port(s): 8080 (HTTP) 09:31:53 2019-09-30. 14992-506 the INFO [main] o.a pache, catalina. Core. StandardService: Starting the service [Tomcat] 2019-09-30 09:31:53. 506 INFO 14992 - [the main] org. Apache. Catalina. Core. StandardEngine: Starting Servlet engine: [Apache Tomcat/9.0.24] 2019-09-30 09:31:53.619 INFO 14992 -- [main] O.A.C.C.C. [Tomcat].[/] : Initializing Spring Embedded WebApplicationContext 2019-09-30 09:31:53.619 INFO 14992 -- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: Initialization Completed in 1000 ms 2019-09-30 09:31:54.019 INFO 14992 -- [main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'14992-2019-09-30 09:31:54. 232 INFO [main] O.S.B.A.E.W eb. EndpointLinksResolver: Exposing 14 endpoint(s) beneath base path '/actuator'14992-2019-09-30 09:31:54. 292 INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: tomcat is started on the port (s) : 8080 (http) with context path ''14992-2019-09-30 09:31:54. 294 INFO [main] c.e xample. Acutator. AcutatorApplication: Started AcutatorApplication in 2.011 seconds (JVM running for 2.745) *** Cat is catching a mouse [on(8)-127.0.0.1] O.A.C.C.C. [Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'14992-2019-09-30 09:31:56. 074 INFO/on (8) - 127.0.0.1 O.S.W eb. Servlet. The DispatcherServlet: Initializing the servlet'dispatcherServlet'14992-2019-09-30 09:31:56. 079 INFO/on (8) - 127.0.0.1 O.S.W eb. Servlet. The DispatcherServlet: Completed initialization in 5 msCopy the code
If we added this annotation to dog.java, it would not pass the compiler, so this approach has a superficial feel. So it works, but it’s not good.
Methods three
@qualifier (), which needs to be configured with a value to be defined, will be combined with @AutoWired to find the Bean by type and name, since the Bean name is unique in the Spring IoC container, which disambiguates it this way.
Modify Businessperson. Java (remove @primary from cat. Java)
package com.example.acutator.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class BusinessPerson implements Person{
@Autowired
@Qualifier("cat")
private Animal animal=null;
@Override
public void service() {
this.animal.work();
}
@Override
public void setAnimal(Animal animal) { this.animal=animal; }}Copy the code
The results
____ ____ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \ / _ ` | \ \ \ \ \ \ / ___) | | _) | | | | | | | (_ | |))))' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.8. RELEASE) the 2019-09-30 09:41:57. 8276-385 the INFO [main] c.e xample. Acutator. AcutatorApplication: Starting AcutatorApplication on XXW4VSPSAQE4OR2 with PID 8276 (D:\ideaProject2\acutator\target\classes started by Item in D:\ideaProject2\acutator) 2019-09-30 09:41:57.388 INFO 8276 - [main] c.example.acutator.AcutatorApplication : No active profile set, falling back to default profiles: The default 09:41:58 2019-09-30. 8276-442 the INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: Tomcat initialized with port(s): 8080 (HTTP) 09:41:58 2019-09-30. 8276-463 the INFO [main] o.a pache, catalina. Core. StandardService: Starting the service [Tomcat] 2019-09-30 09:41:58. 463 INFO 8276 - [the main] org. Apache. Catalina. Core. StandardEngine: Starting Servlet engine: [Apache Tomcat/ 5.0.24] 2019-09-30 09:41:58.581 INFO 8276 -- [main] O.A.C.C.C. [Tomcat].[/] : Initializing Spring Embedded WebApplicationContext 2019-09-30 09:41:58.582 INFO 8276 -- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: Initialization Completed in 1163 MS 2019-09-30 09:41:58.940 INFO 8276 -- [main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'8276-2019-09-30 09:41:59. 119 INFO [main] O.S.B.A.E.W eb. EndpointLinksResolver: Exposing 14 endpoint(s) beneath base path '/actuator'8276-2019-09-30 09:41:59. 192 INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: tomcat is started on the port (s) : 8080 (http) with context path ''8276-2019-09-30 09:41:59. 195 INFO [main] c.e xample. Acutator. AcutatorApplication: Started AcutatorApplication in 2.072 seconds (JVM running for 2.762) *** Cat is catching a mouse [n(10)-127.0.0.1] O.A.C.C. [Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'8276-2019-09-30 09:42:00. 875 INFO [n (10) -- 127.0.0.1] O.S.W eb. Servlet. The DispatcherServlet: Initializing the servlet'dispatcherServlet'8276-2019-09-30 09:42:00. 880 INFO [n (10) -- 127.0.0.1] O.S.W eb. Servlet. The DispatcherServlet: Completed initialization in 5 msCopy the code
No problem at all, which means we’ve solved our ambiguity problem.
The life cycle of the Bean
How we have done it in front of the assembled Bean into the container, how to use into reference example, but we don’t know how the IoC container assembly and destruction process of Bean, sometimes in the instance we need to do some of the initialization process of specific work, such as to initialize the database connection, close the connection resources and so on. Therefore, we need to understand the Bean life cycle, understanding the life cycle can help us further understand Spring IoC and DI.
The definition of a Bean
- Earlier, we introduced the @ComponentScan annotation, which rules the scanning path and tells the IoC container where to look for beans to assemble. We call this resource localization.
- Once the resource is found, it begins to parse the information. At this point, the Bean has not been initialized, so there is no instance of the Bean. It is currently just a definition of the Bean, such as properties, methods, etc.
- Finally, the Bean definition is published to the IoC container, and the IoC container only has the Bean definition, which is still not instantiated
After completing the above three steps, Spring by default continues to instantiate and inject the Bean so that a dependency injection-completed Bean is available from the IoC container.
Initialization of the Bean
The IoC container starts instantiating the Bean when we call the getBean method of the BeanFactory. Ioc instantiates beans by implementing different functional interfaces according to the definition information of beans. The process is as follows.
-
Spring instantiates beans. The default bean is a singleton.
-
Spring does dependency injection for beans;
-
If the bean implements the BeanNameAware interface, Spring passes the bean id to the setBeanName() method;
-
If the bean implements the BeanFactoryAware interface, Spring calls the setBeanFactory method to pass in the BeanFactory instance.
-
If the bean implements the ApplicationContextAware interface, its setApplicationContext() method will be called, passing a reference to the application context into the bean;
-
If the bean implements the BeanPostProcessor interface, its postProcessBeforeInitialization methods are invoked;
-
If the bean implements the InitializingBean interface, Spring calls its afterPropertiesSet interface method, which is also called if the bean declares an initialization method with the init-method property.
-
If the bean implements the BeanPostProcessor interface, its postProcessAfterInitialization interface methods are invoked;
-
The beans are ready to be used by the application, and they reside in the application context until the application context is destroyed;
-
If the bean implements the DisposableBean interface, Spring will call its distroy() interface method. Similarly, if the bean declares a destroy method with the destroy-method attribute, the method is called;
Modify the BusinessPerson. Java
package com.example.acutator.entity;
import com.sun.org.apache.xml.internal.security.Init;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class BusinessPerson implements Person,BeanNameAware,BeanFactoryAware,ApplicationContextAware,InitializingBean,DisposableBean {
@Autowired
@Qualifier("cat")
private Animal animal=null;
@Override
public void service() {
this.animal.work();
}
@Override
public void setAnimal(Animal animal) {
this.animal=animal;
}
@PostConstruct
public void init(){
System.out.println("Bean initialization "" init");
}
@PreDestroy
public void destroy1(){
System.out.println("Bean initialization "destroy1");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Bean initialization "" setBeanFactory");
}
@Override
public void setBeanName(String name) {
System.out.println("Initialization of a Bean" "setBeanName");
}
@Override
public void destroy() throws Exception {
System.out.println("Bean initialization "" Destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Bean initialization "afterPropertiesSet);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("Bean initialization "setApplicationContext); }}Copy the code
Modifying the startup class
@SpringBootApplication
public class AcutatorApplication {
public static void main(String[] args) {
SpringApplication.run(AcutatorApplication.class, args);
ApplicationContext applicationContext=new AnnotationConfigApplicationContext(AppConfig.class);
// User user=applicationContext.getBean(User.class);
// System.out.println("user info>>"+user);
// Student student=applicationContext.getBean(Student.class);
// System.out.println("student info>>"+student); Person person=applicationContext.getBean(BusinessPerson.class); person.service(); ((AnnotationConfigApplicationContext) applicationContext).close(); }}Copy the code
The results
____ ____ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \ / _ ` | \ \ \ \ \ \ / ___) | | _) | | | | | | | (_ | |))))' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.8. RELEASE) the 2019-09-30 10:50:09. 5256-272 the INFO [main] c.e xample. Acutator. AcutatorApplication: Starting AcutatorApplication on XXW4VSPSAQE4OR2 with PID 5256 (D:\ideaProject2\acutator\target\classes started by Administrator in D:\ideaProject2\acutator) 2019-09-30 10:50:09.275 INFO 556 -- [main] c.example.acutator.AcutatorApplication : No active profile set, falling back to default profiles: The default 10:50:10 2019-09-30. 5256-167 the INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: Tomcat initialized with port(s): 8080 (HTTP) 10:50:10 2019-09-30. 5256-184 the INFO [main] o.a pache, catalina. Core. StandardService: Starting the service [Tomcat] 2019-09-30 10:50:10. 185 INFO 5256 - [the main] org. Apache. Catalina. Core. StandardEngine: Starting Servlet engine: [Apache Tomcat/ 5.0.24] 2019-09-30 10:50:10.291 INFO 5256 -- [main] O.A.C.C.C. [Tomcat].[/] : Initializing Spring Embedded WebApplicationContext 2019-09-30 10:50:10.291 INFO 5256 -- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: Initialization Completed in 986 ms Bean Initialization Completed in 986 ms Bean initialization Completed in 986 ms Bean initialization Completed in 986 ms Bean initialization Completed in 986 ms Bean initialization Completed in 986 ms Bean initialization AfterPropertiesSet 2019-09-30 10:50:10.731 INFO 5256 -- [main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'5256-2019-09-30 10:50:10. 919 INFO [main] O.S.B.A.E.W eb. EndpointLinksResolver: Exposing 14 endpoint(s) beneath base path '/actuator'5256-2019-09-30 10:50:10. 974 INFO [main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: tomcat is started on the port (s) : 8080 (http) with context path ''5256-2019-09-30 10:50:10. 976 INFO [main] c.e xample. Acutator. AcutatorApplication: Started AcutatorApplication in 1.994 seconds (JVM running for 2.725 Bean initialization "" setApplicationContext Bean initialization" "Init Bean initialization" "afterPropertiesSet *** The cat is catching the mouse *** Bean initialization" "Destroy1 Destroy 2019-09-30 10:50:12.794 INFO 5256 -- [on(8)-127.0.0.1] O.A.C.C.C. [Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'5256-2019-09-30 10:50:12. 794 INFO/on (8) - 127.0.0.1 O.S.W eb. Servlet. The DispatcherServlet: Initializing the servlet'dispatcherServlet'5256-2019-09-30 10:50:12. 800 INFO/on (8) - 127.0.0.1 O.S.W eb. Servlet. The DispatcherServlet: Completed initialization in 6 msCopy the code
Why did multiple initializations occur, and what did the above initializations do not perform the destruction method?
Analysis:
We previously did a configuration using the appConfig.java class and scanned all classes under the Entity package using annotations. If the class name is annotated @Component, then there are two IoC containers that manage the class. A is the default of the IoC container, the other is AnnotationConfigApplicationContext by constructing create container, namely ApplicationContext, we know that all the container top interface is the BeanFactory, The ApplicationContext is extended on top of the BeanFactory, which is much more powerful. If we think of the BeanFactory as the heart of the human body, the ApplicationContext is the body.
So you can think of two containers assembling and injecting beans at the same time, so there are two initialization messages.
The above is just a simple description of the life cycle. For details, please refer to the official document description and then compare it with this paper to understand it slowly. I believe I will gain more.
conclusion
Please correct the mistake, thank you very much!