2017-10-30 4 views
0

Ich habe einige seltsame Probleme, wo FactoryBean.getObject() aufgerufen wird, bevor die FactoryBean initialisiert wird. Ich habe ein kleines Sample erstellt, das etwas Mist aufweist. Es ist nicht das genaue Problem, das ich mit meiner größeren Anwendung sehe, aber ich denke, es ist verwandt.Spring Anwendungskontext - FactoryBean.getObject() aufgerufen vor FactoryBean initialisiert

Dies wird durch eine kreisförmige Referenz wahrscheinlich verursacht, wo

  • node1 Referenzen node2
  • und node2 Referenzen node1

I Frühling bin mit Version 4.2.4.RELEASE

SpringTestContext.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<beans 
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" 
> 
    <bean id="node1" class="com.hsbc.gbm.dsl.dtm.test.SpringTest$NodeFactory"> 
     <property name="next" ref="node2" /> 
    </bean> 

    <bean id="node2" class="com.hsbc.gbm.dsl.dtm.test.SpringTest$NodeFactory"> 
     <property name="prev" ref="node1" /> 
    </bean> 
</beans> 

SpringTest.java

public class SpringTest { 
    public static class Node { 
     private final Node next; 
     private final Node prev; 
     public Node(Node prev, Node next) { 
      super(); 
      this.prev = prev; 
      this.next = next; 
     } 
    } 

    public static class NodeFactory implements FactoryBean<Node>, BeanNameAware, ApplicationContextAware, InitializingBean { 
     private Node next; 
     private Node prev; 
     private String beanName; 
     private Node node; 
     private ApplicationContext applicationContext; 
     private boolean initialized; 

     public void setNext(Node next) { 
      this.next = next; 
     } 

     public void setPrev(Node prev) { 
      this.prev = prev; 
     } 

     @Override 
     public void setBeanName(String beanName) { 
      this.beanName = beanName; 
     } 

     @Override 
     public void setApplicationContext(ApplicationContext applicationContext) { 
      this.applicationContext = applicationContext; 
     } 

     @Override 
     public Class<?> getObjectType() { 
      return Node.class; 
     } 

     @Override 
     public void afterPropertiesSet() throws Exception { 
      node = new Node(prev, next); 
      initialized = true; 
     } 

     @Override 
     public Node getObject() { 
      System.out.println(String.format("NodeFactory: getObject() beanName=%s, initialized=%s, applicationContext=%s", 
       beanName, initialized, applicationContext)); 

      if (!initialized) { 
       throw new RuntimeException("NodeFactory not initialized before getObject() for " + beanName); 
      } 
      return node; 
     } 

     public boolean isSingleton() { 
      return true; 
     } 
    } 

    @Test 
    public void test() { 
     ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("com/hsbc/gbm/dsl/dtm/test/SpringTestContext.xml"); 
     appContext.start(); 
    } 
} 

Ausgabe

NodeFactory: getObject() beanName=null, initialized=false, applicationContext=null 

Exception

Caused by: java.lang.RuntimeException: NodeFactory not initialized before getObject() for null 
    at com.foo.SpringTest$NodeFactory.getObject(SpringTest.java:74) 
    at com.foo.SpringTest$NodeFactory.getObject(SpringTest.java:1) 
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168) 
    ... 53 more 

Voll Trace

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'node1' defined in class path resource [com/foo/SpringTestContext.xml]: Cannot resolve reference to bean 'node2' while setting bean property 'next'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'node2' defined in class path resource [com/foo/SpringTestContext.xml]: Cannot resolve reference to bean 'node1' while setting bean property 'prev'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'node1': FactoryBean threw exception on object creation; nested exception is java.lang.RuntimeException: NodeFactory not initialized before getObject() for null 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359) 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1481) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1226) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:753) 
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) 
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) 
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) 
    at com.foo.SpringTest.test(SpringTest.java:117) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) 
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'node2' defined in class path resource [com/foo/SpringTestContext.xml]: Cannot resolve reference to bean 'node1' while setting bean property 'prev'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'node1': FactoryBean threw exception on object creation; nested exception is java.lang.RuntimeException: NodeFactory not initialized before getObject() for null 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359) 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1481) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1226) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351) 
    ... 38 more 
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'node1': FactoryBean threw exception on object creation; nested exception is java.lang.RuntimeException: NodeFactory not initialized before getObject() for null 
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:175) 
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:127) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1585) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:254) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351) 
    ... 48 more 
Caused by: java.lang.RuntimeException: NodeFactory not initialized before getObject() for null 
    at com.foo.SpringTest$NodeFactory.getObject(SpringTest.java:74) 
    at com.foo.SpringTest$NodeFactory.getObject(SpringTest.java:1) 
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168) 
    ... 53 more 

Antwort

0

Für alle, die das gleiche Problem haben, löste ich dies, indem ich die zirkuläre Abhängigkeit beseitigte. Ich tat dies, indem ich einen String anstelle eines Node für die prev Eigenschaft einsetzte.

ZB:

public static class NodeFactory implements FactoryBean<Node>, ... { 
     private Node next; 
     private String prevBeanId; 
     ... 
    } 

XML

<bean id="node2" class="com.hsbc.gbm.dsl.dtm.test.SpringTest$NodeFactory"> 
    <property name="prevBeanId" value="node1" /> 
</bean> 

Ich würde Frühling erwartet haben irgendeine Form von CircularReferenceException geworfen zu haben, anstatt Factory.getObject() Aufruf, bevor es initialisiert wird.

In meiner realen Anwendung war der Zirkelverweis schwieriger zu sehen, da es viele Bohnen im Kreis und nicht die beiden im Beispiel-Testfall gab.

Verwandte Themen