SpringMVC?bean加載控制的實現(xiàn)分析
一、問題分析
入門案例的內(nèi)容已經(jīng)做完了,在入門案例中我們創(chuàng)建過一個SpringMvcConfig
的配置類,再回想前面咱們學(xué)習(xí)Spring的時候也創(chuàng)建過一個配置類SpringConfig
。這兩個配置類都需要加載資源,那么它們分別都需要加載哪些內(nèi)容?
我們先來看下目前我們的項目目錄結(jié)構(gòu):
config目錄存入的是配置類,寫過的配置類有:
- ServletContainersInitConfig
- SpringConfig
- SpringMvcConfig
- JdbcConfig
- MybatisConfig
controller目錄存放的是SpringMVC的controller類
service目錄存放的是service接口和實現(xiàn)類
dao目錄存放的是dao/Mapper接口
controller、service和dao這些類都需要被容器管理成bean對象,那么到底是該讓SpringMVC加載還是讓Spring加載呢?
SpringMVC加載其相關(guān)bean(表現(xiàn)層bean),也就是controller包下的類
Spring控制的bean
- 業(yè)務(wù)bean(Service)
- 功能bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等)
分析清楚誰該管哪些bean以后,接下來要解決的問題是如何讓Spring和SpringMVC分開加載各自的內(nèi)容。
在SpringMVC的配置類SpringMvcConfig
中使用注解@ComponentScan
,我們只需要將其掃描范圍設(shè)置到controller即可,如
@configuration @componentscan ("com.itheima.contro1ler") public class springMvcconfig { }
在Spring的配置類SpringConfig
中使用注解@ComponentScan
,當(dāng)時掃描的范圍中其實是已經(jīng)包含了controller,如:
@componentscan (value="com.itheima") public class springconfig { }
從包結(jié)構(gòu)來看的話,Spring已經(jīng)多把SpringMVC的controller類也給掃描到,所以針對這個問題該如何解決,就是咱們接下來要學(xué)習(xí)的內(nèi)容。
概況的描述下咱們現(xiàn)在的問題就是==因為功能不同,如何避免Spring錯誤加載到SpringMVC的bean?
二、思路分析
針對上面的問題,解決方案也比較簡單,就是:
- 加載Spring控制的bean的時候排除掉SpringMVC控制的備案
具體該如何排除,有兩種方式來解決:
- 方式一:Spring加載的bean設(shè)定掃描范圍為com.itheima,排除掉controller包中的bean
- 方式二:Spring加載的bean設(shè)定掃描范圍為精準(zhǔn)范圍,例如service包、dao包等
- 方式三:不區(qū)分Spring與SpringMVC的環(huán)境,加載到同一個環(huán)境中[了解即可]
三、環(huán)境準(zhǔn)備
創(chuàng)建一個Web的Maven項目
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)建對應(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 { }
編寫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)建好的項目結(jié)構(gòu)如下:
四、設(shè)置bean加載控制
方式一:修改Spring配置類,設(shè)定掃描范圍為精準(zhǔn)范圍。
@Configuration @ComponentScan({"com.itheima.service","comitheima.dao"}) public class SpringConfig { }
說明:
上述只是通過例子說明可以精確指定讓Spring掃描對應(yīng)的包結(jié)構(gòu),真正在做開發(fā)的時候,因為Dao最終是交給MapperScannerConfigurer
對象來進行掃描處理的,我們只需要將其掃描到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時,排除的過濾規(guī)則
type屬性:設(shè)置排除規(guī)則,當(dāng)前使用按照bean定義時的注解類型進行排除
- ANNOTATION:按照注解排除
- ASSIGNABLE_TYPE:按照指定的類型過濾
- ASPECTJ:按照Aspectj表達式排除,基本上不會用
- REGEX:按照正則表達式排除
- CUSTOM:按照自定義規(guī)則排除
大家只需要知道第一種ANNOTATION即可
classes屬性:設(shè)置排除的具體注解類,當(dāng)前設(shè)置排除@Controller定義的bean
如何測試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í)行就會報bean未被定義的錯誤
==注意:測試的時候,需要把SpringMvcConfig配置類上的@ComponentScan注解注釋掉,否則不會報錯==
出現(xiàn)問題的原因是,
- Spring配置類掃描的包是
com.itheima
- SpringMVC的配置類,
SpringMvcConfig
上有一個@Configuration注解,也會被Spring掃描到 - SpringMvcConfig上又有一個@ComponentScan,把controller類又給掃描進來了
- 所以如果不把@ComponentScan注釋掉,Spring配置類將Controller排除,但是因為掃描到SpringMVC的配置類,又將其加載回來,演示的效果就出不來
- 解決方案,也簡單,把SpringMVC的配置類移出Spring配置類的掃描范圍即可。
最后一個問題,有了Spring的配置類,要想在tomcat服務(wù)器啟動將其加載,我們需要修改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; } }
對于上述的配置方式,Spring還提供了一種更簡單的配置方式,可以不用再去創(chuàng)建AnnotationConfigWebApplicationContext
對象,不用手動register
對應(yīng)的配置類,如何實現(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[]{"/"}; } }
知識點:@ComponentScan
名稱 | @ComponentScan |
---|---|
類型 | 類注解 |
位置 | 類定義上方 |
作用 | 設(shè)置spring配置類掃描路徑,用于加載使用注解格式定義的bean |
相關(guān)屬性 | excludeFilters:排除掃描路徑中加載的bean,需要指定類別(type)和具體項(classes) includeFilters:加載指定的bean,需要指定類別(type)和具體項(classes) |
到此這篇關(guān)于SpringMVC bean加載控制的實現(xiàn)分析的文章就介紹到這了,更多相關(guān)SpringMVC bean加載控制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java數(shù)據(jù)結(jié)構(gòu)之棧的詳解
這篇文章主要為大家詳細(xì)介紹了Java數(shù)據(jù)結(jié)構(gòu)的棧的應(yīng)用,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能給你帶來幫助2021-08-08Spring mvc防止數(shù)據(jù)重復(fù)提交的方法
這篇文章主要為大家詳細(xì)介紹了Spring mvc防止數(shù)據(jù)重復(fù)提交的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-11-11解決Maven中關(guān)于依賴導(dǎo)入不進的問題
這篇文章主要介紹了解決Maven中關(guān)于依賴導(dǎo)入不進的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11使用java代碼獲取新浪微博應(yīng)用的access token代碼實例
這篇文章主要介紹了使用java代碼獲取新浪微博應(yīng)用的access token實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05