回顾一下我们一般写的项目包括那些包吧:
- config目录存入的是配置类,写过的配置类有:
- ServletContainersInitConfig
- SpringConfig
- SpringMvcConfig
- JdbcConfig
- MybatisConfig
- controller目录存放的是SpringMVC的controller类
- service目录存放的是service接口和实现类
- dao目录存放的是dao/Mapper接口
bean加载控制
众所周知controller、service和dao这些类都需要被容器管理成bean对象:
- SpringMVC加载其相关bean(表现层bean),也就是controller包下的类
- Spring控制的bean
- 业务bean(Service)
- 功能bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等)
如下图所示:
其实很简单我们只需要在SpringMVC的配置类SpringMvcConfig
中使用注解@ComponentScan
,我们只需要将其扫描范围设置到controller即可
但是新的问题出现了,因为在Spring的配置类SpringConfig
中使用注解@ComponentScan
,当时扫描的范围中其实是已经包含了controller
从包结构来看的话,Spring已经多把SpringMVC的controller类也给扫描到,所以因为功能不同,如何避免Spring错误加载到SpringMVC的bean我们继续往下看。
具体操作
解决那个我们我们很容易想到方案:加载Spring控制的bean的时候排除掉SpringMVC控制的bean。
- 方式一:Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等
- 方式二:Spring加载的bean设定扫描范围为com.itheima,排除掉controller包中的bean
- 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中[我不会我跟的视频老师没讲,因为是初阶这里就不涉及了,后面想起来了我会重新回来填坑的]
我们举个例子看下,一下面项目结构为例:
先悄悄给大家搂一样解决方案
方案一
修改Spring配置类,设定扫描范围为精准范围。
@Configuration
@ComponentScan({"com.taro.service","com.taro.dao"})
public class SpringConfig {
}
当然这个例子说明可以精确指定让Spring扫描对应的包结构,真正在做开发的时候,Dao最终是交给MapperScannerConfigurer
对象来进行扫描处理的,我们只需要将其扫描到service包即可。 当然现在还是推荐推荐推荐扫描一下的
。
方案二
方式二:修改Spring配置类,设定扫描范围为com.itheima,排除掉controller包中的bean
@Configuration
@ComponentScan(value="com.taro",
excludeFilters=@ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
public class SpringConfig {
}
还记得@Configuration注解嘛,我们之前提到过,他出现的类Spring在扫描时会扫描它并加载bean
@Configuration//这里这里这里
@ComponentScan("com.taro.controller")
public class SpringMvcConfig {
}
接下来就是介绍一下我们写的那些属性都是哈了:
- excludeFilters属性:设置扫描加载bean时,排除的过滤规则
- type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
- ANNOTATION:按照注解排除
- ASSIGNABLE_TYPE:按照指定的类型过滤
- ASPECTJ:按照Aspectj表达式排除,基本上不会用
- REGEX:按照正则表达式排除
- CUSTOM:按照自定义规则排除
- classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
当然,有了Spring的配置类,要想在tomcat服务器启动将其加载,我们需要修改ServletContainersInitConfig,还记得我们之前写的吗?
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
既然氛围都到这里了,不整点简单的都不好意思了;
//web配置类简化开发,仅设置配置类类名即可
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
直观的对比感受一下吧:
他俩是父子类哦。。。