FactoryBean和BeanFactory

BeanFactory 和 FactoryBean的区别?

  • BeanFactory是个bean工厂,也就是IOC容器或对象工厂,在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的,提供了实例化对象和获取对象的功能。是IOC最基本的容器,负责生产和管理bean,它为其他具体的IOC容器实现提供了最基本的规范,例如DefaultListableBeanFactory, XmlBeanFactory, ApplicationContext 等具体的容器都是实现了BeanFactory,再在其基础之上附加了其他的功能。           

public interface BeanFactory {    
    String FACTORY_BEAN_PREFIX = "&";    
    Object getBean(String name) throws BeansException;    
    <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;    
    String[] getAliases(String name);    
} 
BeanFactory

          使用场景:

    • 从Ioc容器中获取Bean(byName or byType)

    • 检索Ioc容器中是否包含指定的Bean

    • 判断Bean是否为单例

  • FactoryBean是个Bean,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。

    使用场景

    • ProxyFactoryBean

BeanFactory和FactoryBean区别

他们两个都是 创建bean对象的

BeanFactory:提供了类似模板的方法,根据模板方法实现具体的bean创建

BeanFactory

 

FactoryBean:则是提供了定制化的 ,独特的,与众不同的Bean创建,你可以根据自己的方式创建bean,最后通过FactoryBean中的getObject获取你定制化实现的bean

FactoryBean里面有三个方法:目的是为了做扩展,Spring Cloud 用到了FactoryBean如(FeignClientFactoryBean),feign实现了FactoryBean,getObject可以获取

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

MapperFactoryBean通过实现FactoryBean中的getObject()方法生成Mapper对应的代理对象

SqlSessionFactoryBean:创建DefaultSqlSession

FactoryBean接口

 

 

   public Object getObject() {
        return this.getTarget();
    }
<T> T getTarget() {
        FeignContext context = (FeignContext)this.applicationContext.getBean(FeignContext.class);
        Builder builder = this.feign(context);
        if (!StringUtils.hasText(this.url)) {
            if (!this.name.startsWith("http")) {
                this.url = "http://" + this.name;
            } else {
                this.url = this.name;
            }

            this.url = this.url + this.cleanPath();
            return this.loadBalance(builder, context, new HardCodedTarget(this.type, this.name, this.url));
        } else {
            if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
                this.url = "http://" + this.url;
            }

            String url = this.url + this.cleanPath();
            Client client = (Client)this.getOptional(context, Client.class);
            if (client != null) {
                if (client instanceof FeignBlockingLoadBalancerClient) {
                    client = ((FeignBlockingLoadBalancerClient)client).getDelegate();
                }

                builder.client(client);
            }

            Targeter targeter = (Targeter)this.get(context, Targeter.class);
            return targeter.target(this, builder, context, new HardCodedTarget(this.type, this.name, url));
        }
    }
FeignClientFactoryBean

 

  public T getObject() throws Exception {
        return this.getSqlSession().getMapper(this.mapperInterface);
    }

//通过代理创建对象
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MybatisMapperProxyFactory<T> mapperProxyFactory = (MybatisMapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MybatisPlusMapperRegistry.");
        } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }
MapperFactoryBean

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BeanFactory和ApplicationContext的异同

  

 

BeanFactory:

BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化;

 

ApplicationContext:

ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化;  

应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;

1) 国际化(MessageSource)

2) 访问资源,如URL和文件(ResourceLoader)

3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层  

4) 消息发送、响应机制(ApplicationEventPublisher)

5) AOP(拦截器)

 

ApplicationContext:继承了bean工厂,环境,事件发布功能资源解析,获取资源等功能,功能比beanFactory更全

主要实现类: 

  1. AnnotationConfigApplicationContext
  2. ClassPathXmlApplicationContext
  3. FileSystemXmlApplicationContext 

相同:

  • Spring提供了两种不同的IOC 容器,一个是BeanFactory,另外一个是ApplicationContext,它们都是Java interface,ApplicationContext继承于BeanFactory(ApplicationContext继承ListableBeanFactory)。

  • 它们都可以用来配置XML属性,也支持属性的自动注入。

  • 而ListableBeanFactory继承BeanFactory),BeanFactory 和 ApplicationContext 都提供了一种方式,使用getBean("bean name")获取bean。

不同:

  • 当你调用getBean()方法时,BeanFactory仅实例化bean,而ApplicationContext 在启动容器的时候实例化单例bean,不会等待调用getBean()方法时再实例化。

  • BeanFactory不支持国际化,即i18n,但ApplicationContext提供了对它的支持。

  • BeanFactory与ApplicationContext之间的另一个区别是能够将事件发布到注册为监听器的bean。

  • BeanFactory 的一个核心实现是XMLBeanFactory 而ApplicationContext 的一个核心实现是ClassPathXmlApplicationContext,Web容器的环境我们使用WebApplicationContext并且增加了getServletContext 方法。

  • 如果使用自动注入并使用BeanFactory,则需要使用API注册AutoWiredBeanPostProcessor,如果使用ApplicationContext,则可以使用XML进行配置。

简而言之,BeanFactory提供基本的IOC和DI功能,而ApplicationContext提供高级功能,BeanFactory可用于测试和非生产使用,但ApplicationContext是功能更丰富的容器实现,应该优于BeanFactory

 

posted @ 2021-02-18 15:38  暖暖-木木  阅读(443)  评论(0编辑  收藏  举报