An overview of the
In terms of bean types, Spring divides beans into normal beans and factoryBeans. There are also two ways to declare beans: @Component and @bean. So let’s take a look at the similarities and differences in how these beans are instantiated. Here we call Normal beans and @Component legitimate beans because they are instantiated in a public way, whereas factoryBeans and @Beans are not legitimate beans because they are instantiated in a somewhat niche way. I don’t think there is good or bad, just like people, what you like is good.
You gain
What can you get out of this article?
- The Normal Bean and @Component generate an entry to the beanDefinition
- How do the beanDefinition of normal Beans and @Component generate bean instances and put them into the Spring container
- The @bean generates an entry to the beanDefinition
- How does the @bean beanDefinition generate a Bean instance and put it into the Spring container, where instance might bea proxy class
- The FactoryBean generates an entry to the beanDefinition
- How does the beanDefinition of A FactoryBean generate a bean instance and put it into the Spring container, where instance might bea proxy class
- The connections and differences between these different types of beans generate bean instance procedures
This article is focused and concise, and I hope you have some insights and ideas
The sample
Below, we list the classes that are commonly used in practice, one for each type of bean, so that we can align our thinking
import com.skyler.project // normal bean @Service public class UserServiceImpl implements IUserService { @Override Public int insert(User User) {}} // @bean declared class @configuration public class MapperAutoConfiguration {@bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) } }Copy the code
Different types of beans generate an entry to the BeanDefinition, as shown in the figure below, which we will call “entry diagrams” for later introduction.
The figure shows the entry for generating BeanDefinitions from.class files of different types of classes, as well as the big-box process and entry for general-purpose beanDefinition generating bean Instance or proxy proxy classes
Normal beans and beans of @Component type
The entrance
See entrance diagram above
Specific BeanDefinition
Normal beans and beans of type @Component generate BeanDefinitions as rootBeanDefinitions. The key attributes at this point are
resolvedTargetType=com.skyler.project.UserServiceImpl resolvedConstructorOrFactoryMethod=com.skyler.project.UserServiceImpl beanClass=com.skyler.project.UserServiceImpl AutowireMode = 0 attributes extenallyManagedConfigMembers = deposit is a member of the bean propertiesCopy the code
At the end of the article, the object attribute comparison diagram of BeanDefinition’s @Component declared bean, @Bean declared bean, and Bean of FactoryBean type is posted
How does beanDefinition generate bean instance
How does beanDefinition generate the bean instance trace
UserServiceImpl:
AbstractBeanFactory.getBean
AbstractBeanFactory.doGetBean
DefaultSingletonBeanRegistry.getSingleton
AbstractAutowireCapableBeanFactory.createBean
AbstractAutowireCapableBeanFactory.doCreateBean
--this.createBeanInstance
----resolveBeanClass
----instantiateBean
AbstractAutowireCapableBeanFactory.populateBean
--AutowiredAnnotationBeanPostProcessor.postProcessProperties forBeanPostProcessor.postProcessProperties ----InjectionMetadata.inject AbstractAutowireCapableBeanFactory.initializeBean // Use AbstractAdvisor to generate a proxy classCopy the code
Bean of type @bean
The entrance
See entrance diagram above
Specific BeanDefinition
At this time for ConfigurationClassBeanDefinition BeanDefinition type. Taking @bean SqlSessionFactory as an example, the key attributes are
factoryMethodMetadata
autowireMode=3
factoryBeanName=tk.mybatis.mapper.autoconfigure.MapperAutoConfiguration
factoryMethodName=sqlSessionFactory
factoryMethodReturnType
Copy the code
At the end of the article, the object attribute comparison diagram of BeanDefinition’s @Component declared bean, @Bean declared bean, and Bean of FactoryBean type is posted
How does beanDefinition generate bean instance
How does beanDefinition generate the bean instance trace
AbstractBeanFactory.getBean
AbstractBeanFactory.doGetBean
DefaultSingletonBeanRegistry.getSingleton
AbstractAutowireCapableBeanFactory.createBean
AbstractAutowireCapableBeanFactory.doCreateBean
--this.createBeanInstance
----this.instantiateUsingFactoryMethod
------ConstructorResolver.instantiateUsingFactoryMethod
--------ConfigurationClassEnhancer$BeanMethdoInterceptor
Copy the code
You can view the debug running trace more clearly
Bean of type @Configuration
The entrance
See entrance diagram above
Specific BeanDefinition
At this time for ConfigurationClassBeanDefinition BeanDefinition type. A bean of type @Configuration generates a BeanDefinition in a special way, as shown in the figure below
How does beanDefinition generate bean instance
AbstractBeanFactory.getBean AbstractBeanFactory.doGetBean DefaultSingletonBeanRegistry.getSingleton AbstractAutowireCapableBeanFactory.createBean AbstractAutowireCapableBeanFactory.doCreateBean -- AbstractAutowireCapableBeanFactory. AutowireConstructor if the constructorCopy the code
You can view the debug running trace more clearly. So let’s take MapperAutoConfiguration as an example
A bean of type FactoryBean
The entrance
There is no entry for FactoryBean’s.class file to generate a beanDefinition. Because a FactoryBean is a special bean. Take a look at its usage and situations. A FactoryBean is first a bean, and second, a factory bean: what does a factory bean do? Producing beans. How to produce it? What are the benefits of producing with the factoryBean.getobject () method? Or what does a FactoryBean mean?
FactoryBean produces products, not FactoryBeans themselves. That is, the object returned by a FactoryBean is not an instance of the specified class. It returns the object returned by the FactoryBean’s getObject method. A FactoryBean is special in that it can register two beans to the container, one itself and the Bean represented by the return value of the factoryBean.getobject () method. Within the Spring framework, there are many implementation classes for FactoryBeans, which are used in many applications (Spring AOP, ORM, transaction management)
So, the FactoryBean interface is an extension point for the instantiation logic of the Spring IoC container. If the initialization code is complex, you can customize a FactoryBean in this scenario, write complex initializers in the class, and add them to the container as plug-ins. Both Spring Cloud openFeign and Mybatis Mapper apply this technique to the actual working code
// Spring Cloud openFeign declares a FeignClient @feignClient (value =)"${provider.application:skyler-base}", contextId = "SkylerComboFeignService")
public interface SkylerComboFeignService {
@PostMapping(value = "api/skyler/combo/create", produces = MediaType.APPLICATION_JSON_VALUE)
ResultDTO create(@RequestBody ComboParam param);
@GetMapping(value = "api/skyler/combo/list") ResultDTO<Page<ComboDTO>> listCombo(Long comboId, Integer currentPage,Integer pageSize); } @repository public interface ComboMapper {int insert(Combo record); List<Combo> selectByExample(ComboExample example); } @Service public class ComboService { @AutoWired ComboMapper comboMapper; }Copy the code
I’m sure you’re familiar with these two pieces of code, both of which are commonly used in development. As soon as we declare/define this, we can use Feign to call the database remotely, and all of this is done by FactoryBean.
So the openFeign entry is at FeignClientsRegistrar; The entry point to Mybatis Mapper is at MapperScannerRegistrar.
Specific BeanDefinition
The BeanDefinition type is RootBeanDefinition. Taking @FeignClient and Mybatis Mapper as an example, the key attributes are as follows
propertyValues=MutablePropertyValues
resolvedTargetType=org.springframework.cloud.openfeign.FeignClientFactoryBean
resolvedConstructorOrFactoryMethod=org.springframework.cloud.openfeign.FeignClientFactoryBean
beanClass=org.springframework.cloud.openfeign.FeignClientFactoryBean
autowireMode=2
Copy the code
At the end of the article, the object attribute comparison diagram of BeanDefinition’s @Component declared bean, @Bean declared bean, and Bean of FactoryBean type is posted
How does beanDefinition generate bean instance
@feignClient generates the bean instance/ instantiation process as follows
AbstractBeanFactory.getBean AbstractBeanFactory.doGetBean AbstractBeanFactory.getObjectForBeanInstance FactoryBeanRegistrySupport.getObjectFromFactoryBean FactoryBeanRegistrySupport.doGetObjectFromFactoryBean object = factory.getObject(); // Factory is a FactoryBean typeCopy the code
Mybatis Mapper generates bean instance/ instantiation as follows
AbstractBeanFactory.getBean AbstractBeanFactory.doGetBean DefaultSingletonBeanRegistry.getSingleton AbstractAutowireCapableBeanFactory.createBean AbstractAutowireCapableBeanFactory.doCreateBean AbstractAutowireCapableBeanFactory.populateBean AbstractAutowireCapableBeanFactory.autowireByType(beanName, mbd, bw, PVS) / / to PVS assignment and MBD setPropertyValues (PVS) AbstractAutowireCapableBeanFactory. ApplyPropertyValues (beanName, MBD, bw, PVS) // Assigns PVS to bw. PropertyValues // assigns the sqlSession property of userMapper's MapperFactoryBean AbstractAutowireCapableBeanFactory.initializeBean AbstractAutowireCapableBeanFactory.invokeInitMethods // MapperFactoryBean DaoSupport and InitializingBean subtype DaoSupport. AfterPropertiesSet AbstractBeanFactory.getObjectForBeanInstance FactoryBeanRegistrySupport.getObjectFromFactoryBean FactoryBeanRegistrySupport.doGetObjectFromFactoryBean object = factory.getObject(); // Factory is a FactoryBean(MapperFactoryBean) object is a proxy object, Generated as follows other MapperProxy = MapperProxyFactory. NewInstance (sqlSession) / / generated proxy class object MapperProxy userMapper Above is ComboMapper generated proxy class MapperProxy process, and then assigned to ComboService.com boMapper, assignment method is field. The set (target, MapperProxy), field for ComboMapper; Target for ComboServiceCopy the code
Comparison diagram of BeanDefinition object properties of different types
The picture is a little unclear, so I’ll take a screenshot of it on the big screen
it`s time to summary
The purpose of this article is to give you a ladder by sorting out where the different types of beans come in to generate BeanDefinitions. With this ladder, you can quickly locate a given location and track code and filaments in greater detail. To truly understand how technology works, it takes more than reading articles. You have to do it yourself. So, the purpose of this article is to shorten your path to learning technical principles and save valuable time for more important things.
extension
After peeling the skin, we can see how beanDefinition generates bean instance. We can see from the source code that all bean instances end up calling the getObjectForBeanInstance() method. The getObjectForBeanInstance() method determines whether the bean is a FactoryBean, and if not, returns the bean directly. If it is a FactoryBean and name begins with an ampersand, it represents the native object from which the FactoryBean was obtained, and will be returned directly. If name does not begin with an ampersand, it means that you want to get the object returned by the getObject() method in FactoryBean. The code is as follows
AbstractBeanFactory class
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
Object sharedInstance = getSingleton(beanName);
if(sharedInstance ! = null && args == null) { bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }else {
if (mbd.isSingleton()) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else{ bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); }}return (T) bean;
}
Copy the code
A picture of a lake relaxes your mind