![](/img/trans.png)
[英]No bean resolver registered in the context to resolve access to bean
[英]@RestController bean registered in root context, despite being excluded in excludeFilters
因此,我已經使用基於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
上的@ComponentScan
。 包abcontroller
包含我的@RestController
。 我希望僅在子上下文中對它們進行初始化。
因此,在我的根上下文中,我從組件掃描中排除了@RestController
注釋的類。 所以我猜那些控制器不應該在那兒注冊。 但是,這沒有發生。 我所有的其余控制器都先在根上下文中注冊,然后在子上下文中注冊(在根上下文中覆蓋子控制器)。
我不確定為什么會這樣,並且無法解決問題。 我的應用程序中沒有任何web.xml ,因為java config可以確保一切正常。 這是一個問題。
第二個問題是,即使RestController已注冊兩次,當在子上下文中加載@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
設置為false
。 顯然,這可能對您不起作用,因為您可能希望通過這些注釋找到其他類型。
“適當”的解決方案是將您的東西分開包裝。
關於財產決議。 您配置的PropertyPlaceholderConfigurer
或PropertySourcesPlaceholderConfigurer
(尚未看到PropertiesConfig
)是BeanFactoryPostProcessor
。 這種類型的處理器僅處理其包含的BeanFactory
的bean。 換句話說,一個孩子上下文的BeanFactory
將不使用BeanFactoryPostProcessor
在父上下文(據我所知)。 由於您的PropertiesConfig
是在RootConfig
聲明的,因此只有在那里定義的bean才能獲得屬性解析。
您可以在控制器的init
方法中放置一個斷點。 您會注意到,對於在DispatcherServlet
的上下文(子上下文)中初始化的bean,未解析@Value
注釋字段的值。
問題是@ComponentScan
您的RootConfig
,雖然排除@RestController
它會掃描整個ab
包,包括所有的子包。 依次檢測WebMvcConfig
,該WebMvcConfig
依次掃描abcontroller
程序包,但不排除任何內容。 因此,您的控制器實例化了兩次,基本上所有與Web相關的內容(也包括Spring @MVC)都被加載了兩次。
@Configuration
也是@Component
,因此會自動檢測到。 要解決此問題,請在RootConfig
上為@Configuration
類添加排除RootConfig
。
@Configuration
@Import(value = { PropertiesConfig.class, AppConfig.class })
@ComponentScan( basePackages = "a.b",
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = RestController.class),
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class})
public class RootConfig {}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.