Define spring beans
Bean definition in the corresponding code is the configuration meta information interface of beans defined in the Spring Framework, mainly including:
- Bean's class name, fully qualified name, concrete implementation class
- Bean configuration meta information: scope, Auto Wiring, lifecycle callback
- Bean References: Collaborators or Dependencies,
- Configured settings: Bean properties (such as connection pool size)
BeanDefinition meta information
overview
attribute | explain | remarks |
---|---|---|
Class | The class name cannot be the full abstract class name | |
Name | Name or ID of the Bean | |
Scope | Scope of Bean (singleton, prototype,...) | |
Constructor arguments | Bean constructor parameters (for dependency injection) | |
Properties | Attribute setting of Bean (for dependency injection) | |
Autowiring mode | Bean automatic binding mode (for example, byName...) | |
Lazy initialization mode | Bean delay initialization (delay "reinitialization when necessary, shorten the time" and non delay "default") | |
Initialization method | Bean initialization callback method name | |
Destruction method | Bean destroy callback method name |
structure
Through BeanDefinitionBuilder
// 1. Build through BeanDefinitionBuilder BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class); // "beanDefinitionBuilder.addPropertyValue("name","Steve").addPropertyValue("id",30);" can be used here through property setting (adding one by one) beanDefinitionBuilder.addPropertyValue("name","Steve"); beanDefinitionBuilder.addPropertyValue("id",30); // Get BeanDefinition instance BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); // Beandefinition has many set methods. Beandefinition is not the final state of a Bean and can be customized and modified
Through AbstractBeanDefinition and derived classes
// 2. Through AbstractBeanDefinition and derived classes GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition(); // Set Bean type genericBeanDefinition.setBeanClass(User.class); // Through MutablePropertyValues batch operation, you can use "propertyValues.add("name","Steve").add("id",31)" here MutablePropertyValues propertyValues = new MutablePropertyValues(); propertyValues.addPropertyValue("name","Steve"); propertyValues.addPropertyValue("id",31); genericBeanDefinition.setPropertyValues(propertyValues);
Name Spring Bean
Bean name
Recommended reading: Naming of bean s learned by spring - segmentfault
Each Bean has one or more identifiers, which should be unique in the container where the Bean is located. Usually, a Bean has an identifier. If additional identifiers are needed, alias extension is used.
In the case of XML, the identifier of the Bean can be specified with the id or name attribute. If you want to use an alias, use "" or "" in the name attribute separate.
The id or name of the Bean can be left blank. When left blank, the container will automatically generate a unique name for the Bean. Hump is recommended, which conforms to Java Naming standard.
Two implementations of BeanNameGenerator can be viewed in Spring.
Annotation implementation
For details: AnnotationBeanNameGenerator
For example, @ component, @ Repository, @ Service, @ Controller and so on are used. In fact, the latter three simply package the first layer
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Service { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ @AliasFor(annotation = Component.class) String value() default ""; }
Default implementation
See DefaultBeanNameGenerator for details
Alias of Spring Bean
benefit
- Existing BeanDefinitio can be reused
- The usage scenario can be seen through naming (for example, the same Bean is called beanInA in system A and beanInB in system B)
Register Spring Bean
Basics
XML configuration meta information
Java annotation
@Bean,@Component,@Import
Java API configuration meta information
- Naming method: beandefinitionregistry#registerbeandefinition (string beanname, beandefinition, beandefinition)
- Non naming method: beandifinitionreaderutils#registerwithgeneratedname (abstractbeandefinition definition, beandefinitionregistry)
- Class configuration method: AnnotatedBeanDefinitionReader#register(Class <? >... Componentclasses)
code
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition; /** * Annotation BeanDefinition example * * @author Steve * @date */ @Import(AnnotationBeanDefinitionDemo.Config.class)// Import via import @ public class AnnotationBeanDefinitionDemo { public static void main(String[] args) { // Create BeanFactory container AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // Register configuration class // Mode 3: configuration mode; See: annotationconfigapplicationcontext #register (class <? >... Componentclasses) - > annotatedbeandefinitionreader #register (class <? >... Componentclasses) applicationContext.register(AnnotationBeanDefinitionDemo.class); registerUserBeanDefinition(applicationContext,"mindartisan-user"); registerUserBeanDefinition(applicationContext); // Launch Spring application context applicationContext.refresh(); // Output Bean of config type: {com.mindartesan.spring.geek.Bean.definition.annotationbeandefinitiondemo $config = com.mindartesan.spring.geek.Bean.definition.annotationbeandefinitiondemo$ Config@7f416310 } System.out.println("Config Type Bean: " + applicationContext.getBeansOfType(Config.class)); // Bean of User type: {user=User{id=1, name='Steve '}} System.out.println("User Type Bean: " + applicationContext.getBeansOfType(User.class)); // Close the Spring application context applicationContext.close(); } /** * bean Registration method of * * @param beanDefinitionRegistry * @param beanName */ public static void registerUserBeanDefinition(BeanDefinitionRegistry beanDefinitionRegistry, String beanName) { BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(User.class); beanDefinitionBuilder .addPropertyValue("id", 1L) .addPropertyValue("name", "Steve"); if (StringUtils.hasText(beanName)) { // Register BeanDefinition by naming method beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition()); } else { // Non naming method BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), beanDefinitionRegistry); } } public static void registerUserBeanDefinition(BeanDefinitionRegistry beanDefinitionRegistry) { registerUserBeanDefinition(beanDefinitionRegistry, null); } @Component// Define the current class as a Spring Bean (Component) through @ Component public static class Config { /** * Define beans through Java annotations * * @return */ @Bean(name = {"user", "steve-user"})// Define a Bean through @ Bean public User user() { User user = new User(); user.setId(1L); user.setName("Steve"); return user; } } }
extend
The SingletonBeanRegistry#registerSingleton(String beanName, Object singletonObject) is mainly used to register through external monomer objects; method
SingtonBeanRegistrationDemo.class:
/** * External monomer Bean registration instance * External bean s: classes that are not managed by Spring * * @author Steve * @date */ public class SingtonBeanRegistrationDemo { public static void main(String[] args) { // Create BeanFactory container AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // The userFactory here is not managed by Spring UserFactory userFactory = new DefaultUserFactory(); ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory(); // Launch Spring application context applicationContext.refresh(); // Registering external singleton objects beanFactory.registerSingleton("userFactory", userFactory); // Get userFactory through dependency lookup UserFactory userFactoryByLookup = beanFactory.getBean("userFactory", UserFactory.class); System.out.println("userFactory == userFactoryByLookup: " + (userFactory == userFactoryByLookup)); // Close the Spring application context applicationContext.close(); } }
Instantiate Spring Bean
routine
Through the constructor (configuration meta information: XML, Java annotation, Java API)
Through static factory method (configuration meta information: XML, Java API)
Through Bean factory method (configuration meta information: XML, Java API)
Through FactoryBean (configuration meta information: XML, Java annotation, Java API)
code
See the comments in xml and the naming in the main method for details
User.class:
/** * user * * @author Steve * @date */ public class User { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } /** * Instantiate by static method * * @return {@link User} */ public static User createUser(){ User user = new User(); user.setId(1L); user.setName("Steve"); return user; } }
bean-instantiation-context.xml:
<?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"> <!--Static method instantiation Bean--> <bean id="user-by-static-method" class="com.mindartisan.spring.geek.ioc.overview.domain.User" factory-method="createUser"/> <!--example Bean Method instantiation bean--> <bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/> <bean id="userFactory" class="com.mindartisan.spring.geek.bean.factory.DefaultUserFactory"/> <!--FactoryBean instantiation bean--> <bean id="user-by-factory-bean" class="com.mindartisan.spring.geek.bean.factory.UserFactoryBean"/> </beans>
BeanInstantinationDemo.class:
/** * Bean Instantiate demo * * @author Steve * @date */ public class BeanInstantinationDemo { public static void main(String[] args) { BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/bean-instantiation-context.xml"); User userByStaticMethod = beanFactory.getBean("user-by-static-method", User.class); // Output "User{id=1, name='Steve '}" System.out.println(userByStaticMethod); User userByInstanceMethod = beanFactory.getBean("user-by-instance-method", User.class); // Output "User{id=1, name='Steve '}" System.out.println(userByInstanceMethod); // Output "false" System.out.println(userByStaticMethod == userByInstanceMethod); User userByFactoryBean = beanFactory.getBean("user-by-factory-bean", User.class); // Output "User{id=1, name='Steve '}" System.out.println(userByFactoryBean); // Output "false" System.out.println(userByStaticMethod == userByFactoryBean); // Output "false" System.out.println(userByFactoryBean == userByInstanceMethod); } }
UserFactory.class:
/** * Factory class * * @author Steve * @date */ public interface UserFactory { default User createUser(){ return User.createUser(); } }
DefaultUserFactory.class:
/** * Default user factory * * @author Steve * @date */ public class DefaultUserFactory implements UserFactory { }
UserFactoryBean.class:
/** * Implementation of FactoryBean * * @author Steve * @date */ public class UserFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { return User.createUser(); } @Override public Class<?> getObjectType() { return User.class; } }
special
Through ServiceLoaderFactoryBean (configuration meta information: XML, Java annotation, Java API)
Through AutowireCapableBeanFactory#createBean(Java.lang.Class,int,boolean)
Through BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
reference resources: Register spring bean - > java api configuration meta information
code
SpecialBeanInstantinationDemo.class:
package com.mindartisan.spring.geek.bean.definition; import com.mindartisan.spring.geek.bean.factory.DefaultUserFactory; import com.mindartisan.spring.geek.bean.factory.UserFactory; import com.mindartisan.spring.geek.ioc.overview.domain.User; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.Iterator; import java.util.ServiceLoader; /** * Special Bean instantiation demo * * @author Steve * @date */ public class SpecialBeanInstantinationDemo { public static void main(String[] args) { // serviceloader BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/special-bean-instantiation-context.xml"); // Create a ServiceLoader from ServiceLoaderFactoryBean, and then get all the implementation classes of the ServiceLoader through traversal // In this code, create an implementation of "SecondUserFactory", and displayServiceLoader will output two "User{id=1, name='Steve '}" ServiceLoader<UserFactory> userFactoryServiceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class); displayServiceLoader(userFactoryServiceLoader); // demoServiceLoader(); System.out.println("---------------"); // Obtain autowireCapableBeanFactory through applicationContext ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/special-bean-instantiation-context.xml"); AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory(); // Create a userFactory object from autowireCapableBeanFactory // Note: when autowirecapablebeanfactory #createbean (class < T > beanClass), beanClass should be a specific class, not an interface or abstract class UserFactory userFactory = autowireCapableBeanFactory.createBean(DefaultUserFactory.class); User user = userFactory.createUser(); // Output "User{id=1, name='Steve '}" System.out.println(user); } /** * serviceloader demo */ public static void demoServiceLoader() { ServiceLoader<UserFactory> userFactoryServiceLoader = ServiceLoader.load(UserFactory.class, Thread.currentThread().getContextClassLoader()); displayServiceLoader(userFactoryServiceLoader); } public static void displayServiceLoader(ServiceLoader<UserFactory> userFactoryServiceLoader) { Iterator<UserFactory> userFactoryIterator = userFactoryServiceLoader.iterator(); while (userFactoryIterator.hasNext()) { UserFactory userFactory = userFactoryIterator.next(); // Output "User{id=1, name='Steve '}" System.out.println(userFactory.createUser()); } } }
special-bean-instantiation-context.xml:
<?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"> <bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean"> <property name="serviceType" value="com.mindartisan.spring.geek.bean.factory.UserFactory"/> </bean> </beans>
SecondUserFactory.class:
/** * Secondary user factory * * @author Steve * @date */ public class SecondUserFactory implements UserFactory { }
META-INF/services/com.mindartisan.spring.geek.bean.factory.UserFactory
Related to ServiceLoader
com.mindartisan.spring.geek.bean.factory.DefaultUserFactory com.mindartisan.spring.geek.bean.factory.SecondUserFactory
The above specifies com mindartisan. spring. geek. bean. factory. Implementation class of userfactory
Extension: ServiceLoader
Embodies SPI mechanism
ServiceLoader of JDK
In the main method, the ServiceLoader provided by JDK is used. Above_ META-INF/services/com.mindartisan.spring.geek.bean.factory.UserFactory__ Why in_ META/INF/services is under this path because of the following codes in ServiceLoader:
private static final String PREFIX = "META-INF/services/";
"ServiceLoader" in Spring
In Spring, it also provides the implementation of ServiceLoader in JDK: serviceloaderfactorybean Class, its parent class abstractserviceloaderbasedfactorybean Class has three subclasses, as follows:
There are three different implementations of abstractserviceloaderbasedfactorybean #getobjecttoexpose (serviceloader <? > serviceloader) in the three subclasses:
- ServiceFactoryBean: returns a
- ServiceLoaderFactoryBean:
- ServiceListFactoryBean: returns all
When using, you should also pay attention to setting serviceType. The configuration method of xml is as follows:
<bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean"> <property name="serviceType" value="com.mindartisan.spring.geek.bean.factory.UserFactory"/> </bean>
Initialize Spring Bean
realization
- @PostConstruct annotation method
- Implement the afterpropertieset() method of the InitializingBean interface
- Custom initialization method
- XML configuration: < bean init method = "init"... / >
- Java annotation: @ Bean(initMethod = "init")
- Java API: AbstractBeanDefinition#setInitMethodName(String)
code
BeanInitializationDemo.class
@Configuration public class BeanInitializationDemo { public static void main(String[] args) { // Create BeanFactory container AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.register(BeanInitializationDemo.class); // Launch Spring application context applicationContext.refresh(); UserFactory userFactory = applicationContext.getBean(UserFactory.class); // Close the Spring application context applicationContext.close(); } @Bean(initMethod = "initUserFactory") public UserFactory userFactory() { return new DefaultUserFactory(); } }
DefaultUserFactory.class
/** * Default user factory * * @author Steve * @date */ public class DefaultUserFactory implements UserFactory, InitializingBean { // Bean initialization use // 1. Annotation based on @ PostConstruct @PostConstruct public void init() { System.out.println("@PostConstruct: UserFactory Initializing"); } public void initUserFactory() { System.out.println("Custom initialization method initUserFactory(): UserFactory Initializing"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("afterPropertiesSet: UserFactory Initializing"); } }
order
reference resources: Spring official
- Using annotations
- Inherit interface, override method
- Manual configuration method
Delay initializing spring beans
realization
- XML configuration < bean lazy init = "true"... / >
- Java annotation: @ Lazy
code:
BeanInitializationDemo.class
@Configuration public class BeanInitializationDemo { public static void main(String[] args) { // Create BeanFactory container AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.register(BeanInitializationDemo.class); // Launch Spring application context applicationContext.refresh(); // Non deferred initialization is initialized after the Spring application context is started System.out.println("Spring Application context started"); UserFactory userFactory = applicationContext.getBean(UserFactory.class); System.out.println("Used @Lazy annotation「Currently true」: "+userFactory); // Close the Spring application context applicationContext.close(); } @Bean(initMethod = "initUserFactory") @Lazy(value = true) public UserFactory userFactory() { return new DefaultUserFactory(); } }
When @ Lazy(value = true), the following contents are output:
Spring application context has been started
@PostConstruct: UserFactory initializing
afterPropertiesSet: UserFactory is initializing
User defined initialization method initUserFactory(): in UserFactory initialization
The @ Lazy Annotation "currently true" is used: com mindartisan. spring. geek. bean. factory. DefaultUserFactory@197d671
BeanInitializationDemo.class
@Configuration public class BeanInitializationDemo { public static void main(String[] args) { // Create BeanFactory container AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.register(BeanInitializationDemo.class); // Launch Spring application context applicationContext.refresh(); // Non deferred initialization is initialized after the Spring application context is started System.out.println("Spring Application context started"); UserFactory userFactory = applicationContext.getBean(UserFactory.class); System.out.println("Used @Lazy annotation「Currently false」: "+userFactory); // Close the Spring application context applicationContext.close(); } @Bean(initMethod = "initUserFactory") @Lazy(value = false) public UserFactory userFactory() { return new DefaultUserFactory(); } }
When @ lazy (value = false), the following contents are output:
@PostConstruct: UserFactory initializing
afterPropertiesSet: UserFactory is initializing
User defined initialization method initUserFactory(): in UserFactory initialization
Spring application context has been started
The @ Lazy Annotation "currently false" is used: com mindartisan. spring. geek. bean. factory. DefaultUserFactory@6b4a4e18
The main difference between delayed initialization and non delayed initialization is that delayed initialization follows the Spring application context and non delayed initialization precedes it.
Destroy spring beans
mode
- @PreDestory annotation method
- Implement the disposablebean #destroy() method
- Custom destruction method
- XML configuration: < bean destroy = "XXX"... / >
- Java annotation: @ Bean(destroy = "xxx")
- Java API: AbstractBeanDefinition#setDestroyMethodName(String)
code
BeanInitializationDemo.class
@Configuration public class BeanInitializationDemo { public static void main(String[] args) { // Create BeanFactory container AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.register(BeanInitializationDemo.class); // Launch Spring application context applicationContext.refresh(); // Non deferred initialization is initialized after the Spring application context is started System.out.println("Spring Application context started"); UserFactory userFactory = applicationContext.getBean(UserFactory.class); System.out.println("Used @Lazy annotation「Currently false」: "+userFactory); System.out.println("Spring Application context ready to close"); // Close the Spring application context applicationContext.close(); System.out.println("Spring The application context has been closed"); } @Bean(initMethod = "initUserFactory",destroyMethod = "doDestroy") @Lazy(value = false) public UserFactory userFactory() { return new DefaultUserFactory(); } }
DefaultUserFactory.class:
/** * Default user factory * * @author Steve * @date */ public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean { // Bean initialization use // 1. Annotation based on @ PostConstruct @PostConstruct public void init() { System.out.println("@PostConstruct: UserFactory Initializing"); } public void initUserFactory() { System.out.println("Custom initialization method initUserFactory(): UserFactory Initializing"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("afterPropertiesSet: UserFactory Initializing"); } @PreDestroy public void preDestroy() { System.out.println("@PreDestroy: UserFactory Destroying"); } @Override public void destroy() throws Exception { System.out.println("DisposableBean#destroy(): UserFactory is destroying ""); } /** * Custom destruction method */ public void doDestroy() { System.out.println("Custom destruction method doDestroy(): UserFactory Destroying"); } }
When @ lazy (value = false), the following contents are output:
@PostConstruct: UserFactory initializing
afterPropertiesSet: UserFactory is initializing
User defined initialization method initUserFactory(): in UserFactory initialization
Spring application context has been started
The @ Lazy Annotation "currently false" is used: com mindartisan. spring. geek. bean. factory. DefaultUserFactory@197d671
The Spring application context is ready to close
@PreDestroy: UserFactory is being destroyed
DisposableBean#destroy(): UserFactory is being destroyed
User defined destruction method doDestroy(): in UserFactory destruction
Spring app context has been closed
order
reference resources: Spring official
- Using annotations
- Inherit interface, override method
- Manual configuration method
Source code analysis
@PreDestory annotation method
It's relatively simple. Directly search the usage of @ PreDestory in IDEA:
- CommonAnnotationBeanPostProcessor.CommonAnnotationBeanPostProcessor();
- InitDestroyAnnotationBeanPostProcessor.setDestroyAnnotationType()
Then search the destroyAnnotationType under the current class, and you will find that reflection is used in the buildlife metadata () method to find the annotated methods. If any, it will be added to the collection of destruction methods currdestroymethods add(new LifecycleElement(method));
Implement the disposablebean #destroy() method
First, look at the output above and make sure it is in ApplicationContext Close() destroy the Bean:
- AbstractApplicationContext.close();
- AbstractApplicationContext.doClose();
- AbstractApplicationContext.destroyBeans();
- ConfigurableBeanFactory.destroySingletons();
- DefaultListableBeanFactory.destroySingletons();
- DefaultSingletonBeanRegistry.destroySingletons(); "Here, the next step is called by traversing the loop"
- DefaultSingletonBeanRegistry.destroySingleton();
- DefaultSingletonBeanRegistry.destroyBean(String beanName, @Nullable DisposableBean bean);
- DisposableBean.destroy();
Garbage collection Spring Bean
- Not understood, to do