聊聊spring
spring對於java開發者來說,是最熟悉不過的框架了,我們日常開發中每天都在使用它。它有着各種各樣的好處,簡單易用,得心應手... ...
我們一說到spring就會講到ioc 、aop、依賴注入,注解等專業名詞,不少剛接觸java的人,都是一頭霧水,很難直觀的去理解這些是個什么玩意,但使用的多了 就愛上了它給我們帶來的便利。
探索spring
當我們熟練的使用它之后就會好奇,ioc怎么實現的呢?為什么我只要在類的變量中加入@AutoWrited 就能使用這個變量?帶着疑惑我們就會開始翻源碼,找答案。經過一番努力,最終我們定位到了spring-context.jar包,找到了
AbstractApplicationContext對象的refresh方法,這里面的實現和步驟,就是整個spring功能的核心,里面的實現另我們嘆為觀止,但也相當之復雜,用到了很大設計模式,難以窺見全貌,很多地方的設計我們不知道為啥需要這么實現。但我們還是知道了ioc容器實際上是用的Hashmap,
依賴注入使用的是反射,aop實際上是動態代理完成的。還有很大一部分代碼看的有點暈,就是加強健壯性保證生命周期和各種特性的。不管怎么說,那都是別人的東西,我們只會用,源碼我們看了很多,但很少自己來實現出來。
spring實現分析
不管怎么說,別人的實現是別人的,自己寫出來的東西是屬於我們自己的。既然下決心要自己也能實現了,那我們就需要分析分析了。
spring怎么做到代碼侵入量少且各層級分明的呢?
spring采用約定大於配置,按照固定模式,層級分為Controller 、Service、Component、Bean、Configuration來標識類型
spring是怎么管理依賴關系的?
是通過注解或xml
spring是怎么發現哪些類需要管理的?
是注解標記+包路徑掃描
spring是如何實現依賴注入的?
通過AutoWrited注解標記加反射實例化對象
spring是如何管理Bean的?
使用HashMap容器、Set容器實現單例Bean
spring怎么實現aop切面的呢?
使用動態代理的方式,並提供了cglib和jdk默認實現兩種方式
spring是在何時加載到內存中的呢?
springMvc是通過web.xml配置入口觸發,springboot是通過springApplication初始化觸發
本次實現spring核心功能會涉及到哪些點?
1.注解的定義與使用
2.容器的初始化
3.配置文件的讀取與使用
4.sevlet的使用
5.注解的定義與使用
6.反射的運用
7.url路由與方法映射
8.參數解析與綁定
9.正則與轉義
正式開始
首先創建一個maven項目,代碼結構如下:
添加jar包依賴:
里面有2個jar包加一個插件
javax.servlet-api.jar 用來啟動核心代碼和處理請求
fastjson.jar 用來做json參數綁定
jetty-maven-plugin 使用jetty作為web容器啟動
完整maven代碼如下:

<?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.honstat</groupId> <artifactId>test-spring</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.56</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.4.5.v20170502</version> <configuration> <scanIntervalSeconds>10</scanIntervalSeconds> <webApp> <contextPath>/</contextPath> </webApp> <httpConnector> <port>8080</port> </httpConnector> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
創建前端控制器類
前端控制器專門處理servlet請求,匹配到對應的方法執行后返回,前端控制器是什么可以參考我的另一篇博客《SpringMvc請求處理流程與源碼探秘》
這里我們創建一個叫CJDispatcherServlet的類,它繼承HttpServlet類,並且重寫HttpServlet的init(),doGet(),doPost() 這3個方法,圖中的HomeService和StudentService可以先忽略不寫
配置web.xml
需要配置<servlet> 和<servlet-mapping> 2個標簽
<servlet>中需要
1.指定servlet名稱
2.指定處理請求的前端控制器類
3.設置初始化配置文件路徑
完整web.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>cjservletMVC</servlet-name> <servlet-class>com.honstat.spring.service.CJDispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>spring/application.properties</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>cjservletMVC</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
添加注解
我們知道,spring里面是通過給類加注解來識別各種使用場景的,那我們就來實現幾個必用的
作用在類上的:
JCController
JCService
JCComponent
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface JCController { String value() default ""; }
全部采用這種類型
作用在方法上和類上的:
JCRequestMapping
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.METHOD}) public @interface JCRequestMapping { String value() default ""; }
作用在字段上的:
JCAutoWrited
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface JCAutoWrited { String value() default ""; }
到此我們已經初步的創建完了需要准備的類,准備工作告一段落。
由於篇幅有限,下一篇開始實現核心功能了!