BeanFactory和FactoryBean 2个很相似,但是区别很大。
1、BeanFactory
BeanFactory接口是Spring容器的核心接口,负责:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
ApplicationContext 这个应用上下文,我们经常用到,如
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
而它就是继承了BeanFactory ,才会有可以getBean(String name) 这个功能。
源代码如下:
1 public interface BeanFactory { 2 String FACTORY_BEAN_PREFIX = "&"; 3 4 Object getBean(String var1) throws BeansException; 5 6 <T> T getBean(String var1, Class<T> var2) throws BeansException; 7 8 <T> T getBean(Class<T> var1) throws BeansException; 9 10 Object getBean(String var1, Object... var2) throws BeansException; 11 12 <T> T getBean(Class<T> var1, Object... var2) throws BeansException; 13 14 boolean containsBean(String var1); 15 16 boolean isSingleton(String var1) throws NoSuchBeanDefinitionException; 17 18 boolean isPrototype(String var1) throws NoSuchBeanDefinitionException; 19 20 boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException; 21 22 boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException; 23 24 Class<?> getType(String var1) throws NoSuchBeanDefinitionException; 25 26 String[] getAliases(String var1); 27 }
2、FactoryBean
一般情况下,Spring通过反射机制利用<bean>的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,
如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。
Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。
说白了就是个普通的Bean,而这个bean可以自定义实现实例化,不想写xml配置,以及里面注入的内容很负责,写配置很困难等情况,跟注解版的@Bean 很相似,用的装饰设计模式,可新增功能。
源代码如下:
1 public interface FactoryBean<T> { 2 T getObject() throws Exception; 3 4 Class<?> getObjectType(); 5 6 boolean isSingleton(); 7 }
很明显调用getObect方法就相当于applicationContext.getBean("student")
具体使用如下:
自定义创建了Mybean.class,实现FactoryBean接口
1 public class MyBean implements FactoryBean<Student> 2 { 3 @Override 4 public Student getObject() throws Exception 5 { 6 return new Student(){{ 7 setName("张三"); 8 }}; 9 } 10 11 @Override 12 public Class<?> getObjectType() 13 { 14 return Student.class; 15 } 16 17 @Override 18 public boolean isSingleton() 19 { 20 return true; 21 } 22 }
<bean id="myBean" class="qt.Dto.MyBean"></bean>
1 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); 2 Object myBean = applicationContext.getBean("myBean"); 3 System.out.println("isStudentBean:" + isStudentBean);
4 System.out.println("myBean name:" + ((Student) myBean).getName());
输出:
isStudentBean:true
myBean name:张三
从上面的执行来看,明明注册className的是qt.Dto.MyBean, 最后获取的竟然是Student对象,不是本身的MyBean对象,
很明显它调用的就是getObject方法,核心就是个代理方式
如果我就想获取MyBean对象呢,还是有办法的,在对象 id前加 &就可以
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Object myBean1 = applicationContext.getBean("&myBean"); boolean isMyBean = myBean instanceof MyBean; System.out.println("isMyBean:" + isMyBean); System.out.println("myBean name:" + myBean1);
输出:
isStudentBean:true
myBean name:张三
用&来识别