美文网首页
Spring核心——FactoryBean

Spring核心——FactoryBean

作者: 零点145 | 来源:发表于2019-07-11 20:02 被阅读0次

    本文继续之前的2篇文章(BeanPostProcessorBeanFactoryPostProcessor)介绍Ioc容器的功能扩展。

    FactoryBean是用来构造Bean的接口。常规情况下向容器添加一个Bean只需要像下面这样通过XML的配置或注解直接引入这个类即可:

    @ComponentclassA{}

    但是某些情况下我们需要动态的装载一个复的Bean,此时可以使用FactoryBean来动态装载一个Bean。FactoryBean字面上看就知道它是一个Bean,但是有Factory的功能(工厂模式)。

    FactoryBean的使用和之前介绍的Processor 一样,实现一个接口,然后设置为一个Spring的Bean即可:

    classMyFactoryimplementsFactoryBean{@OverridepublicObjectgetObject()throwsException{returnnull;}@OverridepublicClassgetObjectType(){returnnull;}}

    下面通过一个适配器的例子来说明FactoryBean的使用,文中的代码仅用于示例,可执行源码请移步 https://gitee.com/chkui-com/spring-core-sample 中的 chkui.springcore.example.xml.factorybean包。

    例子是使用适配器模式对对应的资源进行解码,执行一下3步:

     容器启动之后会加载一个密文资源类,可能是Base64的编码,也可能是UrlBase64的编码,根据配置来确定。

     FactoryBean会根据资源类型向容器添加一个解码的适配器。

     最后用适配器解码输出。

    例子的代码结构如下:

    factorybean

    --BeanFactoryApp.java main方法

    --AdapterFactory.java 一个FactoryBean,用于生成适配器Bean

    --entity

    ----Text.java 编码资源类的接口

    ----Base64Entity.java Base64编码

    ----UrlBase64Entity.java urlBase64编码

    --adapter

    ----DecodeAdapter.java 解码适配器接口

    ----Base64Adapter.java Base64的解码适配器

    ----UrlBase64Adapter.java UrlBase64的解码适配器

    另外配置文件在 resources/xml/factorybean/config.xml:

    <!-- Base64编码 --><!-- UrlBase64编码 --><!-- <bean class="chkui.springcore.example.xml.factorybean.entity.UrlBase64Entity">

        <constructor-arg value="一串加密的文字。URLBase64和Base64的区别是调整了可以用于URL的符号,例如+替换为-。"/>

        </bean> -->

    Base64Entity和UrlBase64Entity是2个资源类,分别用Base64和UrlBase64对字符串进行编码,通过配置来管理。下面是Text和Base64Entity的代码:

    packagechkui.springcore.example.xml.factorybean.entity;//文本资源接口publicinterfaceText{//定义资源类型,目前支持Base64和UrlBase642种加密编码文件publicstaticenumType{Base64,UrlBase64}//获取资源编码类型TypegetType();//获取编码的密文StringgetCipher();}

    packagechkui.springcore.example.xml.factorybean.entity;publicclassBase64EntityimplementsText{privateString cipher;publicBase64Entity(String text){this.cipher = Base64.getEncoder().encodeToString(text.getBytes());}@OverridepublicTypegetType(){returnText.Type.Base64;}@OverridepublicStringgetCipher(){returncipher;}}

    然后我们根据不同的资源定义了不同的适配器来解码,下面是适配器接口和一个实现类——DecodeAdapter、Base64Adapter:

    packagechkui.springcore.example.xml.factorybean.adapter;//加密编码文件解码适配器publicinterfaceDecodeAdapter{//获取解码之后的明文StringgetPlain();}

    packagechkui.springcore.example.xml.factorybean.adapter;publicclassBase64AdapterimplementsDecodeAdapter{privateString cipher;publicBase64Adapter(String cipher){this.cipher = cipher;}@OverridepublicStringgetPlain(){returnnewString(Base64.getDecoder().decode(cipher));}}

    最后是核心的FactoryBean——AdapterFactory,他的作用是根据当前向IoC添加的资源类型来确定启用哪个适配器。AdapterFactory继承了BeanFactoryAware以便获得BeanFactory实例:

    publicclassAdapterFactoryimplementsFactoryBean,BeanFactoryAware{privateText text;privatevolatileDecodeAdapter adapter;@OverridepublicDecodeAdaptergetObject()throws Exception{//根据IoC中的资源类型选择适配器,懒加载模式returnlazyLoadAdapter();}@OverridepublicClass getObjectType() {returnDecodeAdapter.class;}@OverridepublicvoidsetBeanFactory(BeanFactory beanFactory)throws BeansException{this.text = beanFactory.getBean(Text.class);}privateDecodeAdapterlazyLoadAdapter(){if(null == adapter) {synchronized (AdapterFactory.class) {if(null == adapter) {switch(text.getType()) {caseUrlBase64: adapter =newUrlBase64Adapter(text.getCipher());break;caseBase64:default:adapter =newBase64Adapter(text.getCipher());break;}}}}returnthis.adapter;}}

    lazyLoadAdapter方法实现了适配的过程——根据不同的编码类型返回不同的适配器。最后运行容器:

    packagechkui.springcore.example.xml.factorybean;publicclassBeanFactoryApp{publicstaticvoidmain(String[] args){    ApplicationContext context =newClassPathXmlApplicationContext("xml/factorybean/config.xml");    Text text = context.getBean(Text.class);System.out.println("密文:"+ text.getCipher());System.out.println("编码类型:"+ text.getType());DecodeAdapter decode = context.getBean(DecodeAdapter.class);System.out.println("明文:"+ decode.getPlain());    }//通过符号规则获取工厂BeanprivatestaticvoidnameSymbol(ApplicationContext context){    Object adapter = context.getBean("adapter");//获取实际BeanSystem.out.println("adapterClass :"+ adapter.getClass().getName());adapter = context.getBean("&adapter");//获取实际工厂BeanSystem.out.println("adapterClass :"+ adapter.getClass().getName());    }}

    实际上,Spring的所有预设Bean都是通过FactoryBean实现的,现在大概有50多个Spring官方实现的FactoryBean。

    注意nameSymbol方法中的代码和BeanFactory的配置——<bean id="adapter" class="chkui.springcore.example.xml.factorybean.AdapterFactory" />。如果为BeanFactory指定了ID或别名,那么通过ID获取到的是工厂生成Bean而不是这个工厂本身。但是可以通过在之前增加"&"符号来告诉IoC获取BeanFactory本身。

    相关文章

      网友评论

          本文标题:Spring核心——FactoryBean

          本文链接:https://www.haomeiwen.com/subject/dahjkctx.html