在spring官網文檔中無論是spring的基礎文檔,還是spring-mvc文檔都推薦我們使用javaconfig的方式來搭建項目 間接說明
(優點:javaconfig配置>xml配置) 其實 springboot內部就是通過這種方式來做的而我們可以通過這種方式來搭一般的ssm項目,
甚至自己手動內嵌一個tomcat搭建一個簡單的springboot項目都是可以的 。早在servlet3.0開始就能實現零xml配置搭建項目了
(現在最新servlet4.0,下面也會說到為什么從3.0開始可以實現springmvc的零xml配置),也就是說 通過xml搭建項目對於現在而言確實比較老了 。。。
1、首先創建一個maven的web項目
(1)、pom依賴 (后面需要其他的再加) :servlet依賴是用來使用servlet3.0 SCI新特性 實現 零xml 配置的
(2)目錄結構
創建WebApplication 類 等於:web.xml
創建SpringApplicationContext類 等於spring-context.xml 容器
(3)首先通過javaconfig方式配置spring容器(為什么先配置spring容器就不再說了)
只需要 兩個注解 就能實現對spring容器的配置 包括在啟動容器時實例化對象、提供注解的支持、DI等
@Configuration:表示是一個spring容器
@ComponentScan("com.it") 包掃描 ,這里我只創建了com.it.controller(路徑的顆粒度也是可以任意配置的,官網文檔有介紹)
注意 : 從spring4.0 開始 ,就只需設置包掃描 就能完成對spring核心的配置了 ,無需額外打開 注解、驅動之類的設置
這些在spring-core源碼包中都有體現 至此就完成了對spring最基本的配置。。。
(4)如果現在需要測試的話 , 以前是用ClassPathXmlApplicationContext 來加載xml 實例spring容器 ,
現在在main方法通過AnnotationConfigApplicationContext 加載spring容器就完事了 (這里就不測試了,整合完了SpringMVC再測試 )
(5) 配置spring-mvc ,官網文檔中寫的很清楚
web.xml主要配置包括兩部分 配置spring容器和 配置speingMVC這里也是一樣
A、在實例化 spring容器時使用AnnotationConfigWebApplicationContext的register方法來注冊,而AnnotationConfigApplicationContext
通過構造器來實例化spring容器, 其實AnnotationConfigApplicationContext 的構造器(下圖) 的源碼中ClassPathXmlApplicationContext
都是 通過register()這種方法 ,然后refresh() 實例化spring的 容器的
B、spring整合springMVC無非就是 管理DispactcherServlet ,然后再將DispactcherServlet 對象放入tomcat容器,在tomcat啟動的時候 加載
setOnStartUp(1) :在項目啟動的時候就將dispatcherServlet加載
addMapping("/") : 攔截的請求
(6)、部署項目運行tomcat 就能從頁面訪問項目了(自己寫controller測試) 訪問:http://localhost:8080/項目名/RequestMapping
(7) 下面 來提一個問題 ,進而引入 servlet3.0 SCI 特性 ,我們知道 web.xml是項目的主入口 , 在tomcat啟動的時候會加載項目的
WEB-INF/web.xml這個文件 。由於web.xml 配置配置了spring、springMVC 通過解析xml 和 反射技術就能打到對spring容器的創建
問題 :現在只是自己創建了一個WebApplication 類 ,tomcat 也不知道我們具體定義的是什么類放在什么地方,他是如何加載到的呢?
分析源碼可以知曉 下圖:
A、ServletContainerInitializer接口 簡稱 SCI :作用是 在tomcat啟動容器階段通過編程風格將filter、Servlet、Listener添加至servlet
容器從而取代web.xml中的filter、Servlet、Listener的配置
B、在tomcat啟動階段 ,來獲取ServletContainerInitializer的實現類然后執行其onStartUp()方法 ,
spring的SpringServletContainerInitializer 實現了此方法並執行他的onStartUp()方法 ,那么問題來了
ServletAPI也不知道 spring 是用 哪個類 實現這個 ServletContainerInitializer接口的並且tomcat(tomcat中內嵌servlet)
和spring兩個項目是分開的(沒有耦合),那么tomcat是如何加載到 SpringServletContainerInitializer類的呢?
SCI規范在一個類型實現了ServletContainerInitializer時,項目啟動的時候 會將實現這個接口的所有的實現類的 權限定的類名寫到
META-INF/services/javax.servlet.ServletContainerInitializer文件中 ,maven依賴可以看到:
org.springframework.web.SpringServletContainerInitializer
SpringServletContainerInitializer類的實例是通過反射加載這個文件下的全限定類名得到的,根據上面的流程圖
SpringServletContainerInitializer類中的onStartUp方法中 會執行WebApplicationInitializer接口的onStartUp()方法,
根據多態,我們自己項目中 定的WebApplication 類的 onStartUp方法執行 , 才能實現spring容器的初始化,然后管理springMVC
1 @HandlesTypes(WebApplicationInitializer.class)//注解用於注入實現WebApplicationInitializer接口的類的對象, 2 //放入onStartUp()方法的set集合中然后遍歷執行實現類中的onStartUp() 3 public class SpringServletContainerInitializer implements ServletContainerInitializer { 4 @Override 5 public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) 6 throws ServletException { 7 8 List<WebApplicationInitializer> initializers = new LinkedList<>(); 9 10 if (webAppInitializerClasses != null) { 11 for (Class<?> waiClass : webAppInitializerClasses) { 12 // Be defensive: Some servlet containers provide us with invalid classes, 13 // no matter what @HandlesTypes says... 14 if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && 15 WebApplicationInitializer.class.isAssignableFrom(waiClass)) { 16 try { 17 initializers.add((WebApplicationInitializer) 18 ReflectionUtils.accessibleConstructor(waiClass).newInstance()); 19 } 20 catch (Throwable ex) { 21 throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex); 22 } 23 } 24 } 25 } 26 27 if (initializers.isEmpty()) { 28 servletContext.log("No Spring WebApplicationInitializer types detected on classpath"); 29 return; 30 } 31 32 servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); 33 AnnotationAwareOrderComparator.sort(initializers); 34 for (WebApplicationInitializer initializer : initializers) { 35 initializer.onStartup(servletContext); 36 } 37 }
@HandlesTypes(WebApplicationInitializer.clas)注解: 上面的一段代碼是 SpringServletContainerInitializer類的源碼 ,
當onStartUp執行的時候 會將實現WebApplicationInitializer接口的類也就是項目中中自定義的
WebApplication類 注入到當前類中並用Set參數接收
(8)整合Mybatis
(1)整合Mybatis相關依賴
<!-- 添加mybatis依賴--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!--mybatis-spring依賴--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.2</version> </dependency> <!-- mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.7.RELEASE</version> </dependency>
(2)、SpringApplicationContext.java 配置 (思路是跟.xml 一樣的)
數據源的配置可以寫到 .yml 文件中然后再寫個工具類解析的,這里為了方便就直接硬編碼帶代碼里了
。另外這里只配置了 最基本的需要,如果下配置如事物、aop、上傳等 使用@Bean注入即可
@Configuration @ComponentScan("com.it") public class SpringApplicationContext { //創建數據源 @Bean("dataSource") public DataSource getDataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/t1?useUnicode=true&characterEncoding=UTF-8"); dataSource.setUsername("root"); dataSource.setPassword("xxx"); dataSource.setInitialSize(3); dataSource.setMaxIdle(10); dataSource.setMaxWait(1000);//最長等待時間 return dataSource; } //管理mybatis的selSessionBean @Bean("sqlSessionFactoryBean") //value :為創建的 bean取別名,默認是方法名首字母小寫 //參數DataSource :sqlSessionFactoryBean 依賴參數DataSource public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource dataSource) { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); //數據源 sqlSessionFactoryBean.setDataSource(dataSource); //mapper配置 "classpath*:mapping/*Mapper.xml" Resource[] resources = null; try{ resources = new PathMatchingResourcePatternResolver().getResources("classpath*:com/it/dao/mapping/*Mapper.xml"); }catch (Exception e){ e.printStackTrace(); } sqlSessionFactoryBean.setMapperLocations(resources); return sqlSessionFactoryBean; } //掃描mapper創建dao代理 @Bean public MapperScannerConfigurer getMapperScannerConfigurer(){ MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.it.dao"); mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean"); return mapperScannerConfigurer; } }
下一篇:在此基礎上 內置tomcat 來模仿 Springoot main方法啟動web項目