精华内容
下载资源
问答
  • FactoryBean作用

    2020-12-29 14:24:02
    是注入Bean的一种方法。 除此之外还有 xml配置 @Bean [可以增强第三方框架] [new一个类然后返回] @Component[可以增强第三方框架] @Bean和它的区别是不能继承。比如mybatis源码里面的

    是注入Bean的一种方法。

    除此之外还有

    • xml配置
    • @Bean [可以增强第三方框架] [new一个类然后返回]
    • @Component[可以增强第三方框架]

    @Bean和它的区别是不能继承类,实现接口来增强,只能通过代码增强new的对象。。比如mybatis源码里面的

    在这里插入图片描述

    展开全文
  • 一、背景 BeanFactory与FactoryBean名字相似,但是意义确大不相同,可以说基本没有关系。... 本文主要通过FactoryBean作用大家可以明白为什么不同。 FactoryBean相信大家都明白一个类(比如BeanA)如果实现了...

    一、背景

        BeanFactory与FactoryBean名字相似,但是意义确大不相同,可以说基本没有关系。BeanFactory是一个工厂,负责创建bean、获取到bean,而FactoryBean只是一个bean。

    二、两者不同

        本文主要通过FactoryBean的作用大家可以明白为什么不同。

        FactoryBean相信大家都明白一个类(比如BeanA)如果实现了它,那么从容器中getBean(“beanA”)时拿到的是另一个bean,如果想拿到BeanA本身,那么需要getBean(“&beanA”)来操作,如代码所示:

        BeanA:

        

    public class IndexFactoryBean implements FactoryBean<IndexFactory> {
    
        private String name;
        private Integer age;
    
        public IndexFactoryBean(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    
        public IndexFactory getObject() throws Exception {
            IndexFactory indexFactory = new IndexFactory();
            indexFactory.setName(name);
            indexFactory.setAge(age);
            return indexFactory;
        }
    
        public Class<?> getObjectType() {
            return null;
        }
    }

        希望获取的bean:

       

    public class IndexFactory {
        private String name;
        private Integer age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    }

        配置类:

        

    @Configuration
    public class Config {
    
        @Bean
        public IndexFactoryBean indexFactoryBean(){
            return new IndexFactoryBean("test",1);
        }
    }

        测试类:

        

    public class ApplicationMain {
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext annotationContext = new AnnotationConfigApplicationContext(Config.class);
            System.out.println(annotationContext.getBean("&indexFactoryBean"));
            System.out.println(annotationContext.getBean("indexFactoryBean"));
            IndexFactory indexFactory = (IndexFactory) annotationContext.getBean("indexFactoryBean");
            System.out.println(indexFactory.getName());
            System.out.println(indexFactory.getAge());
        }
    }

        结果输出:

        

    com.wolf.test.facade.bean.IndexFactoryBean@1ebea008
    com.wolf.test.facade.bean.IndexFactory@72d6b3ba
    test
    1

        这个效果大家肯定都知道,但是为什么要有这个FactoryBean,我们知道既然要生成IndexFactory这个实例,我们直接用它不就行了吗?直接把属性放置进去不就行了吗?

        设计者这么做肯定有道理。比如我们这个IndexFactory类属性很多很多,而且IndexFactory要提供给外部使用,难道也要别人每次都要set那么多属性吗?本质上可以,但是一般不要这么做,不是很和谐,那么我们就利用IndexFactoryBean暴露给外部使用,这样,外部可能只需要set某些关键属性就可以了。

       例子:我们来看常用的SqlSessionFactoryBean,我们可以看到它也实现了FactoryBean,那这个是为了什么呢?

       源码:

       

      public SqlSessionFactory getObject() throws Exception {
        if (this.sqlSessionFactory == null) {
          afterPropertiesSet();
        }
    
        return this.sqlSessionFactory;
      }

       我们可以看到里面返回的sqlSeesionFactory,那么继续跟进

      public void afterPropertiesSet() throws Exception {
        notNull(dataSource, "Property 'dataSource' is required");
        notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
        state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
                  "Property 'configuration' and 'configLocation' can not specified with together");
    
        this.sqlSessionFactory = buildSqlSessionFactory();
      }

        看到buildSqlSessionFactory可以明白,SqlSessionFactory内部需要很多属性(如果通过xml方式配置bean那么就不会走到这一步),为了方便外部使用,SqlSessionFactoryBean都帮忙处理好了,而我们外部使用的时候只需要setDatasource就可以了,仅仅需要set一个属性,很大程度地方便外部使用。

        看到这里,相信大家明白了吧。

     

    结束语:

        本文主要描述FactoryBean的作用,相信明白了作用就可以明白与BeanFactory的区别了。

        谢谢大家阅读,请大家多多指教文章中的不足,互相学习!!

    展开全文
  • 也是FactoryBean的一个应用场景,如果你知道了这些,再去看spring整合Mybatis源码就会发现整个过程特别清晰,也就理解了FactoryBean作用 总结 所以说FactoryBean本质就是用来给我们实例化、或者动态的注入一些比较...

    背景

    假设我们有这种需求,像Mybaits需要将这些接口注入到Spring容器中

    public interface OneTestDao {
        @Select("SELECT name FROM user WHERE id = 1")
        String query();
    }
    
    public interface TwoTestDao {
        @Select("SELECT name FROM user WHERE id = 2")
        String query();
    }
    

    首先我们想将我们的自己的Bean(比如代理对象)注入到Spring容器中,有什么方式呢?

    一般都是通过Spring扫描Resouce资源然后解析为BeanDefinition,才能从getBean时解析BeanDefinition实例化对象放入此单例缓存中.但是我们这里的是接口,没法直接注入到Spring容器中。

    不过Spring提供了一些扩展接口来供我们在Bean加载、初始化、加载完提供了一些接口,供我们扩展。

    比如

    BeanFactoryPostProcessor

    来看看源码

    @FunctionalInterface
    public interface BeanFactoryPostProcessor {
    
    	/**
    	 * Modify the application context's internal bean factory after its standard
    	 * initialization. All bean definitions will have been loaded, but no beans
    	 * will have been instantiated yet. This allows for overriding or adding
    	 * properties even to eager-initializing beans.
    	 * @param beanFactory the bean factory used by the application context
    	 * @throws org.springframework.beans.BeansException in case of errors
    	 */
    	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
    
    }
    

    可以看到这是一个函数式接口,实现这个接口,可以在spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,然后作一些修改操作,例如我可以将bean的scope从singleton改为prototype,也可以添加一些bean,具体能操作bean的方法全部在beanFactory中。我们可以看看beanFactory有哪些方法

    在这里插入图片描述

    其中提供的registerSingleton方法就可以让我注册bean,使用方式也很简单

    @Component
    public class TestPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            beanFactory.registerSingleton("test", new String("test"));
        }
    }
    

    这样我们就像spring容器中注册了一个String类型的bean,beanName为 test

    这里在这个接口执行前其实spring BeanDefinition已经扫描完成了,我们使用这种方式还不不太好,相当于强制暴力的去修改BeanDefinition属性,可能修改不当会有一些bug。有没有什么方法在扫描的时候添加BeanDefinition呢?也是有的

    主要提供了这两个接口:

    BeanDefinitionRegistryPostProcessor

    public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    
    	/**
    	 * Modify the application context's internal bean definition registry after its
    	 * standard initialization. All regular bean definitions will have been loaded,
    	 * but no beans will have been instantiated yet. This allows for adding further
    	 * bean definitions before the next post-processing phase kicks in.
    	 * @param registry the bean definition registry used by the application context
    	 * @throws org.springframework.beans.BeansException in case of errors
    	 */
    	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
    
    }
    

    可以看到BeanDefinitionRegistryPostProcessor也是继承了BeanFactoryPostProcessor,但是我们在使用BeanDefinitionRegistryPostProcessor只需要实现他的postProcessBeanDefinitionRegistry方法即可, postProcessBeanFactory方法放一个空实现即可,这样让一个类只做一件事,满足单一原则

    使用方式也很简单

    public class CustomBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {
    
    	@Override
    	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    	}
    
    	@Override
    	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    		RootBeanDefinition testBean = new RootBeanDefinition(Test.class);
    		//新增Bean定义
    		registry.registerBeanDefinition("test", testBean);
    	}
    
    }
    

    这样就完成了testBean的注册

    ImportBeanDefinitionRegistrar

    public interface ImportBeanDefinitionRegistrar {
    
    	/**
    	 * Register bean definitions as necessary based on the given annotation metadata of
    	 * the importing {@code @Configuration} class.
    	 * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
    	 * registered here, due to lifecycle constraints related to {@code @Configuration}
    	 * class processing.
    	 * @param importingClassMetadata annotation metadata of the importing class
    	 * @param registry current bean definition registry
    	 */
    	public void registerBeanDefinitions(
    			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
    
    }
    

    ImportBeanDefinitionRegistrar可以看到除了像BeanDefinitionRegistryPostProcessor提供了BeanDefinitionRegistry参数,还提供了一个AnnotationMetadata参数,该参数可以获取指定注解的属性。一般来说BeanDefinitionRegistryPostProcessor用来解析外部资源配置ImportBeanDefinitionRegistrar解析注解配置

    如果对mybatis源码了解多的就可以发现mybatis整合spring其中的两个配置类

    MapperScannerConfigurer就是实现了BeanDefinitionRegistryPostProcessor,

    MapperScannerRegistrar就是实现了ImportBeanDefinitionRegistrar

    说了这么多,我们还没有聊今天的主角FactoryBean

    来看看源码

    public interface FactoryBean<T> {
      //获取bean
    	@Nullable
    	T getObject() throws Exception;
      
    	@Nullable
      //获取classType
    	Class<?> getObjectType();
      //是否单例
    	default boolean isSingleton() {
    		return true;
    	}
    
    }
    

    三个方法也是比较简单,实现FactoryBean的Bean本事 就是一个Bean, 不同的是 Spring 对其做了特殊处理,在试图获取时FactoryBean时,获取的是getObject() 返回的对象。

    既然获取FactoryBean对象的时候,获取的是getObject() 方法的bean对象,那么我们是不是可以基于FactoryBean设置出一个获取所有mapper代理对象的bean呢?

    public class MyFactoryBean<T> implements FactoryBean<T> {
    
        private final Class<T> clazz;
    
        public MyFactoryBean(Class<T> clazz) {
            this.clazz = clazz;
        }
        @Override
        public T getObject() throws Exception {
            return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{clazz}, new MyFactoryBeanHandler());
        }
        @Override
        public Class<?> getObjectType() {
            return clazz;
        }
    }
    
    • MyFactoryBeanHandler
    public class MyFactoryBeanHandler implements InvocationHandler
    {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 仅仅打印注解上的sql 假装执行代理对象执行sql
            Select annotation = method.getAnnotation(Select.class);
            if (annotation == null) return null;
            Class<?> returnType = method.getReturnType();
            System.out.println("-------> " + Arrays.toString(annotation.value()));
            return null;
        }
    }
    

    这样我们在getObject()的时候就可以返回我们的代理对象了,但是有个问题我们的class类型是通过构造方法传入的。如果我们使用

    beanDefinition.setBeanClass(MyFactoryBean.class);
    

    注入对象MyFactoryBean我们能使用getObject()获取到代理对象吗?明显是不能的,因为我们没有传入clazz属性

    那我们的class属性哪里来呢?从BeanDefinition中获取

    beanDefinition.getBeanClassName()
    

    这样就可以获取到我之前的接口OneTestDao类名

    然后通过设置构造方法的参数

    beanDefinition.getConstructorArgumentValues().addGenericArgumentValue()
    

    最后代码就变成了如下

    beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
    

    到这里就能实例化我们自己的FactoryBean,从而在获取我们的Dao接口时获取的都是代理对象,这就是Spring整合Mybatis的核心实现。也是FactoryBean的一个应用场景,如果你知道了这些,再去看spring整合Mybatis源码就会发现整个过程特别清晰,也就理解了FactoryBean的作用

    总结

    所以说FactoryBean本质就是用来给我们实例化、或者动态的注入一些比较复杂的Bean,比如像一些接口的代理对象。这里简单说一下和BeanFactory的区别,最主要的一个区别是FactoryBean是动态注入Bean和BeanFactory主要是负责Bean实例化、定位、配置应用程序中的对象及建立这些对象间的依赖.三言两语无法说清,后续有机会重点分析BeanFactory再来细说吧

    参考

    博客

    展开全文
  • FactoryBean

    2020-11-10 22:14:51
    作用 自定义Bean的创建过程 定义 public interface FactoryBean<T> { /** * Return an instance (possibly shared or independent) of the object * managed by this factory. * <p>As with...

    参考FactoryBean(一)FactoryBean(二),进行总结

    FactoryBean

    作用

    自定义Bean的创建过程

    定义

    public interface FactoryBean<T> {
    
    	/**
    	 * Return an instance (possibly shared or independent) of the object
    	 * managed by this factory.
    	 * <p>As with a {@link BeanFactory}, this allows support for both the
    	 * Singleton and Prototype design pattern.
    	 * <p>If this FactoryBean is not fully initialized yet at the time of
    	 * the call (for example because it is involved in a circular reference),
    	 * throw a corresponding {@link FactoryBeanNotInitializedException}.
    	 * <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}
    	 * objects. The factory will consider this as normal value to be used; it
    	 * will not throw a FactoryBeanNotInitializedException in this case anymore.
    	 * FactoryBean implementations are encouraged to throw
    	 * FactoryBeanNotInitializedException themselves now, as appropriate.
    	 * @return an instance of the bean (can be {@code null})
    	 * @throws Exception in case of creation errors
    	 * @see FactoryBeanNotInitializedException
    	 */
    	@Nullable
    	T getObject() throws Exception;
    
    	/**
    	 * Return the type of object that this FactoryBean creates,
    	 * or {@code null} if not known in advance.
    	 * <p>This allows one to check for specific types of beans without
    	 * instantiating objects, for example on autowiring.
    	 * <p>In the case of implementations that are creating a singleton object,
    	 * this method should try to avoid singleton creation as far as possible;
    	 * it should rather estimate the type in advance.
    	 * For prototypes, returning a meaningful type here is advisable too.
    	 * <p>This method can be called <i>before</i> this FactoryBean has
    	 * been fully initialized. It must not rely on state created during
    	 * initialization; of course, it can still use such state if available.
    	 * <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return
    	 * {@code null} here. Therefore it is highly recommended to implement
    	 * this method properly, using the current state of the FactoryBean.
    	 * @return the type of object that this FactoryBean creates,
    	 * or {@code null} if not known at the time of the call
    	 * @see ListableBeanFactory#getBeansOfType
    	 */
    	@Nullable
    	Class<?> getObjectType();
    
    	/**
    	 * Is the object managed by this factory a singleton? That is,
    	 * will {@link #getObject()} always return the same object
    	 * (a reference that can be cached)?
    	 * <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,
    	 * the object returned from {@code getObject()} might get cached
    	 * by the owning BeanFactory. Hence, do not return {@code true}
    	 * unless the FactoryBean always exposes the same reference.
    	 * <p>The singleton status of the FactoryBean itself will generally
    	 * be provided by the owning BeanFactory; usually, it has to be
    	 * defined as singleton there.
    	 * <p><b>NOTE:</b> This method returning {@code false} does not
    	 * necessarily indicate that returned objects are independent instances.
    	 * An implementation of the extended {@link SmartFactoryBean} interface
    	 * may explicitly indicate independent instances through its
    	 * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}
    	 * implementations which do not implement this extended interface are
    	 * simply assumed to always return independent instances if the
    	 * {@code isSingleton()} implementation returns {@code false}.
    	 * <p>The default implementation returns {@code true}, since a
    	 * {@code FactoryBean} typically manages a singleton instance.
    	 * @return whether the exposed object is a singleton
    	 * @see #getObject()
    	 * @see SmartFactoryBean#isPrototype()
    	 */
    	default boolean isSingleton() {
    		return true;
    	}
    
    }
    

     

     

    展开全文
  • FactoryBean作用

    万次阅读 2018-07-23 14:24:16
    Spring 中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean 即 FactoryBeanFactoryBean跟普通Bean不同,其返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象。创建出来的对象...
  • Spring FactoryBean作用

    千次阅读 2018-07-18 21:43:40
    在Spring中,一般情况下,配置的什么类型就会可以通过getBean()获取到相同类型的实例,对于一些复杂的bean,需要进行大量初始化工作的,我们就可以让这个bean实现FactoryBean&lt;T&gt;这个接口, public ...
  • FactoryBean是Spring中一种特殊的Bean,是用于创建Bean对象的,最大的作用便是可以让我们自定义Bean的创建过程。如果你在XML配置文件配置了一个节点,我们通过ApplicationContext获取的对象实际上是getObject方法...
  • BeanFactory与FactoryBean,相信很多刚翻看Spring源码的同学跟我一样很好奇这俩货怎么长得这么像,分别都是干啥用的。BeanFactory是Spring中Bean工厂的顶层接口,也是我们常说的SpringIOC容器,它定下了IOC容器的...
  • FactoryBean的实现原理与作用

    万次阅读 多人点赞 2016-08-27 16:44:56
    本文通过简单描述FactoryBean与Beanfactory的区别,通过IOC源码中对该类型的Bean的解析讲解其原理,并附上小案例帮助大家理解FactoryBean的核心方法。
  • FactoryBean的使用方法及作用

    千次阅读 2019-01-19 23:19:08
    FactoryBean 的使用方法 自定义 MyFactoryBean ,只需要实现 FactoryBean 接口即可 package com.jack.factoryBean; @Component public class MyFactoryBean implements FactoryBean&lt;MyService&gt; { @...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,775
精华内容 4,310
关键字:

factorybean作用