gpt4 book ai didi

java - @RestController bean 在根上下文中注册,尽管在 excludeFilters 中被排除

转载 作者:行者123 更新时间:2023-11-29 03:13:04 26 4
gpt4 key购买 nike

所以我使用基于 Java 的配置来启动 tomcat 容器,并创建 spring 上下文。这是我的配置类的样子:

@Configuration
public class WebAppInitializer implements WebApplicationInitializer {

private static final Logger LOGGER = LoggerFactory.getLogger(WebAppInitializer.class);

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
LOGGER.debug("Starting Spring Container");
WebApplicationContext rootContext = createRootContext(servletContext);
configureSpringMvc(servletContext, rootContext);
}

private WebApplicationContext createRootContext(ServletContext servletContext) {
LOGGER.debug("Creating Root Context");
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootConfig.class);

servletContext.addListener(new ContextLoaderListener(rootContext));
LOGGER.debug("Created Root Context");
return rootContext;
}

private void configureSpringMvc(ServletContext servletContext, WebApplicationContext rootContext) {
LOGGER.debug("Creating Child Context");
AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();
mvcContext.register(WebMvcConfig.class);
mvcContext.setParent(rootContext);

ServletRegistration.Dynamic appServlet = servletContext.addServlet("dispatcher", new DispatcherServlet(mvcContext));
FilterRegistration.Dynamic authFilter = servletContext.addFilter("authFilter", AuthenticationFilter.class);
authFilter.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), true, "dispatcher");
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/");
LOGGER.debug("Created Child Context");
}
}

如您所见,RootConfig.class 构成我的根应用程序上下文,WebMvcConfig 构成子应用程序上下文。

这些类看起来像:

@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan(basePackages = { "a.b.controller" })
public class WebMvcConfig extends WebMvcConfigurerAdapter {
}

@Configuration
@Import(value = { PropertiesConfig.class, AppConfig.class })
@ComponentScan(basePackages = "a.b", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = RestController.class))
public class RootConfig {
}

注意两个类上的@ComponentScan。包 a.b.controller 包含我的 @RestController。我希望它们仅在子上下文中初始化。

所以在我的根上下文中,我已经从组件扫描中排除了 @RestController 注释的类。所以我想那些 Controller 不应该在那里注册。然而,这并没有发生。我所有的其余 Controller 都在根上下文中注册,然后在子上下文中注册(它覆盖了根上下文中的 Controller )。

我不确定为什么会发生这种情况,运气不好也无法解决。我的应用程序中没有任何 web.xml,因为一切都由 java 配置处理。这是一个问题。

第二个问题是,即使 RestController 注册了两次,当它在子上下文中加载时,我也无法解析这些 Controller 中的 @Value 注释属性。但是,从根上下文加载时,属性会得到解析。

这是一个例子:

@RestController
public class PropertyLessController {

@Value("${prop1}")
private String prop1;

@PostConstruct
public void init() {
LOGGER.debug("Property loaded: {}", prop1);
}
}

我在 init() 方法中记录属性。该日志出现两次:

Property loaded: someActualValue
Property loaded: @{prop1}

第一个来自根上下文(具有已解析属性),第二个来自子上下文(具有未解析属性)。现在为什么会这样?

我正在使用 Spring 4.1.0.RELEASE

最佳答案

这有点棘手。

@RestController@Controller 是元注解。 @RestController@Controller 注解,@Controller@Component 注解。

通过这个元注释 属性,组件扫描过程找到您的PropertyLessController 类型。它为 @RestController 忽略它,但为 @Controller(或 @Component)找到它,然后处理程序映射堆栈注册它,因为它找到 @Controller@RequestMapping

一个解决方案是在 excludeFilters 中列出 @Component@Controller 或将 useDefaultFilters 设置为错误。显然,这可能对您不起作用,因为您可能希望通过这些注释找到其他类型。

“正确”的解决方案是单独打包您的东西。

关于属性(property)决议。您配置的PropertyPlaceholderConfigurerPropertySourcesPlaceholderConfigurer(还没有看到您的PropertiesConfig)是一个BeanFactoryPostProcessor。这种类型的处理器只处理其包含的 BeanFactory 中的 beans。换句话说,子上下文的 BeanFactory 不会在父上下文中使用 BeanFactoryPostProcessor (afaik)。由于您的 PropertiesConfig 是在您的 RootConfig 中声明的,因此只有在那里定义的 bean 才能获得属性解析。

您可以在 Controller 的 init 方法中放置一个断点。您会注意到,@Value 注释字段的值对于在 DispatcherServlet 的上下文(子上下文)中初始化的 bean 是未解析的。

关于java - @RestController bean 在根上下文中注册,尽管在 excludeFilters 中被排除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28220239/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com