SpringMVC?bean加載控制的實(shí)現(xiàn)分析
一、問(wèn)題分析
入門(mén)案例的內(nèi)容已經(jīng)做完了,在入門(mén)案例中我們創(chuàng)建過(guò)一個(gè)SpringMvcConfig的配置類(lèi),再回想前面咱們學(xué)習(xí)Spring的時(shí)候也創(chuàng)建過(guò)一個(gè)配置類(lèi)SpringConfig。這兩個(gè)配置類(lèi)都需要加載資源,那么它們分別都需要加載哪些內(nèi)容?
我們先來(lái)看下目前我們的項(xiàng)目目錄結(jié)構(gòu):

config目錄存入的是配置類(lèi),寫(xiě)過(guò)的配置類(lèi)有:
- ServletContainersInitConfig
- SpringConfig
- SpringMvcConfig
- JdbcConfig
- MybatisConfig
controller目錄存放的是SpringMVC的controller類(lèi)
service目錄存放的是service接口和實(shí)現(xiàn)類(lèi)
dao目錄存放的是dao/Mapper接口
controller、service和dao這些類(lèi)都需要被容器管理成bean對(duì)象,那么到底是該讓SpringMVC加載還是讓Spring加載呢?
SpringMVC加載其相關(guān)bean(表現(xiàn)層bean),也就是controller包下的類(lèi)
Spring控制的bean
- 業(yè)務(wù)bean(Service)
- 功能bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等)
分析清楚誰(shuí)該管哪些bean以后,接下來(lái)要解決的問(wèn)題是如何讓Spring和SpringMVC分開(kāi)加載各自的內(nèi)容。
在SpringMVC的配置類(lèi)SpringMvcConfig中使用注解@ComponentScan,我們只需要將其掃描范圍設(shè)置到controller即可,如
@configuration
@componentscan ("com.itheima.contro1ler")
public class springMvcconfig {
}在Spring的配置類(lèi)SpringConfig中使用注解@ComponentScan,當(dāng)時(shí)掃描的范圍中其實(shí)是已經(jīng)包含了controller,如:
@componentscan (value="com.itheima")
public class springconfig {
}從包結(jié)構(gòu)來(lái)看的話,Spring已經(jīng)多把SpringMVC的controller類(lèi)也給掃描到,所以針對(duì)這個(gè)問(wèn)題該如何解決,就是咱們接下來(lái)要學(xué)習(xí)的內(nèi)容。
概況的描述下咱們現(xiàn)在的問(wèn)題就是==因?yàn)楣δ懿煌?,如何避免Spring錯(cuò)誤加載到SpringMVC的bean?
二、思路分析
針對(duì)上面的問(wèn)題,解決方案也比較簡(jiǎn)單,就是:
- 加載Spring控制的bean的時(shí)候排除掉SpringMVC控制的備案
具體該如何排除,有兩種方式來(lái)解決:
- 方式一:Spring加載的bean設(shè)定掃描范圍為com.itheima,排除掉controller包中的bean
- 方式二:Spring加載的bean設(shè)定掃描范圍為精準(zhǔn)范圍,例如service包、dao包等
- 方式三:不區(qū)分Spring與SpringMVC的環(huán)境,加載到同一個(gè)環(huán)境中[了解即可]
三、環(huán)境準(zhǔn)備
創(chuàng)建一個(gè)Web的Maven項(xiàng)目
pom.xml添加Spring依賴(lài)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>springmvc_02_bean_load</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>創(chuàng)建對(duì)應(yīng)的配置類(lèi)
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMvcConfig {
}
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}編寫(xiě)Controller,Service,Dao,Domain類(lèi)
@Controller
public class UserController {
@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'info':'springmvc'}";
}
}
public interface UserService {
public void save(User user);
}
@Service
public class UserServiceImpl implements UserService {
public void save(User user) {
System.out.println("user service ...");
}
}
public interface UserDao {
@Insert("insert into tbl_user(name,age)values(#{name},#{age})")
public void save(User user);
}
public class User {
private Integer id;
private String name;
private Integer age;
//setter..getter..toString略
}最終創(chuàng)建好的項(xiàng)目結(jié)構(gòu)如下:

