• 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
    努力了的才叫梦想,不努力的就是空想,努力并且坚持下去,毕竟这是我相信的力量
  • 相关阅读:
    思维导图 第八章 项目质量管理
    思维导图 第七章 项目成本管理
    redis安装与配置
    思维导图 第六章 项目进度管理
    思维导图 第五章 项目范围管理
    Linux下用户-组权限配置
    意灵魔法馆首页的初步设计
    try catch自定义异常类的使用
    使用freemarker时,生成的html出现乱码
    乱码问题
  • 原文地址:https://www.cnblogs.com/Joe-Go/p/10143550.html
Copyright © 2020-2023  润新知