目錄
Yao框架
每次看spring的源碼都是難以看進去, 但是平時都會通過各種各樣的博客文章中大致理解了spring的基本原理。 同時我也萌生了自己實現一個類似框架的想法,於是便有了這個項目。雖然是重複造輪子,但是寫這個項目的過程中我對於spring的實現也有了更深的瞭解吧。
雖然我只是無人氣的小博主, 但是我還是在我的在這裏推下我的框架,因爲夢想還是要有的,萬一這個框架哪天火了呢!
想學習spring的,又難以看進去源碼的, 可以看看我的這個項目,
歡迎star和留言。有疑問請留言, 我很樂意與你們一起探討技術問題。 這個項目我會堅持更新的,希望大家能給與我支持。
項目地址
https://github.com/blanexie/Yao
使用示例
說明除了下面示例的方式, 還可以使用FactoryBean接口和@Bean註解方法的方式將bean放入容器中
導入maven包
<!-- 依賴注入的核心包, 提供基本的依賴注入功能 -->
<dependency>
<groupId>xyz.xiezc</groupId>
<artifactId>xioc</artifactId>
<version>1.0</version>
</dependency>
<!-- 整合mybatis的包 -->
<dependency>
<groupId>xyz.xiezc</groupId>
<artifactId>xorm</artifactId>
<version>1.0</version>
</dependency>
<!-- 數據源鏈接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- 整合netty的包, 提供了基本的http能力和websocket支持 -->
<dependency>
<groupId>xyz.xiezc</groupId>
<artifactId>xweb</artifactId>
<version>1.0</version>
</dependency>
定義一個啓動類
import xyz.xiezc.ioc.Xioc;
import xyz.xiezc.ioc.annotation.Configuration;
import xyz.xiezc.ioc.starter.orm.annotation.MapperScan;
@MapperScan("xyz.xiezc.example.web")
@Configuration
public class ExampleApplication {
public static void main(String[] args) {
Xioc.run(ExampleApplication.class);
}
}
定義一個Controller放入容器中
import cn.hutool.json.JSONUtil;
import xyz.xiezc.ioc.annotation.Inject;
import xyz.xiezc.ioc.starter.orm.common.example.Example;
import xyz.xiezc.ioc.starter.web.annotation.Controller;
import xyz.xiezc.ioc.starter.web.annotation.GetMapping;
import xyz.xiezc.ioc.starter.web.entity.WebContext;
import java.util.List;
import java.util.Map;
@Controller("/")
public class TestController {
@Inject
AlbumMapper albumMapper;
@GetMapping("/test.json")
public String get(String param) {
WebContext webContext = WebContext.get();
//
Example build = Example.of(Album.class)
.andEqualTo(Album::getId,3537) //支持類似mybatis-plus的lambda的使用方式
.build();
List<Album> albums = albumMapper.selectByExample(build);
//獲取session信息
Map<String, Object> session = webContext.getSession();
session.put("param", param);
return JSONUtil.toJsonStr( albums);
}
}
定義一個實體類
import lombok.Data;
import xyz.xiezc.ioc.starter.orm.annotation.Column;
import xyz.xiezc.ioc.starter.orm.annotation.Id;
import xyz.xiezc.ioc.starter.orm.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Table("t_album")
public class Album implements Serializable {
@Id
Integer id;
@Column
String title;
@Column
String publishTime;
@Column
String type;
@Column
LocalDateTime createTime;
@Column
Integer coverId;
@Column
Integer see;
}
定義一個Mapper接口
import xyz.xiezc.ioc.starter.orm.common.BaseMapper;
public interface AlbumMapper extends BaseMapper<Album> {
}
定義一個websocket的controller
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import xyz.xiezc.ioc.starter.web.annotation.WebSockerController;
import xyz.xiezc.ioc.starter.web.netty.websocket.WebSocketFrameHandler;
@WebSockerController("/websocket")
public class WebSocketHandler implements WebSocketFrameHandler {
@Override
public WebSocketFrame handleTextWebSocketFrame(TextWebSocketFrame textWebSocketFrame) {
String text = textWebSocketFrame.text();
TextWebSocketFrame textWebSocketFrame1 = new TextWebSocketFrame("resp:" + text);
return textWebSocketFrame1;
}
@Override
public WebSocketFrame handleBinaryWebSocketFrame(BinaryWebSocketFrame binaryWebSocketFrame) {
return null;
}
}
配置文件
## 基本配置信息
# JDBC URL,根據不同的數據庫,使用相應的JDBC連接字符串
url = jdbc:mysql://127.0.0.1:8306/daily
# 用戶名,此處也可以使用 user 代替
username = root
# 密碼,此處也可以使用 pass 代替
password = 123456
# JDBC驅動名,可選(Hutool會自動識別)
driver = com.mysql.cj.jdbc.Driver
## 是否啓用ssl
xweb.server.ssl.enable = false
### web服務的端口
xweb.server.port=8443
### 靜態文件的目錄
xweb.static.path=/static
Xioc 小型的依賴注入框架,
目前支持的註解詳解
- @Component 被註解的類放入容器成爲bean,可以註解類和方法。
- @Configuration 被註解的類放入容器成爲bean, 只能註解類。
- @Inject 註解字段,是的字段從容器中注入bean。
- @Bean 方法註解, 只能配合@Configuration註解通過方法來生產bean
- @BeanScan 類註解, 只能配合@Configuration一起使用,用來標註框架掃描的包路徑
- @Init 方法註解, 被註解的方法在所在bean初始化完成後調用, 方法必須無參
- @Value 字段註解。 將配置中的內容注入到字段中, 類型轉換參照Hutool的類型轉換工具。
- @EventListener 類註解, 被註解的方類必須有無參構造方法,且實現ApplicationListener接口, 註解中必須設置處理的時間名稱。
目前支持功能列表如下
- 所有的bean都是單例模式
- 基本的掃描注入類,
- 支持方法注入bean
- 支持注入配置,配置文件使用Hutool的setting
- 支持類似springboot的starter一樣的導入包引入對應功能的方法
需要導入的starter包必須在xyz.xiezc.ioc.starter包下放上一個@Configuration註解的類。 並且可以配合@BeanScan一起使用
- 支持bean初始化後調用的init方法
- 支持基本的事件處理器
- 支持配置注入
缺陷待完善
- AOP功能需要在被切的類上面增加註解, 但是AOP的意義就在於不用修改被切類從而達到切面的目的
xweb 整合netty支持web的框架
支持的註解
- @Controller 參考SpringMvc
- @GetMapping 參考SpringMvc
- @PostMapping 參考SpringMvc
- @RequestBody 參考SpringMvc
- @WebSockerController 被註解的類必須實現WebSocketFrameHandler接口, 從而來實現websocket. 這個註解的value值就是websocket的連接的url
說明
- 默認靜態文件目錄是
classPath:static/
,在這個目錄下面的文件會作爲靜態文件。可以在配置文件中指定xweb.static.path
作爲靜態文件。 - 請求路徑只有在controller中找不到後纔會進入靜態文件目錄下查找。
- GET和POST請求只返回application/json格式的內容,不返回其他類型。這樣已經夠用了, 現在幾乎都是前後端分離的項目。
待改進
- 只支持GET和Post請求
- Post請求只默認提供支持的ContentType類型只有 “application/json” ,“multipart/form-data” ,
"application/x-www-form-urlencoded"和從url中獲取參數的Default幾種類型,但是提供了擴展接口。
只要實現HttpMessageConverter接口,並將實現類放入容器中,就可以了。
配置文件
## 是否啓用ssl
xweb.server.ssl.enable = false
### web服務的端口
xweb.server.port=8443
### 靜態文件的目錄
xweb.static.path=/static
XORM 整合mybatis方便查詢的項目
支持的註解
- @Column 標註在實體類中, 可以通過value 指定數據庫字段的名稱。
- @Id 標註在實體類中, 可以通過value 指定數據庫字段的名稱。
- @MapperScan 一定要標註在啓動類中, value指定項目中的mybatis的mapper接口的地址
- @Table 標註在實體類上, 標識這個類對應一個數據庫表
支持的配置文件的配置
- mybatis.configLocation 指定自定義的mybatis的配置文件地址
- mybatis.mapperLocations 指定自定義的mapper.xml文件的路徑
- mybatis.typeAliasesPackage 參考mybatis-spring
- mybatis.typeHandlersPackage 參考mybatis-spring
數據源的配置
本框架中數據源的使用是完全使用hutool中的數據源的方式
## 基本配置信息
# JDBC URL,根據不同的數據庫,使用相應的JDBC連接字符串
url = jdbc:mysql://127.0.0.1:8306/daily
# 用戶名,此處也可以使用 user 代替
username = root
# 密碼,此處也可以使用 pass 代替
password = 123456
# JDBC驅動名,可選(Hutool會自動識別)
driver = com.mysql.cj.jdbc.Driver
支持如下的數據源
- HikariCP
- Druid
- Tomcat
- Dbcp
- C3p0
本框架句自動識別數據源以及自動注入配置文件中的連接池配置(包括數據庫連接配置),如果引入了多種數據源的jar包。 本框架會按照上面的順序來檢測引入數據源包,檢測到則會自動構建數據源。如果沒有檢測到數據源包, 就會使用內置的簡單數據源(性能問題, 不推薦線上使用)
以druid爲例, 我們看下如何使用
- 先引入druid的包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
- 再在配置文件中增加如下
#----------------------------------------------------------------------------------------------------------------
## 基本配置信息
# JDBC URL,根據不同的數據庫,使用相應的JDBC連接字符串
url = jdbc:mysql://<host>:<port>/<database_name>
# 用戶名,此處也可以使用 user 代替
username = 用戶名
# 密碼,此處也可以使用 pass 代替
password = 密碼
# JDBC驅動名,可選(Hutool會自動識別)
driver = com.mysql.jdbc.Driver
# 是否在日誌中顯示執行的SQL
showSql = true
# 是否格式化顯示的SQL
formatSql = true
#----------------------------------------------------------------------------------------------------------------
## 連接池配置項
## ---------------------------------------------------- Druid
# 初始化時建立物理連接的個數。初始化發生在顯示調用init方法,或者第一次getConnection時
initialSize = 0
# 最大連接池數量
maxActive = 8
# 最小連接池數量
minIdle = 0
# 獲取連接時最大等待時間,單位毫秒。配置了maxWait之後, 缺省啓用公平鎖,併發效率會有所下降, 如果需要可以通過配置useUnfairLock屬性爲true使用非公平鎖。
maxWait = 0
# 是否緩存preparedStatement,也就是PSCache。 PSCache對支持遊標的數據庫性能提升巨大,比如說oracle。 在mysql5.5以下的版本中沒有PSCache功能,建議關閉掉。作者在5.5版本中使用PSCache,通過監控界面發現PSCache有緩存命中率記錄, 該應該是支持PSCache。
poolPreparedStatements = false
# 要啓用PSCache,必須配置大於0,當大於0時, poolPreparedStatements自動觸發修改爲true。 在Druid中,不會存在Oracle下PSCache佔用內存過多的問題, 可以把這個數值配置大一些,比如說100
maxOpenPreparedStatements = -1
# 用來檢測連接是否有效的sql,要求是一個查詢語句。 如果validationQuery爲null,testOnBorrow、testOnReturn、 testWhileIdle都不會其作用。
validationQuery = SELECT 1
# 申請連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能。
testOnBorrow = true
# 歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能
testOnReturn = false
# 建議配置爲true,不影響性能,並且保證安全性。 申請連接的時候檢測,如果空閒時間大於 timeBetweenEvictionRunsMillis,執行validationQuery檢測連接是否有效。
testWhileIdle = false
# 有兩個含義: 1) Destroy線程會檢測連接的間隔時間 2) testWhileIdle的判斷依據,詳細看testWhileIdle屬性的說明
timeBetweenEvictionRunsMillis = 60000
# 物理連接初始化的時候執行的sql
connectionInitSqls = SELECT 1
# 屬性類型是字符串,通過別名的方式配置擴展插件, 常用的插件有: 監控統計用的filter:stat 日誌用的filter:log4j 防禦sql注入的filter:wall
filters = stat
# 類型是List<com.alibaba.druid.filter.Filter>, 如果同時配置了filters和proxyFilters, 是組合關係,並非替換關係
proxyFilters =
- 開始你的表演, 寫你最熟悉的mapper 代碼
說明
- 目前沒有實現事務的功能, 還不支持事務。
- Mapper接口必須實現xyz.xiezc.ioc.starter.orm.common.BaseMapper接口,BaseMapper接口提供了基本的方便的查詢的方法,十分方便。
- 可以不用謝mapper.xml文件。 只有到BaseMapper接口不滿足需求的時候可以加上xml文件,
mapper.xml文件的默認路徑是classPath:mapper/ 。 也可以通過配置文件mybatis.mapperLocations來指定
本框架待改進的地方
- 不要引入mysql的jdbc鏈接包。 因爲用戶不一定是使用的mysql。
- 實現事務的管理功能, 可以參考spring的事務管理實現
參考項目
hutool 這真的是一個很好的工具包項目, 全面而有強大, 依賴少。 本框架大量依賴這個工具包
blade是和本項目類似的框架。我的整合netty中的代碼參考這個項目很多
spring
netty