四、設(shè)置bean加載控制
方式一:修改Spring配置類(lèi),設(shè)定掃描范圍為精準(zhǔn)范圍。
@Configuration
@ComponentScan({"com.itheima.service","comitheima.dao"})
public class SpringConfig {
}說(shuō)明:
上述只是通過(guò)例子說(shuō)明可以精確指定讓Spring掃描對(duì)應(yīng)的包結(jié)構(gòu),真正在做開(kāi)發(fā)的時(shí)候,因?yàn)镈ao最終是交給MapperScannerConfigurer對(duì)象來(lái)進(jìn)行掃描處理的,我們只需要將其掃描到service包即可。
方式二:修改Spring配置類(lèi),設(shè)定掃描范圍為com.itheima,排除掉controller包中的bean
@Configuration
@ComponentScan(value="com.itheima",
excludeFilters=@ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
public class SpringConfig {
}excludeFilters屬性:設(shè)置掃描加載bean時(shí),排除的過(guò)濾規(guī)則
type屬性:設(shè)置排除規(guī)則,當(dāng)前使用按照bean定義時(shí)的注解類(lèi)型進(jìn)行排除
- ANNOTATION:按照注解排除
- ASSIGNABLE_TYPE:按照指定的類(lèi)型過(guò)濾
- ASPECTJ:按照Aspectj表達(dá)式排除,基本上不會(huì)用
- REGEX:按照正則表達(dá)式排除
- CUSTOM:按照自定義規(guī)則排除
大家只需要知道第一種ANNOTATION即可
classes屬性:設(shè)置排除的具體注解類(lèi),當(dāng)前設(shè)置排除@Controller定義的bean
如何測(cè)試controller類(lèi)已經(jīng)被排除掉了?
public class App{
public static void main (String[] args){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
System.out.println(ctx.getBean(UserController.class));
}
}如果被排除了,該方法執(zhí)行就會(huì)報(bào)bean未被定義的錯(cuò)誤

==注意:測(cè)試的時(shí)候,需要把SpringMvcConfig配置類(lèi)上的@ComponentScan注解注釋掉,否則不會(huì)報(bào)錯(cuò)==
出現(xiàn)問(wèn)題的原因是,
- Spring配置類(lèi)掃描的包是
com.itheima - SpringMVC的配置類(lèi),
SpringMvcConfig上有一個(gè)@Configuration注解,也會(huì)被Spring掃描到 - SpringMvcConfig上又有一個(gè)@ComponentScan,把controller類(lèi)又給掃描進(jìn)來(lái)了
- 所以如果不把@ComponentScan注釋掉,Spring配置類(lèi)將Controller排除,但是因?yàn)閽呙璧絊pringMVC的配置類(lèi),又將其加載回來(lái),演示的效果就出不來(lái)
- 解決方案,也簡(jiǎn)單,把SpringMVC的配置類(lèi)移出Spring配置類(lèi)的掃描范圍即可。
最后一個(gè)問(wèn)題,有了Spring的配置類(lèi),要想在tomcat服務(wù)器啟動(dòng)將其加載,我們需要修改ServletContainersInitConfig
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
}對(duì)于上述的配置方式,Spring還提供了一種更簡(jiǎn)單的配置方式,可以不用再去創(chuàng)建AnnotationConfigWebApplicationContext對(duì)象,不用手動(dòng)register對(duì)應(yīng)的配置類(lèi),如何實(shí)現(xiàn)?
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[]{"/"};
}
}知識(shí)點(diǎn):@ComponentScan
| 名稱(chēng) | @ComponentScan |
|---|---|
| 類(lèi)型 | 類(lèi)注解 |
| 位置 | 類(lèi)定義上方 |
| 作用 | 設(shè)置spring配置類(lèi)掃描路徑,用于加載使用注解格式定義的bean |
| 相關(guān)屬性 | excludeFilters:排除掃描路徑中加載的bean,需要指定類(lèi)別(type)和具體項(xiàng)(classes) includeFilters:加載指定的bean,需要指定類(lèi)別(type)和具體項(xiàng)(classes) |
到此這篇關(guān)于SpringMVC bean加載控制的實(shí)現(xiàn)分析的文章就介紹到這了,更多相關(guān)SpringMVC bean加載控制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java多線程之火車(chē)售票系統(tǒng)模擬實(shí)例
下面小編就為大家?guī)?lái)一篇java多線程之火車(chē)售票系統(tǒng)模擬實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06
Java設(shè)計(jì)模式之訪問(wèn)者模式使用場(chǎng)景及代碼示例
這篇文章主要介紹了Java設(shè)計(jì)模式之訪問(wèn)者模式使用場(chǎng)景及代碼示例,小編覺(jué)得還是挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。2017-11-11
java數(shù)據(jù)結(jié)構(gòu)之棧的詳解
這篇文章主要為大家詳細(xì)介紹了Java數(shù)據(jù)結(jié)構(gòu)的棧的應(yīng)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能給你帶來(lái)幫助2021-08-08
Spring mvc防止數(shù)據(jù)重復(fù)提交的方法
這篇文章主要為大家詳細(xì)介紹了Spring mvc防止數(shù)據(jù)重復(fù)提交的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
Java函數(shù)式接口Supplier接口實(shí)例詳解
這篇文章主要介紹了Java函數(shù)式接口Supplier接口實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
解決Maven中關(guān)于依賴(lài)導(dǎo)入不進(jìn)的問(wèn)題
這篇文章主要介紹了解決Maven中關(guān)于依賴(lài)導(dǎo)入不進(jìn)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
使用java代碼獲取新浪微博應(yīng)用的access token代碼實(shí)例
這篇文章主要介紹了使用java代碼獲取新浪微博應(yīng)用的access token實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
Spring依賴(lài)注入DI之三種依賴(lài)注入類(lèi)型詳解
這篇文章主要介紹了Spring依賴(lài)注入DI之三種依賴(lài)注入類(lèi)型詳解,通過(guò) @Autowired 注解,字段注入的實(shí)現(xiàn)方式非常簡(jiǎn)單而直接,代碼的可讀性也很強(qiáng),事實(shí)上,字段注入是三種注入方式中最常用、也是最容易使用的一種,需要的朋友可以參考下2023-09-09

