Spring extension point five: the use of factoryBean

The difference between beanFactory and factoryBean

When talking about factoryBean, it is usually compared with beanFactory. The two names are relatively similar, but there is no correlation between the two.
BeanFactory is an interface for operating the bean container and provides methods such as getBean() and isSingleton(). The DefaultListableBeanFactory we often say is the implementation class of the interface. The
factoryBean is an extension mechanism provided by spring. What I understand is: if we implement the factoryBean interface ourselves, we can initialize a bean by ourselves, and spring will complete the instantiation of the bean. , But the initialization process is controlled by ourselves

Spring source code processing factoryBean

We take the mapperFactoryBean used when mybatis and spring are integrated as an example to illustrate how factoryBean is used

In our previous blog, it was said that when mybatis is integrated with spring, when it scans the mapper interface and converts it to beanDefinition, it will set its beanClass to mapperFactoryBean and set the automatic injection model to 2. Among them, beanClass Setting to mapperFactoryBean has something to do with the factoryBean mentioned here, let’s look at the setting code

org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions

definition.setBeanClass(this.mapperFactoryBean.getClass());

Now that the beanClass is set to mapperFactoryBean, there is always some place to use it, where is it used?

When calling the dogetBean() method to try to get the bean from the single-instance pool, the factoryBean will be processed

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	/**
	 * 通过name获取beanName,这里不使用name直接作为beanName有两个原因:
	 *  1.name可能是以&开头的,表明调用者想获取FactoryBean本身,而非FactoryBean;在beanFactory中factoryBean的存储也是map格式
	 *    <beanName,bean> 只是说,普通的beanName是没有&这个字符串的,所以,需要将name的首字母移除,这样才能从缓存中拿到factoryBean
	 *  2.还是别名的问题,需要转换
	 */
	final String beanName = transformedBeanName(name);
	Object bean;

	/**
	 * 1.从单例池中获取当前bean
	 * 2.这里是循环依赖的重要方法之一
	 * 如果取到的sharedInstance不为null,就表示从单实例池中或者二级缓存中,获取到了bean,就无须进行实例化
	 */
	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		if (logger.isDebugEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		/**
		 * 如果获取到的bean是factoryBean类型的(比如:mybatis的mapper接口就是MapperFactoryBean类型的),就会在下面这行代码中,调用
		 * factoryBean的getObject()方法,完成代理对象的生成或者一些业务逻辑的处理
		 */
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
}

It can be seen here that after the bean is obtained from the single instance pool, the getObjectForBeanInstance() method is called. In this method, the processing of the factorybean is
frankly speaking, the processing logic here is not fully understood, so it is no longer Going deeper into the inner layer, I will study this thoroughly later, and add, we can now simply think that in this method, the getObject() method of factoryBean will be called, because the factoryBean set by the beanDefinition initialized by the mapper interface is MapperFactoryBean, so the mapperFactoryBean.getObject() method will be called here

Thinking

We know that spring provides the factoryBean interface and the processing of factoryBean. As for how we write our own business logic in the implementation class, spring does not care. Spring only needs us to guarantee that it is calling factoryBean's getObject() In the method, it will return an object. This object is the object that spring needs to continue to instantiate and assign properties.

I personally feel that the main function of factoryBean is that when a third-party framework is integrated with spring, this extension point can be used to hand over the class of the third-party framework to spring for management, because we want to, if mybatis is integrated with spring , How to put one interface into the spring container? It can not be said that in the source code of mybatis, it directly depends on the spring jar package, and then injects the mapper into the spring container through the @Component annotation. In this case, it is strongly coupled with spring, so mybatis uses the factoryBean extension Point, mybatis itself declares a factoryBean implementation class, and then in the getObject() method of the implementation class, it will return a proxy object corresponding to the mapper interface, and then spring will inject this proxy object into the service layer. In this case , When we call the method in the mapper interface, we actually call the invoke method of the proxy object, and then after the invoke method intercepts the method, the delete, update, select and other methods of sqlSession will be called

The above are some of my own insights on factoryBean. I have other ideas. I can add them later. This knowledge point is actually quite simple. I just feel that I can write a separate note and record it so that I can record the expansion at any time later.

Guess you like

Origin blog.csdn.net/CPLASF_/article/details/115267683