SpringMVC?bean加載控制的實(shí)現(xiàn)分析
一、問(wèn)題分析
入門(mén)案例的內(nèi)容已經(jīng)做完了,在入門(mén)案例中我們創(chuàng)建過(guò)一個(gè)SpringMvcConfig
的配置類,再回想前面咱們學(xué)習(xí)Spring的時(shí)候也創(chuàng)建過(guò)一個(gè)配置類SpringConfig
。這兩個(gè)配置類都需要加載資源,那么它們分別都需要加載哪些內(nèi)容?
我們先來(lái)看下目前我們的項(xiàng)目目錄結(jié)構(gòu):
config目錄存入的是配置類,寫(xiě)過(guò)的配置類有:
- ServletContainersInitConfig
- SpringConfig
- SpringMvcConfig
- JdbcConfig
- MybatisConfig
controller目錄存放的是SpringMVC的controller類
service目錄存放的是service接口和實(shí)現(xiàn)類
dao目錄存放的是dao/Mapper接口
controller、service和dao這些類都需要被容器管理成bean對(duì)象,那么到底是該讓SpringMVC加載還是讓Spring加載呢?
SpringMVC加載其相關(guān)bean(表現(xiàn)層bean),也就是controller包下的類
Spring控制的bean
- 業(yè)務(wù)bean(Service)
- 功能bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等)
分析清楚誰(shuí)該管哪些bean以后,接下來(lái)要解決的問(wèn)題是如何讓Spring和SpringMVC分開(kāi)加載各自的內(nèi)容。
在SpringMVC的配置類SpringMvcConfig
中使用注解@ComponentScan
,我們只需要將其掃描范圍設(shè)置到controller即可,如
@configuration @componentscan ("com.itheima.contro1ler") public class springMvcconfig { }
在Spring的配置類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類也給掃描到,所以針對(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依賴
<?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)的配置類
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類
@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配置類,設(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配置類,設(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í)的注解類型進(jìn)行排除
- ANNOTATION:按照注解排除
- ASSIGNABLE_TYPE:按照指定的類型過(guò)濾
- ASPECTJ:按照Aspectj表達(dá)式排除,基本上不會(huì)用
- REGEX:按照正則表達(dá)式排除
- CUSTOM:按照自定義規(guī)則排除
大家只需要知道第一種ANNOTATION即可
classes屬性:設(shè)置排除的具體注解類,當(dāng)前設(shè)置排除@Controller定義的bean
如何測(cè)試controller類已經(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配置類上的@ComponentScan注解注釋掉,否則不會(huì)報(bào)錯(cuò)==
出現(xiàn)問(wèn)題的原因是,
- Spring配置類掃描的包是
com.itheima
- SpringMVC的配置類,
SpringMvcConfig
上有一個(gè)@Configuration注解,也會(huì)被Spring掃描到 - SpringMvcConfig上又有一個(gè)@ComponentScan,把controller類又給掃描進(jìn)來(lái)了
- 所以如果不把@ComponentScan注釋掉,Spring配置類將Controller排除,但是因?yàn)閽呙璧絊pringMVC的配置類,又將其加載回來(lái),演示的效果就出不來(lái)
- 解決方案,也簡(jiǎn)單,把SpringMVC的配置類移出Spring配置類的掃描范圍即可。
最后一個(gè)問(wèn)題,有了Spring的配置類,要想在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)的配置類,如何實(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
名稱 | @ComponentScan |
---|---|
類型 | 類注解 |
位置 | 類定義上方 |
作用 | 設(shè)置spring配置類掃描路徑,用于加載使用注解格式定義的bean |
相關(guān)屬性 | excludeFilters:排除掃描路徑中加載的bean,需要指定類別(type)和具體項(xiàng)(classes) includeFilters:加載指定的bean,需要指定類別(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-06Java設(shè)計(jì)模式之訪問(wèn)者模式使用場(chǎng)景及代碼示例
這篇文章主要介紹了Java設(shè)計(jì)模式之訪問(wèn)者模式使用場(chǎng)景及代碼示例,小編覺(jué)得還是挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。2017-11-11java數(shù)據(jù)結(jié)構(gòu)之棧的詳解
這篇文章主要為大家詳細(xì)介紹了Java數(shù)據(jù)結(jié)構(gòu)的棧的應(yīng)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能給你帶來(lái)幫助2021-08-08Spring mvc防止數(shù)據(jù)重復(fù)提交的方法
這篇文章主要為大家詳細(xì)介紹了Spring mvc防止數(shù)據(jù)重復(fù)提交的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11Java函數(shù)式接口Supplier接口實(shí)例詳解
這篇文章主要介紹了Java函數(shù)式接口Supplier接口實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02解決Maven中關(guān)于依賴導(dǎo)入不進(jìn)的問(wèn)題
這篇文章主要介紹了解決Maven中關(guān)于依賴導(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