@Configuration+@Bean
Front
Create User and Pet classes
public class User { private String name; private Integer age; public User(){ } public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
public class Pet { private String name; public Pet(){ } public Pet(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
In the previous study of Spring, we usually inject components into the container through the configuration file.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--stay spring Practice in--> <bean id="user01" class="com.zjh.boot.bean.User"> <property name="name" value="zjh"></property> <property name="age" value="20"></property> </bean> <bean id="cat01" class="com.zjh.boot.bean.Pet"> <property name="name" value="tomcat"></property> </bean> </beans>
In Springboot, we can register components through two annotations to inject @ Configuration+@Bean into the container.
We create a class MyConfig in which we declare two methods to return the User object and the Pet object
@Configuration public class MyConfig { @Bean // The method name will be put into the container as the id of the component, the return type is the component type, and the returned object is the instance saved by the component in the container public User userConfig(){ User user = new User("zjh", 200); user.setPet(petConfig()); return user; } @Bean // bean tags can have custom names public Pet petConfig(){ return new Pet("tomcat"); } }
@Configuration is declared on the class. It is declared that this class is a configuration class, which is equivalent to the configuration file xml in Spring. This configuration class will be scanned into the IOC container. The component name is the class name (if the initial letter of the class name is uppercase, it will be automatically converted to lowercase). We can customize the component name through the value attribute
@When Bean is declared on the method, it will also scan the return value of the method into the container. The component name is the method name (if the initial letter of the method name is uppercase, it will be automatically converted to lowercase). We can customize the component name through the name attribute.
Is the component a single instance?
@SpringBootApplication public class MainApplication { public static void main(String[] args) { // 1. Return to IOC container ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 2. Check the components in the container String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } System.out.println("================="); Pet pet01 = run.getBean("petConfig",Pet.class); Pet pet02 = run.getBean("petConfig",Pet.class); System.out.println("pet01 Is equal to pet02 ? "+ (pet01 == pet02)); } }
From the results, we can know that the components in the IOC container are single instance.
How to set to multi instance?
Just declare * * @ Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) on the method**
proxyBeanMethods
@The proxyBeanMethods property in Configuration is true by default. What is the meaning of the proxyBeanMethods property?
proxyBeanMethods is translated into proxy bean methods.
The myConfig component we obtained from the container defines two methods * * userConfig() and petConfig(). Then the question arises. If I obtain the myConfig component, do I call its petConfig() * * method to obtain the same pet instance as that obtained directly from the container?
We test a wave
@SpringBootApplication public class MainApplication { public static void main(String[] args) { // 1. Return to IOC container ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 2. Check the components in the container String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } Pet pet01 = run.getBean("petConfig",Pet.class); MyConfig myConfig = run.getBean("myConfig", MyConfig.class); Pet pet = myConfig.petConfig(); System.out.println("Judge whether the component is taken out pet Is it the same as the one taken from the configuration file pet Are they the same? " +(pet == pet01)); } }
From the conclusion, if proxyBeanMethods=true, the result is true. When proxyBeanMethods=false, the result is false.
Conclusion: if configuration is true, the obtained myConfig is the proxy object. When calling the method of the proxy object, it will check whether there is a matching component in the IOC. If there is, it will be taken directly. If not, it will be created, that is, it will maintain a single instance of the component
springboot has two configurations at the bottom of Configuration: full (proxyBeanMethods is true full Configuration) lite (proxyBeanMethods is false lightweight Configuration)
So what scenario is this to solve?
Component dependency
For example, we have a pet attribute in user
public class User { private String name; private Integer age; private Pet pet; public User(){ } public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Pet getPet() { return pet; } public void setPet(Pet pet) { this.pet = pet; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
@Configuration (proxyBeanMethods = true) public class MyConfig { @Bean // The method name will be put into the container as the id of the component, the return type is the component type, and the returned object is the instance saved by the component in the container public User userConfig(){ User user = new User("zjh", 200); user.setPet(petConfig()); return user; } @Bean // bean tags can have custom names public Pet petConfig(){ return new Pet("tomcat"); } }
If we get the user component and call the getPet() method in it, is the pet obtained the same as the pet component directly taken from the container? proxyBeanMethods = true
@SpringBootApplication public class MainApplication { public static void main(String[] args) { // 1. Return to IOC container ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 2. Check the components in the container String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } Pet pet01 = run.getBean("petConfig",Pet.class); System.out.println("================="); User user = run.getBean("userConfig", User.class); Pet user_pet = user.getPet(); System.out.println("user Inside pet And in the container pet Is it the same "+(user_pet == pet01));
Conclusion: proxyBeanMethods = true. If the class and its methods obtain instances, they will first go to the IOC to find out whether there are matching instances. If there are, they will be taken directly. If not, they will be created. If proxyBeanMethods = false, they will be created directly.
Advantages of false proxyBeanMethods: springboot will not check in the container, and the running speed will be accelerated, but it will increase the memory overhead.
If you only register components and do not involve calls between components, it is recommended to use lite mode, and vice versa.