2013-12-19 92 views
0

這是一個跟進問題Spring + Jackson + joda time: how to specify the serialization/deserialization format?Spring:WebMvcConfigurerAdapter bean註冊兩次

當我在寫代碼的最終版本,在我第一次寫,如下所示:(只相關部分顯示)

@Configuration 
public class WebMvcConfiguration 
{ 
    @Bean 
    public WebMvcConfigurerAdapter apiWebMvcConfiguration() 
    { 
     return new ApiWebMvcConfiguration(); 
    } 

    public class ApiWebMvcConfiguration extends WebMvcConfigurerAdapter 
    { 
     public ApiWebMvcConfiguration() 
     { 
      log.debug("### ApiWebMvcConfiguration"); 
     } 

     @Bean 
     public UserInterceptor userInterceptor() 
     { 
      return new UserInterceptor(false); 
     } 

     @Override 
     public void addInterceptors(InterceptorRegistry registry) 
     { 
      log.debug("### addInterceptors"); 
      registry.addInterceptor(userInterceptor()) 
       .addPathPatterns("/api/user/**"); 
     } 
    } 

    private static final Log log = 
     LogFactory.getLog(WebMvcConfiguration.class); 
} 

沒有@EnableWebMvc,因爲默認@EnableWebMvc使用Spring Boot類。
請注意,userInterceptor bean位於WebMvcConfigurerAdapter類中,該類也是一個bean。

當我運行應用程序,出現下列錯誤:
(我的類的類路徑名被換成我自己對「...」)

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name '...WebMvcConfiguration$ApiWebMvcConfiguration': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [...WebMvcConfiguration$ApiWebMvcConfiguration]: No default constructor found; nested exception is java.lang.NoSuchMethodException: ...WebMvcConfiguration$ApiWebMvcConfiguration.<init>() 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1076) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1021) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700) 
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482) 
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:124) 
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:609) 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) 
    at ...Application.main(Application.java:17) 
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [...WebMvcConfiguration$ApiWebMvcConfiguration]: No default constructor found; nested exception is java.lang.NoSuchMethodException: ...WebMvcConfiguration$ApiWebMvcConfiguration.<init>() 
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1069) 
    ... 14 more 
Caused by: java.lang.NoSuchMethodException: ...WebMvcConfiguration$ApiWebMvcConfiguration.<init>() 
    at java.lang.Class.getConstructor0(Class.java:2810) 
    at java.lang.Class.getDeclaredConstructor(Class.java:2053) 
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80) 
    ... 15 more 

然後,我改變ApiWebMvcConfiguration類靜態內心階層。

應用程序「正常」啓動,但ApiWebMvcConfiguration類實例化了兩次。即,「### ApiWebMvcConfiguration」被打印兩次。因此,「### addInterceptors」被打印兩次。

然後,當UserIntercepter的代碼運行時,由於null @Autowired JdbcTemplate失敗。也就是說@Autowired不是爲這個對象工作的。 (JdbcTemplate在其他對象中成功@Autowired)

因此,我將代碼更改爲最終版本,如Spring + Jackson + joda time: how to specify the serialization/deserialization format?所示,即UserIntercepter bean已從ApiWebMvcConfiguration中拔出,問題消失了。

這是正確的行爲?
@Bean是不是應該嵌套?

回答

0

Spring試圖實例化ApiWebMvcConfiguration本身。這不起作用,因爲非靜態內部類不能像普通類一樣實例化。他們需要對外部類的實例的引用。因此錯誤消息「找不到默認構造函數」。

當您將內部類更改爲靜態類時,實例化可以工作,但正如您注意到的那樣,它仍會發生兩次。

問題是userInterceptor()@Bean註釋。你告訴Spring它可以從這個方法獲得一個bean。但爲了獲得一個,Spring需要一個ApiWebMvcConfiguration的實例。所以它自己創造一個。但是另一個是由apiWebMvcConfiguration()方法創建的。

0

@Configuration類中的嵌套類總是被解釋爲@Bean。所以你通過添加你自己的顯式@Bean定義來註冊它兩次。

+0

謝謝。但是,如果刪除apiWebMvcConfiguration()方法,那麼ApiWebMvcConfiguration對象根本就沒有實例化。 (也許我不太明白你的解釋。) – zeodtr

+0

據我所知它會被實例化(只要它是'@ Configuration'和靜態的)。 –