0

这是Spring + Jackson + joda time的后续问题:如何指定序列化/反序列化格式?.

在写最终版代码的时候,第一次写成这样:(只显示相关部分)

@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,因为使用了 Spring Boot 的默认 @EnableWebMvc 类。
请注意,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:如何指定序列化/反序列化格式?,即UserIntercepter bean被拉出ApiWebMvcConfiguration,问题就没有了。

这是正确的行为吗?
@Bean 不应该嵌套吗?

4

2 回答 2

0

Spring 尝试实例化ApiWebMvcConfiguration自身。这不起作用,因为非静态内部类不能像普通类一样实例化。他们需要对外部类的实例的引用。因此出现错误消息“未找到默认构造函数”。

当您将内部类更改为静态类时,实例化会起作用,但正如您所注意到的,它仍然会发生两次。

问题 @BeanuserInterceptor(). 你告诉 Spring 它可以从这个方法中获取一个 bean。但是为了得到一个,Spring 需要一个ApiWebMvcConfiguration. 所以它自己创造了一个。但随后该方法创建了另一个apiWebMvcConfiguration()

于 2013-12-19T07:37:02.177 回答
0

@Configuration 类中的嵌套类总是被解释为@Bean。因此,您通过添加自己的显式 @Bean 定义来注册它两次。

于 2013-12-19T07:37:35.923 回答