beanFactory 、ApplicationContext、FactoryBean、

BeanFactory
  BeanFactory 是 Spring 的“心脏”。就是 Spring IoC 容器的真面目。Spring 使用 BeanFactory 来实例化、配置和管理 Bean。

  BeanFactory:是IOC容器的核心接口, 定义IOC的基本功能,主要定义getBean方法。getBean方法是IOC容器获取bean对象和引发依赖注入的起点。方法的功能是返回特定的名称的Bean

  BeanFactory 是初始化 Bean 和调用它们生命周期方法的“吃苦耐劳者”。注意,BeanFactory 只能管理单例(Singleton)Bean 的生命周期。不能管理原型(prototype,非单例)Bean 的生命周期。因为原型 Bean 实例被创建之后便被传给客户端,容器失去了对它们的引用。

  

  BeanFactory作为最顶层的一个接口类,定义IOC容器的基本功能规范,BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。最终的默认实现类是 DefaultListableBeanFactory,实现了所有的接口。那为何要定义这么多层次的接口呢?主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如:

  • ListableBeanFactory 接口:表示 Bean 是可列表的。
  • HierarchicalBeanFactory 接口:表示的是这Bean 是有继承关系的,也就是每个Bean 有可能有父 Bean。
  • AutowireCapableBeanFactory 接口:定义 Bean 的自动装配规则。

看一下BeanFactory的源码:

package org.springframework.beans.factory;

public interface BeanFactory {

    /**
     * 用来引用一个实例,或把它和工厂产生的Bean区分开,如果一个FactoryBean的名字为a,那么,&a会得到那个Factory
     */
    String FACTORY_BEAN_PREFIX = "&";

    /*
     * 四个不同形式的getBean方法,获取实例
     */
    Object getBean(String name) throws BeansException;
//返回给定名称注册的bean实例。根据bean的配置情况,如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常
//
<T> T getBean(String name, Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> 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;
// 返回给定名称的bean的Class,如果没有找到指定的bean实例,则排除NoSuchBeanDefinitionException异常 String[] getAliases(String name);// 根据实例的名字获取实例的别名 }

    BeanFactory最常见的实现类为XmlBeanFactory,可以从classpath或文件系统等获取资源。

File file = new File("fileSystemConfig.xml");
Resource resource = new FileSystemResource(file);
BeanFactory beanFactory = new XmlBeanFactory(resource);


Resource resource = new ClassPathResource("classpath.xml"); 
BeanFactory beanFactory = new XmlBeanFactory(resource);

ApplicationContext

  BeanFactory是Spring的心脏,ApplicationContext就是完整的躯体,ApplicationContext由BeanFactory派生而来,提供更多面向实际应用的功能。在BeanFactory中,需要以编程的方式实现,而在ApplicationContext中则可以通过配置实现。

  BeanFactorty接口提供配置框架及基本功能,但是无法支持spring的aop功能和web应用。而ApplicationContext接口作为BeanFactory的派生,提供BeanFactory所有的功能。而且ApplicationContext还在功能上做扩展,相较于BeanFactorty,ApplicationContext还提供以下的功能: 

  (1)MessageSource, 提供国际化的消息访问  
  (2)资源访问,如URL和文件 :Resource rs = ctx. getResource(“classpath:config.properties”)
  (3)事件传播特性,即支持aop特性
  (4)载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层 

  ApplicationContext:是IOC容器另一个重要接口, 继承BeanFactory的基本功能, 也继承容器的高级功能,如:MessageSource(国际化资源接口)、ResourceLoader(资源加载接口)、ApplicationEventPublisher(应用事件发布接口)等。

       Spring为ApplicationContext提供3种实现,分别是ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、XmlWebApplicationContext,其中XmlWebApplicationContext是专为Web工程定制的。

  

  二者区别

  1.BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样就不能发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。在容器启动时,可以发现Spring中存在的配置错误。 

  BeanFacotry延迟加载,如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常;而ApplicationContext则在初始化自身是检验,有利于检查所依赖属性是否注入;
  应用上下文则会在上下文启动后预载入所有的单实例Bean。通过预载入单实例bean ,确保当需要的时候,就不用等待,因为它们已经创建好了。

  2.BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册而ApplicationContext则是自动注册。(Applicationcontext比 beanFactory 加入一些更好使用的功能。

 

BeanFactory和FactoryBean的区别

      BeanFactory是接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供规范,在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的

      BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,

      Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。  

 

    Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。

     FactoryBean以Bean结尾,表示是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身如果要获取FactoryBean对象,请在id前面加一个&符号来获取

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

/**
 * my factory bean<p>
 * 代理一个类,拦截该类的所有方法,在方法的调用前后进行日志的输出
 * @author daniel.zhao
 *
 */
public class MyFactoryBean implements FactoryBean<Object>, 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配置如下

<bean id="fbHelloWorldService" class="com.ebao.xxx.MyFactoryBean">
     <property name="interfaceName" value="com.ebao.xxx.HelloWorldService" />
<property name="target" ref="helloWorldService" /> </bean>

Junit Test class

@RunWith(JUnit4ClassRunner.class)
@ContextConfiguration(classes = { MyFactoryBeanConfig.class })
public class MyFactoryBeanTest {

    @Autowired
    private ApplicationContext context;
    
    /**
     * 测试验证FactoryBean原理,代理一个servcie在调用其方法的前后,打印日志亦可作其他处理
     * 从ApplicationContext中获取自定义的FactoryBean
     * context.getBean(String beanName) ---> 最终获取到的Object是FactoryBean.getObejct(), 
     * 使用Proxy.newInstance生成service的代理类
     */
    @Test
    public void testFactoryBean() {
        HelloWorldService helloWorldService = (HelloWorldService) context.getBean("fbHelloWorldService");
        helloWorldService.getBeanName();
        helloWorldService.sayHello();
    }
}

 

参考:

https://www.cnblogs.com/aspirant/p/9082858.html

https://www.cnblogs.com/xiaoxi/p/5850095.html

 

posted on 2018-10-29 16:19  溪水静幽  阅读(314)  评论(0)    收藏  举报