BeanFactory 和 FactoryBean

BeanFactory

BeanFactory 是 IOC 最基本的容器,负责生产和管理 bean,它为其他具体的 IOC 容器实现提供了最基本的规范,例如 DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext 等具体的容器都是实现了 BeanFactory,再在其基础之上附加了其他的功能

public interface BeanFactory {    
    String FACTORY_BEAN_PREFIX = "&";    
    Object getBean(String name) throws BeansException;    
     T getBean(String name, Class requiredType) throws BeansException;    
     T getBean(Class requiredType) throws BeansException;    
    Object getBean(String name, Object... args) throws BeansException;    
    boolean containsBean(String name);    
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;    
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;    
    boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;    
    Class getType(String name) throws NoSuchBeanDefinitionException;    
    String[] getAliases(String name);    
} 

FactoryBean

FactoryBean 是一个接口,当在 IOC 容器中的 Bean 实现了 FactoryBean 接口后,通过 getBean(String BeanName) 获取到的 Bean 对象并不是 FactoryBean 的实现类对象,而是这个实现类中的 getObject() 方法返回的对象。要想获取 FactoryBean 的实现类,就要 getBean(&BeanName),在 BeanName 之前加上 &

public interface FactoryBean {    
    T getObject() throws Exception;    
    Class getObjectType();    
    boolean isSingleton();    
}  

FactoryBean 的好处

假如有个 Person 对象,里面包含 name,address,age

public class Person {  
    private String name;        // setter、getter
    private String address;  
    private int age;  
}  

那么如果要在 Spring 中配置该对象的话,需要这么配置:

  
      
      
      
  

这样就可以通过 getBean("personBean") 来获取该对象了:

BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/spring-context.xml");
Person p = beanFactory.getBean("personBean");

如果通过实现 FactoryBean:

public class PersonFactoryBean implements FactoryBean{  
    private String personInfo;  
    public Person getObject() throws Exception {  
        Person person = new Person() ;      
        String[] infos = personInfo.split(",") ;  
        person.setName(infos[0]);  
        person.setAddress(infos[1]);  
        person.setAge(Integer.parseInt(infos[2]));  
        return person;  
    }  

    public Class getObjectType() {  
        return Person.class;  
    }  

    public boolean isSingleton() {  
        return true;  
    }  
}  

这里 PersonFactoryBean 实现了 FactoryBean 接口,那么自然也要实现它定义的方法。这里是通过一个 personInfo 字符串解析得到 Person 对象,那么在配置 Spring 的时候就可以这么配置:

  
    
   

or


BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/spring-context.xml");
// 获取 bean:
Person p = beanFactory.getBean("personFactory");
// 获取 FactoryBean 的实现类
FactoryBean fb = beanFactory.getBean("&personFactory");

可见:如果使用传统方式配置 Person 类的 , 类的每个属性分别对应一个 元素标签,配置文件就会变得冗长;其次,使用 FactoryBean 可以自定义实例化逻辑,即在 bean 返回之前,对 bean 对象做一些处理,这里采用了工厂模式和装饰器模式

例如自己实现一个 FactoryBean,功能:用来代理一个对象,对该对象的所有方法做一个拦截,在调用前后都输出一行 LOG,模仿 ProxyFactoryBean 的功能

public class MyFactoryBean implements FactoryBean, InitializingBean, DisposableBean {

    private static final Logger logger = LoggerFactory.getLogger(MyFactoryBean.class);    
    private String interfaceName;    
    private Object target;    
    private Object proxyObj;    
    @Override
    public void destroy() throws Exception {
        logger.debug("destroy......");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        proxyObj = Proxy.newProxyInstance(
                this.getClass().getClassLoader(), 
                new Class[] { Class.forName(interfaceName) }, 
                new InvocationHandler() {                    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                logger.debug("invoke method......" + method.getName());
                logger.debug("invoke method before......" + System.currentTimeMillis());
                Object result = method.invoke(target, args);
                logger.debug("invoke method after......" + System.currentTimeMillis());
                return result;            }            
        });
        logger.debug("afterPropertiesSet......");
    }

    @Override
    public Object getObject() throws Exception {
        logger.debug("getObject......");
        return proxyObj;
    }

    @Override
    public Class getObjectType() {
        return proxyObj == null ? Object.class : proxyObj.getClass();
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public String getInterfaceName() {
        return interfaceName;
    }

    public void setInterfaceName(String interfaceName) {
        this.interfaceName = interfaceName;
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public Object getProxyObj() {
        return proxyObj;
    }

    public void setProxyObj(Object proxyObj) {
        this.proxyObj = proxyObj;
    }

}
 
 

XML-Bean配置如下


    
    

FactoryBean 应用场景

当某些对象的实例话过程过于烦琐,通过 XML 配置过于复杂,不如使用 Java 代码来完成这个实例化过程的时候,或者,某些第三方库不能直接注册到 Spring 容器中的时候,就可以实现 FactoryBean 接口,给出自己的对象实例化代码。当然实现自定义工厂也是可以的。但是 FactoryBean 是 Spring 的标准

区别

BeanFactory 是个 Factory,也就是 IOC 容器或对象工厂,所有的 Bean 都是由 BeanFactory 来进行管理

FactoryBean 是一个能生产或者修饰生成对象的工厂 Bean(本质上也是一个 bean),可以在 BeanFactory(IOC 容器)中被管理,所以它并不是一个简单的 Bean。当使用容器中 factory bean 的时候,该容器不会返回 factory bean 本身,而是返回其生成的对象。要想获取 FactoryBean 的实现类本身,得在 getBean(String BeanName) 中的 BeanName 之前加上 &,写成 getBean(String &BeanName)

你可能感兴趣的:(BeanFactory 和 FactoryBean)