在前面的文章中,咱们知道能够经过多种方式向Spring容器中注册bean。能够使用@Configuration结合@Bean向Spring容器中注册bean;能够按照条件向Spring容器中注册bean;能够使用@Import向容器中快速导入bean对象;能够在@Import中使用ImportBeanDefinitionRegistrar向容器中注册bean。java
项目工程源码已经提交到GitHub:https://github.com/sunshinelyz/spring-annotationgit
通常状况下,Spring经过反射机制利用bean的class属性指定实现类来实例化bean 。在某些状况下,实例化bean过程比较复杂,若是按照传统的方式,则须要在
FactoryBean接口对于Spring框架来讲占有重要的地位,Spring 自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring 3.0 开始, FactoryBean开始支持泛型,即接口声明改成FactoryBean
在Spring 5.2.6版本中,FactoryBean接口的定义以下所示。缓存
package org.springframework.beans.factory; import org.springframework.lang.Nullable; public interface FactoryBean<T> { String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; @Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
这里,须要注意的是:当配置文件中
首先,建立一个PersonFactoryBean,实现FactoryBean接口,以下所示。微信
package io.mykit.spring.plugins.register.bean; import org.springframework.beans.factory.FactoryBean; /** * @author binghe * @version 1.0.0 * @description 商品的FactoryBean,测试FactoryBean */ public class PersonFactoryBean implements FactoryBean<Person> { //返回一个Person对象,这个对象会被注册到Spring容器中 @Override public Person getObject() throws Exception { return new Person(); } @Override public Class<?> getObjectType() { return Person.class; } //bean是否为单例;true:是;false:否 @Override public boolean isSingleton() { return true; } }
接下来,咱们在PersonConfig2类中加入PersonFactoryBean的声明,以下所示。框架
@Bean public PersonFactoryBean personFactoryBean(){ return new PersonFactoryBean(); }
这里须要小伙伴们注意的是:我在这里使用@Bean注解向Spring容器中添加的是PersonFactory对象。那咱们就来看看Spring容器中有哪些bean。接下来,运行SpringBeanTest类中的testAnnotationConfig7()方法,输出的结果信息以下所示。ide
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 personFactoryBean company
能够看到,结果信息中输出了一个personFactoryBean,咱们看下这个personFactoryBean究竟是个什么鬼!此时,咱们对SpringBeanTest类中的testAnnotationConfig7()方法稍加改动,添加获取personFactoryBean的代码,并输出personFactoryBean实例的类型,以下所示。学习
@Test public void testAnnotationConfig7(){ ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class); String[] names = context.getBeanDefinitionNames(); Arrays.stream(names).forEach(System.out::println); Object personFactoryBean = context.getBean("personFactoryBean"); System.out.println("personFactoryBean实例的类型为:" + personFactoryBean.getClass()); }
再次运行SpringBeanTest类中的testAnnotationConfig7()方法,输出的结果信息以下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 personFactoryBean company personFactoryBean实例的类型为:class io.mykit.spring.plugins.register.bean.Person
能够看到,虽然我在代码中使用@Bean注解注入的PersonFactoryBean对象,可是,实际上从Spring容器中获取到的bean对象倒是调用PersonFactoryBean类中的getObject()获取到的Person对象。
看到这里,是否是有种豁然开朗的感受!!!
在PersonFactoryBean类中,咱们将Person对象设置为单实例bean,接下来,咱们在SpringBeanTest类中的testAnnotationConfig7()方法屡次获取Person对象,并输出屡次获取的对象是否为同一对象,以下所示。
@Test public void testAnnotationConfig7(){ ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class); String[] names = context.getBeanDefinitionNames(); Arrays.stream(names).forEach(System.out::println); Object personFactoryBean1 = context.getBean("personFactoryBean"); Object personFactoryBean2 = context.getBean("personFactoryBean"); System.out.println(personFactoryBean1 == personFactoryBean2); }
运行testAnnotationConfig7()方法输出的结果信息以下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 personFactoryBean company true
能够看到,在PersonFactoryBean类的isSingleton()方法中返回true时,每次获取到的Person对象都是同一个对象,说明Person对象是单实例bean。
这里,可能就会有小伙伴要问了,若是将Person对象修改为多实例bean呢?别急,这里咱们只须要在PersonFactoryBean类的isSingleton()方法中返回false,便可将Person对象设置为多实例bean,以下所示。
//bean是否为单例;true:是;false:否 @Override public boolean isSingleton() { return false; }
再次运行SpringBeanTest类中的testAnnotationConfig7()方法,输出的结果信息以下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 personFactoryBean company false
能够看到,最终结果返回了false,说明此时Person对象是多实例bean。
以前,咱们使用@Bean注解向Spring容器中注册的PersonFactoryBean,获取出来的确实Person对象。那么,小伙伴们可能会问:我就想获取PersonFactoryBean实例,该怎么办呢?
其实,这也很简单, 只须要在获取bean对象时,在id前面加上&符号便可。
打开咱们的测试类SpringBeanTest,在testAnnotationConfig7()方法中添加获取PersonFactoryBean实例的代码,以下所示。
@Test public void testAnnotationConfig7(){ ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class); String[] names = context.getBeanDefinitionNames(); Arrays.stream(names).forEach(System.out::println); Object personFactoryBean1 = context.getBean("personFactoryBean"); Object personFactoryBean2 = context.getBean("personFactoryBean"); System.out.println("personFactoryBean1类型:" + personFactoryBean1.getClass()); System.out.println("personFactoryBean2类型:" + personFactoryBean2.getClass()); System.out.println(personFactoryBean1 == personFactoryBean2); Object personFactoryBean3 = context.getBean("&personFactoryBean"); System.out.println("personFactoryBean3类型:" + personFactoryBean3.getClass()); }
运行SpringBeanTest类中的testAnnotationConfig7()方法,输出的结果信息以下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 personFactoryBean company personFactoryBean1类型:class io.mykit.spring.plugins.register.bean.Person personFactoryBean2类型:class io.mykit.spring.plugins.register.bean.Person false personFactoryBean3类型:class io.mykit.spring.plugins.register.bean.PersonFactoryBean
能够看到,在获取bean时,在id前面加上&符号就会获取到PersonFactoryBean实例对象。
那问题又来了!!为何在id前面加上&符号就会获取到PersonFactoryBean实例对象呢?
接下来,咱们就揭开这个神秘的面纱,打开BeanFactory接口,
package org.springframework.beans.factory; import org.springframework.beans.BeansException; import org.springframework.core.ResolvableType; import org.springframework.lang.Nullable; public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; /**************如下省略n行代码***************/ }
看到这里,是否是明白了呢?没错,在BeanFactory接口中定义了一个&前缀,只要咱们使用bean的id来从Spring容器中获取bean时,Spring就会知道咱们是在获取FactoryBean自己。
好了,我们今天就聊到这儿吧!别忘了给个在看和转发,让更多的人看到,一块儿学习一块儿进步!!
项目工程源码已经提交到GitHub:https://github.com/sunshinelyz/spring-annotation
若是以为文章对你有点帮助,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习Spring注解驱动开发。公众号回复“spring注解”关键字,领取Spring注解驱动开发核心知识图,让Spring注解驱动开发再也不迷茫。