zoukankan      html  css  js  c++  java
  • FactoryBean的使用

    前言

     一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean。在某些情况下,实例化bean的过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息,配置方式的灵活性是受限制的,这时采用编码的方式可能会得到一个更简单的方案。Spring为此提供了一个org.Springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。

    FactoryBean的简单使用

    FactoryBean接口对于Spring框架来说占有重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明为FactoryBean<T>的形式,如下:

    public interface FactoryBean<T> {
    
        T getObject() throws Exception;
    
        Class<?> getObjectType();
    
        default boolean isSingleton() {
            return true;
        }
    }

    可以看出,FactoryBean接口定义了3个方法:

      (1)T getObject():返回FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单例实例缓存池中。

      (2)boolean isSingleton():返回由FactoryBean创建bean实例的作用域是singleton还是prototype。

      (3)Class<T> getObjectType():返回FactoryBean创建的bean类型。

    当配置文件中<bean>的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean里getObject()方法所返回的对象,相当于FactoryBean里的getObject()代理了getBean()方法。

    例如:如果使用传统的配置文件方式配置下面的Hero的<bean>时,Hero的每个属性都会对应一个<property>元素标签。

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

    传统方式配置文件为:

    <bean id="hero" class="com.joe.mytag.Hero">
            <property name="age" value="25"></property>
            <property name="name" value="Joe"></property>
    </bean>

    如果用FactoryBean的方式实现就会灵活一些,下面举例为“,”分割符的方式一次性地为Hero的所有属性指定配置项:

    public class HeroFactoryBean implements FactoryBean<Hero> {
        public String getHeroInfo() {
            return heroInfo;
        }
    
        public void setHeroInfo(String heroInfo) {
            this.heroInfo = heroInfo;
        }
    
        private String heroInfo;
        @Override
        public Hero getObject() throws Exception {
            Hero hero = new Hero();
            String[] info = heroInfo.split(",");
            hero.setAge(Integer.parseInt(info[1]));
            hero.setName(info[0]);
            return hero;
        }
    
        @Override
        public Class<?> getObjectType() {
            return Hero.class;
        }
    
        @Override
        public boolean isSingleton() {
            return false;
        }
    }

    使用了FactoryBean后,配置文件为:

        <bean id="hero1" class="com.joe.mytag.HeroFactoryBean">
            <property name="heroInfo" value="Jordan,35"></property>
        </bean>

    测试:

    public class Main {
        @SuppressWarnings("deprecation")
        public static void main(String[] args) {
            BeanFactory bf = new XmlBeanFactory(new ClassPathResource("spring.xml"));
            Hero hero = (Hero) bf.getBean("hero1");
            System.out.println("name: " + hero.getName() + " age: " + hero.getAge());
        }
    }

    输出结果:

    十二月 19, 2018 2:42:31 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    信息: Loading XML bean definitions from class path resource [spring.xml]
    name: Jordan age: 35

    可以看出,成功。这只是一个简单的例子,如果有个JavaBean的属性多达十几二十个,如果使用传统的配置方式,那么就需要与属性种类一样多的<property>来进行配置,这样就会很麻烦。这时若使用FactoryBean来处理,则会方便很多。

    解释一下实现FactoryBean后,Spring的调用逻辑:当调用getBean("hero1")时,Spring通过反射机制发现HeroFactoryBean实现了FactoryBean接口,这时Spring容器就调用接口方法,HeroFactoryBean里的getObject()方法返回。如果希望获取HeroFactoryBean的实例,则需要在使用getBean(beanName)方法时在beanName前显示的加上"&"前缀,例如调用getBean("&hero1")。如下:

    public class Main {
        @SuppressWarnings("deprecation")
        public static void main(String[] args) {
            BeanFactory bf = new XmlBeanFactory(new ClassPathResource("spring.xml"));
            Object hero =  bf.getBean("&hero1");
            System.out.println(hero.toString() );
        }
    }

    输出结果:

    十二月 19, 2018 3:23:37 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    信息: Loading XML bean definitions from class path resource [spring.xml]
     com.joe.mytag.HeroFactoryBean@c818063

    参考:《Spring源码深度解析》 郝佳 编著:

    作者:Joe
    努力了的才叫梦想,不努力的就是空想,努力并且坚持下去,毕竟这是我相信的力量
  • 相关阅读:
    【Android Developers Training】 73. 布局变化的动画
    【Android Developers Training】 72. 缩放一个视图
    【Android Developers Training】 71. 显示翻牌动画
    svn更改地址怎么办
    python学习手册
    failed to bind pixmap to texture
    Ubuntu 12.04安装Google Chrome
    svn update 时总是提示 Password for '默认密钥' GNOME keyring: 输入密码
    重设SVN 的GNOME keyring [(null)] 的密码
    Nginx + uWSGI + web.py 搭建示例
  • 原文地址:https://www.cnblogs.com/Joe-Go/p/10143550.html
Copyright © 2011-2022 走看看