spring 的父子容器的关系;规格和继承一样! 父容器不能使用子容器的bean,子容器可以!
WHY:包扫描BUG!引出spring父子容器的问题。
在spring核心概念中【容器】是核心思想,它是用来管理bean生命周期的,在一个项目中存在多个容器时,就会有这个层级关系;
SSM中常用的是spring+springMVC配置文件;
【可以用配置:<context:component-scan base-package="**" /> 批量注册,且不需要分开注册,
Spring提供的参考手册中我们得知该配置的功能是扫描配置的base-package包下的所有使用了@Component注解的类,
并且将它们自动注册到容器中,
同时也扫描@Controller,@Service,@Respository这三个注解,因为他们是继承自@Component。
<context:component-scan base-package="~~" />必须在spring中配置并且必须加上下面配置;因为springMVC默认不会去找父容器中的Controller】
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="detectHandlerMethodsInAncestorContexts">
<value>true</value>
</property>
</bean> {最下面有 解 }
{此配置 上面配置默认打开}
<context:annotation-config/>配置代表的是:默认声明注解:@Required , @Autowired , @PostConstrut
@PersistenceContext , @Resource , @PreDestroy
<mvc:annotation-driven />
这个是SpringMVC必须要配置的,它声明了@RequestMapping、@RequestBody、@ResponseBody等。
并且,该配置默认加载很多的参数绑定方法,比如json转换解析器等
@RequestMapping :请求及请求路径映射到具体方法上
@RequestBody :页面JOSN转成java对象
@ResponseBody :后端Java对象转JSON数据
等价的配置
<!--配置注解控制器映射器,它是SpringMVC中用来将Request请求URL到映射到具体Controller-->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<!--配置注解控制器映射器,它是SpringMVC中用来将具体请求映射到具体方法-->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<!--配置注解控制器映射器,它是SpringMVC中用来将Request请求URL到映射到具体Controller-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--配置注解控制器映射器,它是SpringMVC中用来将具体请求映射到具体方法-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
这个不是很清楚【**】
下面我们来查看具体原因,翻看源码,从SpringMVC的DispatcherServlet开始往下找,
我们发现SpringMVC初始化时,会寻找SpringMVC容器中的所有使用了@Controller注解的Bean,
来确定其是否是一个handler。
1,2两步的配置使得当前springMVC容器中并没有注册带有@Controller注解的Bean,
而是把所有带有@Controller注解的Bean都注册在Spring这个父容器中了,
所以springMVC找不到处理器,不能进行跳转。核心源码如下:
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (isHandler(getApplicationContext().getType(beanName))){
detectHandlerMethods(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
在方法isHandler中会判断当前bean的注解是否是controller
protected boolean isHandler(Class<?> beanType) {
return AnnotationUtils.findAnnotation(beanType, Controller.class) != null;
}
在initHandlerMethod()方法中的detectHandlerMethodsInAncestorContexts默认是不包括父容器的;所以解决之前的问题可以在
springMVC的配置中加
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="detectHandlerMethodsInAncestorContexts">
<value>true</value>
</property>
</bean>
SpringMVC容器会把service、dao层的bean重新加载,
从而造成新加载的bean覆盖了老的bean,
但事务的AOP代理没有配置在spring-mvc.xml配置文件中,造成事务失效。
解决办法是:在spring-mvc.xml配置文件中的context:component-scan标签中
使用use-default-filters=“false”禁用掉默认的行为。
<context:component-scan base-package="com.hafiz.www" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
mybatis+spring+springMVC小整合:
注意:spring配置和springMVC配置存在的父子容器的关系;spring[父]:不能使用springMVC[子]容器的bean;相反 子>>父
介意: spring:扫描service
bean映射器配置器MapperScannerConfigurer -->basePackage扫描dao ;
springMVC:扫描Controller ;
网友评论