代碼分解
java是如何解析注解的?
首先來看一下Java定義注解的源碼:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {=
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
以注解Autowired為例子,可以發現,事實上每一個注解的本質上都是一個接口,當我們在某一個類中用到這個注解的時候,就可以通過java的反射機制知道是哪個類用了這個注解也就可以拿到這個類的類名,然后就可以根據類名使用反射機制創建對象,大致的步驟如下:
- 利用反射機制獲取一個類的class對象
- 通過這個class對象可以去獲取他的每一個字段的Field
- Field類提供了方法getDeclaredAnnotations來獲取這一個字段的所有注解
關鍵問題:Java反射
JAVA中編譯的類型有兩種:
- 靜態編譯:在編譯時確定類型,綁定對象即通過
- 動態編譯:運行時確定類型,綁定對象。動態編譯最大限度地發揮了Java的靈活性,體現了多態的應用,降低類之間的耦合度
JAVA反射是java作為動態語言的關鍵。這個機制允許程序在運行時,通過Reflection APIs取得任何一個已知名稱的class的內部信息,包括其modifies(諸如public、static等),Object、實現interface,也包括fields和method的所有信息。
- Class類:代表一個類
- Field類:代表類的成員變量、類的屬性
- Method類:代表類的方法
- Constructor類:代表類的構造方法
- Array類:提供了動態創建數組、以及訪問數據元素的靜態方法
所以說一旦一個類加上了@Autowired注解,那么Spring會在程序運行時,對標記Autowired注解的類進行掃描,這里會用到反射的方法:getDeclaredAnnotations(),假設有一段代碼:
@Autowired
UserMapper userMapper;
那么,Spring就知道有一個字段UserMapper userMapper使用了注解@Autowired,那么Spring就知道了我要為這個字段來實現一個在他方法之外的一個額外的邏輯,這個額外的邏輯是什么呢?那就是這個注解本身設置的含義,就比如Autowired注解,這個注解屬於spring的容器配置的一個注解,用於自動裝配,那么Spring就知道了,我要自動裝配UserMapper userMapper,把他放進Bean里面。
main函數
@SpringBootApplication
開啟springboot配置注解 ,項目啟動入口,用來啟動spring容器 , 啟動tomcat , 其他包必須與此類在同級目錄或者子包下
什么是 MyBatis?
MyBatis 是一款優秀的持久層框架,它支持自定義 SQL、存儲過程以及高級映射。MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數和獲取結果集的工作。MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為數據庫中的記錄。
UserController.java
第一部分函數名部分:
@RestController
@RequestMapping("/user")
public class UserController {
首先來看一下前兩行的注解
- RestController注解 代表返回JSON格式的數據
- RestController注解的作用等同於 @Controller注解 + @ResponseBody
- 在一個類上加上@Controller注解,表面這個類是一個控制器類 控制器類的作用是用來處理請求
- @Controller注解過的類會被注入到Spring容器中,但這只是改類成為控制器的第一步,還需要@RequestMapping來完成進一步的操作
- @RequestMapping注解用來處理映射請求,即指明處理器可以處理哪些url請求
- @ResponseBody注解表示方法的返回值直接以指定的格式寫入Http response body中,如果要求方法的返回值是json數據格式而不是跳轉
頁面,可以直接在類上標注@RestController
從前面的描述中我們可以看到UserController類的作用是:
- 控制器處理用戶的請求並返回JSON格式的數據(RestController)
- 這個類可以處理的請求url為:
localhost:8080/user開頭的url請求
第二部分函數體部分:
@Autowired
UserMapper userMapper;
首先看一下注解@Autowired,這個注解屬於spring的容器配置的一個注解,用於自動裝配->將Spring容器中的bean自動和我們需要這個bean的類組裝在一起。
更進一步:Autowired通常存在什么位置?
A:controller下->控制器內。控制器本身十分簡單,包含了處理url請求的一些具體實現方法。但是他並沒有做太多的事,而是委托UserMapper來持久化數據。
這里出現了DAO曾(數據持久化):
為了避免持久化的邏輯分散到應用的各個組件中,最好將數據訪問的功能放到一個或多個專注於此項任務的組件中。這樣的組件通常稱為數據訪問對象(data access object,DAO)或Reposity.
為了避免應用與特定的數據訪問策略耦合到一起,編寫良好的DAO應該以接口的方式暴漏功能。
一句話總結就是: 將持久層隱藏在接口之后
這個時候就是usercontroller類里需要實現mysql語句操作數據庫,這時候DI的作用就出現了,他把實現數據持久化的bean--->usermaoper注入到usercontroller類內「usermapper添加了@mapper注解,他使用了mybatis框架來實現JDBC操作,我們只需要維護注解里的sql語句就可以了」,這樣usercontroller就不要再次聲明然后new一個usermapper類了。
問題來了,什么是spring容器?
A:在給予Spring的應用中,你的應用對象生存於Spring容器中,Spring容器負責創建對象,裝配他們。配置並管理他們的整個生命周期。
Bean是什么?
A:bean是一個由Spirng IOC容器實例化、組裝和管理的對象。
- bean是對象,一個或多個不限定;
- bean由Spring中的IOC管理
- 我們的應用程序由一個個bean構成
控制反轉(IOC)是什么?
A:IOC是一個對象定義其以來關系而不創建他們的過程 即不適用new來創建一個對象,而是交給Spring去做
關鍵問題:DI(以來注入)是什么?
A: IOC的一個重點是在系統運行中,動態的想某個對象提供它所需要的其他對象。這一點是通過DI(Dependency Injection,依賴注入)來實現的。比如對象A需要操作數據庫,以前我們總是要在A的方法中編寫代碼來獲取一個Connect對象,通過connect對象的方法來鏈接數據庫。但是當我們使用Spring之后,我們就只需要告訴Spring,A中需要一個Connection,至於這個Connection怎么構造的何時去構造,A不需要知道。在系統運行的時候,spring會在適當的時候去制造一個connection,然后像打針一樣,注入到A中,這也是依賴注入名字的由來。
關鍵問題:依賴注入如何實現?
A:Java的反射機制(reflection).他允許程序在運行的時候動態的生成對象、執行對象的方法,改變對象的屬性。Spring就是通過反射來實現注入的。
后半段代碼相似度很高,這里只介紹其中一段
@RequestMapping("/add")
String add(User user) {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
user.setCREATE_DTIME(timestamp);
user.setQTIME_BEGIN(timestamp);
user.setQTIME_END(timestamp);
user.setTASK_BEGIN(timestamp);
user.setTASK_END(timestamp);
user.setCREATOR("zyn8492");
return userMapper.add(user) == 1 ? "success" : "failed";
}
前面的描述中我們可以知道@RequestMapping的作用,所以String add(User user)方法的調用的url為:
localhost:8080/user/add
函數內部為add方法的具體實現。
User.java
@Data
public class User {
首先是lombok中的@Data注解:
這個注解的作用是JAVA代碼中不需要生成getter和setter方法,編譯的時候會自動生成getter和setter
我寫代碼的時候沒注意,寫了getter和setter方法,這里可以把User.java這個文件簡化成:
@Data
public class User {
private BigInteger TASK_ID;
private String HIVE_TABLE;
private Timestamp QTIME_BEGIN;
private Timestamp QTIME_END;
private int STATUS;
private String REASON;
private String RESULT_PATH;
private Timestamp TASK_BEGIN;
private Timestamp TASK_END;
private Timestamp CREATE_DTIME;
private String CREATOR;
}
而不需要額外的代碼,這會到之前面的UserController.java代碼段報紅(編輯器發現你沒有在User類內定義getter和setter方法),但是沒關系,程序可以正常運行。
UserMapper.java
MVC即model view controller
model曾=entity。存放我們的實體類與數據空中的屬性值基本保持一致
mapper曾=dao層。對數據庫進行持久化操作,他的方法語句是直接針對數據庫進行操作的。
UserMapper是作為一個映射文件存在的。Mapper文件中包含的元素有:
- cache – 配置給定命名空間的緩存。
- cache-ref – 從其他命名空間引用緩存配置。
- resultMap – 映射復雜的結果對象。
- sql – 可以重用的 SQL 塊,也可以被其他語句引用。
- insert – 映射插入語句
- update – 映射更新語句
- delete – 映射刪除語句
- select – 映射查詢語句
@Mapper
public interface UserMapper {
@Mapper注解一般使用在接口上,表面這是一個mapper映射文件。
@Select("SELECT * FROM learn_task_zyn8492 limit 1000")
List<User> queryAll();
@select注解,只需要在mapper映射文件中方法上加上@Select(),然后在括號內寫入需要實現的SQL語句,就可以完成方法與SQL語句的映射
