• BeanFactory和FactoryBean的区别:


    用了这么久的SpringMVC框架,有一天看到一个问题,BeanFactory和FactoryBean有什么区别?

    我当时的第一想法是BeanFactory不就是生产bean的工厂吗,FactoryBean不就是工厂里面生产出来的Bean吗?

    后来发现,我的答案不是很对。去查了Spring的源码,看到了FactoryBean的接口,如下

    public interface FactoryBean<T> {
    
    	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
    	@Nullable
    	T getObject() throws Exception;
    	@Nullable
    	Class<?> getObjectType();
    	default boolean isSingleton() {
    		return true;
    	}
    }
    

    从开始的注释第一句就是,FactoryBean是BeanFactory里面使用到的接口。真的是在BeanFactory使用到的bean。同时实现了这个接口的bean不能向常规的bean一样使用他,如何注入一个FactoryBean后面的例子会提到。

    但是FactoryBean实际上还是一个工厂,他有一个泛型T,表示这个工厂创建的实例类型,getObject() 则是返回T,就是创建bean的方法。getObjectType返回的是创建bean的Class对象。而isSingleton则是表示一个FactoryBean创建出来的Bean是不是单例,

    这个应该不难理解。

    那么如何在实际开发里面使用呢?

    这里有两个对象,一个是要创建出来的泛型T,一个是实现FactoryBean接口的类。

    类:ToolFactoryBean

    public class ToolFactoryBean implements FactoryBean<Tool> {
    	private int factoryId;
    	private int toolId;
    
    	public void setFactoryId(int factoryId) {
    		this.factoryId = factoryId;
    	}
    
    	public int getToolId() {
    		return toolId;
    	}
    
    	public void setToolId(int toolId) {
    		this.toolId = toolId;
    	}
    
    	@Override
    	public Tool getObject() throws Exception {
    		return new Tool(toolId);
    	}
    
    	@Override
    	public Class<?> getObjectType() {
    		return Tool.class;
    	}
    
    	public int getFactoryId() {
    		return factoryId;
    	}
    }
    

    需要注意的是如果你用的是xml配置方式,那么你需要有setter来设置属性。

    被创建出来的实例:

    public class Tool {
    	private int id;
    	public Tool(int i) {
    		this.id = i;
    	}
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    }
    

    这里只是实现功能不需要定义复杂的属性。只需要定义一个id即可。

    配置类:

    @Configuration
    public class FactoryBeanAppConfig {
    	@Bean(name = "toolFactory")
    	public ToolFactoryBean getTooFactoryBean() {
    		ToolFactoryBean toolFactoryBean = new ToolFactoryBean();
    		toolFactoryBean.setFactoryId(1111);
    		toolFactoryBean.setToolId(2333);
    		return toolFactoryBean;
    	}
    
    //	@Bean
    //	public Tool getTool() throws Exception {
    //		return getTooFactoryBean().getObject();
    //	}
    }
    

    xml配置方式多少有点落伍了,这里直接使用配置类的方式。需要说明的是如果配置了ToolFactoryBean就无需再配置出他创建出来的那个bean了,因为spring会糊涂。

    使用方式:

    package com.example.springmvcdemo.bean;
    
    import javax.annotation.Resource;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import static org.hamcrest.MatcherAssert.assertThat;
    import static org.hamcrest.Matchers.equalTo;
    import static org.junit.jupiter.api.Assertions.*;
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = FactoryBeanAppConfig.class)
    public class ToolFactoryBeanTest1 {
    	@Autowired
    	private Tool tool;
    
    	@Resource(name = "&toolFactory")
    	private ToolFactoryBean toolFactoryBean;
    
    	@Test
    	public void test() {
    		assertThat(tool.getId(), equalTo(2333));
    		assertThat(toolFactoryBean.getFactoryId(), equalTo(1111));
    	}
    
    }
    

    由于FactoryBean无法通过正常的AutoWired获取到,所以使用& + beanName的方式获取,同样的,你会发现没有配置的Toolbean居然可以直接Autowired

    以上就是FactoryBean的简单的使用,可以看出,FactoryBean可以给我们留有一些预设Bean属性的余地。

    FactoryBean是如何在BeanFactory里面生效的?

    1. FactoryBean的创建时机

    因为是测试所以前面有分析依赖,然后走到了注入创建bean的逻辑。

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    		Assert.notNull(beanName, "Bean name must not be null");
    		synchronized (this.singletonObjects) {
    			Object singletonObject = this.singletonObjects.get(beanName);
    			if (singletonObject == null) {
    				if (this.singletonsCurrentlyInDestruction) {
    					throw new BeanCreationNotAllowedException(beanName,
    							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
    							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
    				}
    				if (logger.isDebugEnabled()) {
    					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
    				}
    				beforeSingletonCreation(beanName);
    				boolean newSingleton = false;
    				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
    				if (recordSuppressedExceptions) {
    					this.suppressedExceptions = new LinkedHashSet<>();
    				}
    				try {
    					singletonObject = singletonFactory.getObject(); 
    					newSingleton = true;
    				}
    				catch (IllegalStateException ex) {
    					// Has the singleton object implicitly appeared in the meantime ->
    					// if yes, proceed with it since the exception indicates that state.
    					singletonObject = this.singletonObjects.get(beanName);
    					if (singletonObject == null) {
    						throw ex;
    					}
    				}
    				catch (BeanCreationException ex) {
    					if (recordSuppressedExceptions) {
    						for (Exception suppressedException : this.suppressedExceptions) {
    							ex.addRelatedCause(suppressedException);
    						}
    					}
    					throw ex;
    				}
    				finally {
    					if (recordSuppressedExceptions) {
    						this.suppressedExceptions = null;
    					}
    					afterSingletonCreation(beanName);
    				}
    				if (newSingleton) {
    					addSingleton(beanName, singletonObject);
    				}
    			}
    			return singletonObject;
    		}
    	}
    

    核心的代码是:

    singletonObject = singletonFactory.getObject(); 
    

    用来创建一个FactoryBean

    	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    			throws BeanCreationException {
    
    		// Instantiate the bean.
    		BeanWrapper instanceWrapper = null;
    		if (mbd.isSingleton()) {
    			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    		}
    		if (instanceWrapper == null) {
    			instanceWrapper = createBeanInstance(beanName, mbd, args);
    		}
    		Object bean = instanceWrapper.getWrappedInstance();// 创建bean
    		Class<?> beanType = instanceWrapper.getWrappedClass();
    		//省略一些代码
    
    		return exposedObject;
    	}
    ```java
    
    FactoryBean里面创建的Bean将在`getObjectForBeanInstance`方法中创建:
    
    ```java
    protected Object getObjectForBeanInstance(
    			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    
    		// Don't let calling code try to dereference the factory if the bean isn't a factory.
    		if (BeanFactoryUtils.isFactoryDereference(name)) {
    			if (beanInstance instanceof NullBean) {
    				return beanInstance;
    			}
    			if (!(beanInstance instanceof FactoryBean)) {
    				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
    			}
    			if (mbd != null) {
    				mbd.isFactoryBean = true;
    			}
    			return beanInstance;
    		}
    
    		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
    		// If it's a FactoryBean, we use it to create a bean instance, unless the
    		// caller actually wants a reference to the factory.
    		if (!(beanInstance instanceof FactoryBean)) {
    			return beanInstance;
    		}
    
    		Object object = null;
    		if (mbd != null) {
    			mbd.isFactoryBean = true;
    		}
    		else {
    			object = getCachedObjectForFactoryBean(beanName);
    		}
    		if (object == null) {
    			// Return bean instance from factory.
    			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
    			// Caches object obtained from FactoryBean if it is a singleton.
    			if (mbd == null && containsBeanDefinition(beanName)) {
    				mbd = getMergedLocalBeanDefinition(beanName);
    			}
    			boolean synthetic = (mbd != null && mbd.isSynthetic());
    			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    		}
    		return object;
    	}
    

    其实最终调用的都是FactoryBean的getObject方法来创建Bean

    那么BeanFactory又是什么呢?

    源代码长了,截取部分注释和方法分析

    开篇第一句:

    The root interface for accessing a Spring bean container. //所有Spring容器的父接口
    

    他的增强的接口有ListableBeanFactory, ConfigurableBeanFactory,他提供了一系列的获取Bean的方法:

    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;
    

    获取Bean信息的一些方法

    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;
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
    String[] getAliases(String name);
    

    另外提供了ObjectProvider的获取方法:

    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
    
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
    

    ObjectProvider是用来做延迟加载的,可以消除@Autowired

    例子:

    public class FooService {
        private final FooRepository repository;
        public FooService(ObjectProvider<FooRepository> repositoryProvider) {
            this.repository = repositoryProvider.getIfUnique();
        }
    }
    

    另外在BeanFactory中还有,如何获取FactoryBean的方法:

    	/**
    	 * Used to dereference a {@link FactoryBean} instance and distinguish it from
    	 * beans <i>created</i> by the FactoryBean. For example, if the bean named
    	 * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
    	 * will return the factory, not the instance returned by the factory.
    	 */
    	String FACTORY_BEAN_PREFIX = "&";
    

    总的来说FactoryBean是容器,他里面包含了获取Bean和Bean信息的各种方法,而FactoryBean是在BeanFactory里面使用的一种特殊的Bean,他主要的职能是用来创建Bean。

    参考:

    1. https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/ObjectProvider.html
    2. https://www.baeldung.com/spring-factorybean
    3. https://blog.csdn.net/alex_xfboy/article/details/83342164?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-2&spm=1001.2101.3001.4242
  • 相关阅读:
    python 爬取豆瓣电影短评并wordcloud生成词云图
    基于javaweb人脸识别注册登录系统
    html/jsp导出pdf格式的几种方法(jsPDF,iText,wkhtmltopdf)
    微信小程序wx.getLocation()获取经纬度及JavaScript SDK调用腾讯地图API获取某一类地址
    微信小程序登录流程及解析用户openid session_key,获取用户信息
    Windows Server 2012 R2服务器部署Tomcat JDK、安装Mysql以及将Java项目部署到CVM
    Tomcat出现端口占用错误
    linux cmake error undefined reference to symbol 'pthread_create@@GLIBC_2.2.5
    CMake Warning This command specifies the relative path as a link directory.
    linux vim查看文件编码格式
  • 原文地址:https://www.cnblogs.com/lijunyzzZ/p/14186681.html
Copyright © 2020-2023  润新知