代码之家  ›  专栏  ›  技术社区  ›  sidlejinks

Spring FactoryBean公司

  •  1
  • sidlejinks  · 技术社区  · 11 年前

    我正在努力掌握Spring的FactoryBean,我已经遇到了问题。你能看看下面我的消息来源并回答吗。这是我的应用程序上下文:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                               http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                               http://www.springframework.org/schema/context
                               http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    
        <context:annotation-config/>
    
        <bean id="SHADigest" class="com.dtoryanik.spring.factorybean.MessageDigestFactoryBean">
            <property name="algorithmName">
                <value>SHA1</value>
            </property>
        </bean>
    
        <bean id="defaultDigest" class="com.dtoryanik.spring.factorybean.MessageDigestFactoryBean"/>
    
        <bean id="digester" class="com.dtoryanik.spring.factorybean.MessageDigester">
            <property name="messageDigest1">
                <ref local="SHADigest"/>
            </property>
            <property name="messageDigest2">
                <ref local="defaultDigest"/>
            </property>
        </bean>
    </beans>
    

    实际上这是一个工厂的豆子:

    public class MessageDigestFactoryBean implements FactoryBean<MessageDigest>{
    
        private String algorithmName = "MD5";
        private MessageDigest messageDigest = null;
    
        @Override
        public MessageDigest getObject() throws Exception {
            System.out.println("<> MessageDigestFactoryBean.getObject()");
            return messageDigest;
        }
    
        @Override
        public Class<?> getObjectType() {
            System.out.println("<> MessageDigestFactoryBean.getObjectType()");
            return MessageDigest.class;
        }
    
        @Override
        public boolean isSingleton() {
            System.out.println("<> MessageDigestFactoryBean.isSingleton()");
            return true;
        }
    
        @PostConstruct
        public void postConstructHandler() throws NoSuchAlgorithmException {
            System.out.println("<> MessageDigestFactoryBean.postConstructHandler()");
            messageDigest = MessageDigest.getInstance(algorithmName);
        }
    
        public void setAlgorithmName(String algorithmName) {
            this.algorithmName = algorithmName;
        }
    }
    

    还有另一个类-MessageDigester,但它对主题没有任何帮助。我有一个主要的方法类:

    public class MessageDigestDemo {
    
    public static void main(String[] args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:app-ctx.xml");
        ctx.refresh();
    
        MessageDigester messageDigester = (MessageDigester) ctx.getBean("digester");
        messageDigester.digest("Hello World!");
    }
    

    }

    这个问题在我的输出中。我似乎有一个双重实例化。方法isSingleton()和getObject()为每个bean调用两次(尽管我只从工厂检索了两个实例)。为什么会发生这种情况?也许我做错了什么?

    <> MessageDigestFactoryBean.postConstructHandler()
    <> MessageDigestFactoryBean.postConstructHandler()
    <> MessageDigestFactoryBean.isSingleton()
    <> MessageDigestFactoryBean.getObject()
    <> MessageDigestFactoryBean.isSingleton()
    <> MessageDigestFactoryBean.getObject()
    <> MessageDigestFactoryBean.isSingleton()
    <> MessageDigestFactoryBean.getObjectType()
    <> MessageDigestFactoryBean.isSingleton()
    <> MessageDigestFactoryBean.getObjectType()
    
    1 回复  |  直到 11 年前
        1
  •  2
  •   Dmitry Kuskov    11 年前

    我修改了你的 MessageDigestFactoryBean 类,以便输出 algorithmName 同样,这将有助于澄清此案。更改后,输出为:

    <> MessageDigestFactoryBean.postConstructHandler() SHA1
    <> MessageDigestFactoryBean.postConstructHandler() MD5
    <> MessageDigestFactoryBean.isSingleton() SHA1
    <> MessageDigestFactoryBean.getObject() SHA1
    <> MessageDigestFactoryBean.isSingleton() MD5
    <> MessageDigestFactoryBean.getObject() MD5
    <> MessageDigestFactoryBean.isSingleton() SHA1
    <> MessageDigestFactoryBean.getObjectType() SHA1
    <> MessageDigestFactoryBean.isSingleton() MD5
    <> MessageDigestFactoryBean.getObjectType() MD5
    

    让我们试着分析一下这个输出。

    1. 你已经申报了两个 消息挖掘FactoryBean 实例,因此当Spring在上下文中发现它们时,它会初始化它们,并在过程中调用带注释的方法 @PostConstruct - MessageDigestFactoryBean.postConstructHandler() .
    2. 然后,正如Spring发现的那样 digester bean,它试图获得它的依赖项。Spring认为依赖关系是 FactoryBean ,所以它最终调用 FactoryBeanRegistrySupport.getObjectFromFactoryBean 。此方法首先检查bean是否为singleton,调用 MessageDigestFactoryBean.isSingleton() 如果bean是singleton,那么它首先尝试从工厂bean对象缓存中获取对它的引用。由于这是第一次引用这个bean,它还没有被缓存,所以引用是通过 MessageDigestFactoryBean.getObject() ,已缓存,然后返回。由于您在中引用了两个工厂bean 蒸煮器 ,显然,对每一个都重复这个过程。
    3. 初始化完成后,Spring尝试发布 ContextRefreshedEvent 到生命周期处理器,因此它在所有bean定义中搜索实现的实例 Lifecycle 界面基本上,Spring循环遍历上下文中定义的所有bean,检查匹配类型的singleton bean(实际上还有更多的检查,但我们只对这些感兴趣)。在这个过程中,对于工厂的豆子 消息挖掘FactoryBean.isSingleton() 被调用以确定对象是否为singleton,并且 MessageDigestFactoryBean.getObjectType() 被调用以检查对象的类型是否可从 Lifecycle 界面同样,由于您有两个 消息挖掘FactoryBean ,这些方法中的每一个都被调用两次。

    这就是你打电话时会发生的事情 ctx.refresh() 。这只是一个夸张的外观,显然Spring在引擎盖下做了很多工作,但这就是我所能看到的与您的输出相关的全部内容。希望这能回答你的第一个问题。

    现在,对于第二个问题——不,您没有做错任何事情,您看到的输出只是反映了Spring的内部功能。