组件扫描会妨碍 bean 初始化吗?
component-scan get in the way of bean initialization?
我在尝试复制一个简单的 spring OAuth 项目 sparklr2 时遇到了这个问题。源代码在这里
https://github.com/spring-projects/spring-security-oauth/tree/master/samples/oauth2/sparklr
源代码 运行 非常完美,当我使用 tomcat 调试它时,它会初始化 WebMvcConfigurerAdapter 中的所有 @Bean,包括控制器。但注意到 @ComponentScan() 没有被使用。
然后我创建了自己的 MVC 项目,复制了几乎 100% 的代码,但我使用的是 WebApplicationInitializer 而不是 AbstractDispatcherServletInitializer。我使用 WebApllicationInitializer 因为我只学会了这种编码 MVC 的方式。
然后我运行项目,@Bean初始化。然后我用我的浏览器检查 /login,得到 404。这可能是由于 spring 不知道我有控制器,然后我将 @ComponentScan 添加到我的配置 class,/login 现在出现了。
但奇怪的是,所有与Controller相关的@Bean,都没有被初始化。因此,当我调用这些控制器的任何方法时,由于它们的属性未初始化,因此没有对象或空异常。
所以,我的意思是,该示例如何工作,我的意思是控制器和 jsp 在不使用 @ComponentScan 的情况下正确处理和响应?
从不同的角度来看,为什么@ComponentScan 会阻止@Bean 在我的项目中被初始化?
我的 WebApplicationInitializer
@Configuration
@EnableWebMvc
@ComponentScan("umedia.test.oauth.controller")
public class MvcConfig extends WebMvcConfigurerAdapter {
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public ContentNegotiatingViewResolver contentViewResolver()
throws Exception {
ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
contentNegotiationManager.addMediaType("json",
MediaType.APPLICATION_JSON);
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
MappingJackson2JsonView defaultView = new MappingJackson2JsonView();
defaultView.setExtractValueFromSingleKeyModel(true);
ContentNegotiatingViewResolver contentViewResolver = new ContentNegotiatingViewResolver();
contentViewResolver
.setContentNegotiationManager(contentNegotiationManager
.getObject());
contentViewResolver.setViewResolvers(Arrays
.<ViewResolver> asList(viewResolver));
contentViewResolver.setDefaultViews(Arrays.<View> asList(defaultView));
return contentViewResolver;
}
@Bean
public PhotoServiceImpl photoServices() {
List<PhotoInfo> photos = new ArrayList<PhotoInfo>();
photos.add(createPhoto("1", "marissa"));
photos.add(createPhoto("2", "paul"));
photos.add(createPhoto("3", "marissa"));
photos.add(createPhoto("4", "paul"));
photos.add(createPhoto("5", "marissa"));
photos.add(createPhoto("6", "paul"));
PhotoServiceImpl photoServices = new PhotoServiceImpl();
photoServices.setPhotos(photos);
return photoServices;
}
// N.B. the @Qualifier here should not be necessary (gh-298) but lots of
// users report needing it.
@Bean
public AdminController adminController(
TokenStore tokenStore,
@Qualifier("consumerTokenServices") ConsumerTokenServices tokenServices,
SparklrUserApprovalHandler userApprovalHandler) {
AdminController adminController = new AdminController();
adminController.setTokenStore(tokenStore);
adminController.setTokenServices(tokenServices);
adminController.setUserApprovalHandler(userApprovalHandler);
return adminController;
}
// this url, do I need to change it?
private PhotoInfo createPhoto(String id, String userId) {
PhotoInfo photo = new PhotoInfo();
photo.setId(id);
photo.setName("photo" + id + ".jpg");
photo.setUserId(userId);
photo.setResourceURL("/org/springframework/security/oauth/examples/sparklr/impl/resources/"
+ photo.getName());
return photo;
}
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Bean
public PhotoServiceUserController photoServiceUserController(
PhotoService photoService) {
PhotoServiceUserController photoServiceUserController = new PhotoServiceUserController();
return photoServiceUserController;
}
@Bean
public PhotoController photoController(PhotoService photoService) {
PhotoController photoController = new PhotoController();
photoController.setPhotoService(photoService);
return photoController;
}
@Bean
public AccessConfirmationController accessConfirmationController(
ClientDetailsService clientDetailsService,
ApprovalStore approvalStore) {
AccessConfirmationController accessConfirmationController = new AccessConfirmationController();
accessConfirmationController
.setClientDetailsService(clientDetailsService);
accessConfirmationController.setApprovalStore(approvalStore);
return accessConfirmationController;
}
/* @Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations(
"/resources/");
}
}
那么,您有 @ComponentScan
与控制器上的 @Controller
交互 + 仍然创建 @Bean
吗?
作为第一步,尝试删除 @Beans
并尝试使用 @Autowired
在控制器的构造函数中注入依赖项。然后@ComponentScan 应该识别 @Controller
,注入依赖项并使用 @RequestMapping
没有问题。
我在尝试复制一个简单的 spring OAuth 项目 sparklr2 时遇到了这个问题。源代码在这里 https://github.com/spring-projects/spring-security-oauth/tree/master/samples/oauth2/sparklr
源代码 运行 非常完美,当我使用 tomcat 调试它时,它会初始化 WebMvcConfigurerAdapter 中的所有 @Bean,包括控制器。但注意到 @ComponentScan() 没有被使用。
然后我创建了自己的 MVC 项目,复制了几乎 100% 的代码,但我使用的是 WebApplicationInitializer 而不是 AbstractDispatcherServletInitializer。我使用 WebApllicationInitializer 因为我只学会了这种编码 MVC 的方式。
然后我运行项目,@Bean初始化。然后我用我的浏览器检查 /login,得到 404。这可能是由于 spring 不知道我有控制器,然后我将 @ComponentScan 添加到我的配置 class,/login 现在出现了。 但奇怪的是,所有与Controller相关的@Bean,都没有被初始化。因此,当我调用这些控制器的任何方法时,由于它们的属性未初始化,因此没有对象或空异常。
所以,我的意思是,该示例如何工作,我的意思是控制器和 jsp 在不使用 @ComponentScan 的情况下正确处理和响应? 从不同的角度来看,为什么@ComponentScan 会阻止@Bean 在我的项目中被初始化?
我的 WebApplicationInitializer
@Configuration
@EnableWebMvc
@ComponentScan("umedia.test.oauth.controller")
public class MvcConfig extends WebMvcConfigurerAdapter {
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public ContentNegotiatingViewResolver contentViewResolver()
throws Exception {
ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
contentNegotiationManager.addMediaType("json",
MediaType.APPLICATION_JSON);
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
MappingJackson2JsonView defaultView = new MappingJackson2JsonView();
defaultView.setExtractValueFromSingleKeyModel(true);
ContentNegotiatingViewResolver contentViewResolver = new ContentNegotiatingViewResolver();
contentViewResolver
.setContentNegotiationManager(contentNegotiationManager
.getObject());
contentViewResolver.setViewResolvers(Arrays
.<ViewResolver> asList(viewResolver));
contentViewResolver.setDefaultViews(Arrays.<View> asList(defaultView));
return contentViewResolver;
}
@Bean
public PhotoServiceImpl photoServices() {
List<PhotoInfo> photos = new ArrayList<PhotoInfo>();
photos.add(createPhoto("1", "marissa"));
photos.add(createPhoto("2", "paul"));
photos.add(createPhoto("3", "marissa"));
photos.add(createPhoto("4", "paul"));
photos.add(createPhoto("5", "marissa"));
photos.add(createPhoto("6", "paul"));
PhotoServiceImpl photoServices = new PhotoServiceImpl();
photoServices.setPhotos(photos);
return photoServices;
}
// N.B. the @Qualifier here should not be necessary (gh-298) but lots of
// users report needing it.
@Bean
public AdminController adminController(
TokenStore tokenStore,
@Qualifier("consumerTokenServices") ConsumerTokenServices tokenServices,
SparklrUserApprovalHandler userApprovalHandler) {
AdminController adminController = new AdminController();
adminController.setTokenStore(tokenStore);
adminController.setTokenServices(tokenServices);
adminController.setUserApprovalHandler(userApprovalHandler);
return adminController;
}
// this url, do I need to change it?
private PhotoInfo createPhoto(String id, String userId) {
PhotoInfo photo = new PhotoInfo();
photo.setId(id);
photo.setName("photo" + id + ".jpg");
photo.setUserId(userId);
photo.setResourceURL("/org/springframework/security/oauth/examples/sparklr/impl/resources/"
+ photo.getName());
return photo;
}
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Bean
public PhotoServiceUserController photoServiceUserController(
PhotoService photoService) {
PhotoServiceUserController photoServiceUserController = new PhotoServiceUserController();
return photoServiceUserController;
}
@Bean
public PhotoController photoController(PhotoService photoService) {
PhotoController photoController = new PhotoController();
photoController.setPhotoService(photoService);
return photoController;
}
@Bean
public AccessConfirmationController accessConfirmationController(
ClientDetailsService clientDetailsService,
ApprovalStore approvalStore) {
AccessConfirmationController accessConfirmationController = new AccessConfirmationController();
accessConfirmationController
.setClientDetailsService(clientDetailsService);
accessConfirmationController.setApprovalStore(approvalStore);
return accessConfirmationController;
}
/* @Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations(
"/resources/");
}
}
那么,您有 @ComponentScan
与控制器上的 @Controller
交互 + 仍然创建 @Bean
吗?
作为第一步,尝试删除 @Beans
并尝试使用 @Autowired
在控制器的构造函数中注入依赖项。然后@ComponentScan 应该识别 @Controller
,注入依赖项并使用 @RequestMapping
没有问题。