造個輪子,我學到了什麼

閱讀原文:造個輪子,我學到了什麼前端

據說的最多的是否是「不要重複的造輪子」?不要被這句話矇騙了,這句話應該還沒說完整,在什麼狀況下不要造輪子?
實際項目中因爲工期和質量緣由,確定不但願你造輪子,你造輪子花費時間且質量不如現有的輪子。java

可是!不造輪子怎麼去裝X!不造輪子怎麼去了解其中原理!不造輪子怎麼成長!git

那在造參數校驗器輪子的過程當中我學到了什麼呢?github

  • 註解的定義與使用
  • 反射的應用
  • Spring AOP的使用
  • 異常的拋出與處理

造以前的規劃

雄心勃勃的規劃,開幹!我必定比hibernate validator作的好!web

我要支持:面試

  • 屬性驗證
  • 方法參數驗證
  • 方法驗證
  • 方法內主動驗證

註解

你初見註解時,是否是有種疑惑?爲何在某個類或方法屬性上添加一個註解,它就能擁有某種功能呢?
那麼我將爲你慢慢解開這個迷惑。編程

註解就至關於一個標籤,它自己並無任何功能性,只是打個標籤說明一下這是什麼。那它怎麼實現的某些功能呢?這就要說說反射了,只有註解和反射雙劍合璧,才能發揮它的功效。咱們先說註解,後說反射。數組

如何定義一個註解

格式

自定義註解的格式爲:安全

public @interface 註解名{註解體}微信

  • @interface用來聲明一個註解,並自動繼承java.lang.annotation.Annotation接口。
  • 註解體中的相似方法定義的,咱們稱爲註解中的元素。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotNull{
    
    String value() default "";
}

註解元素

格式:權限修飾符 數據類型 元素名() default 默認值

權限修飾符:只能public和default(默認)

返回值類型:8種基本數據類型和String,Class,enum,Annotaion及他們的數組

默認值限制:編譯器對元素的默認值有些挑剔,元素的值不能爲null而且不能有不肯定的默認值(即要麼有默認值,要麼使用時提供值),因此通常咱們在定義註解時便加上默認值。

元註解

定義註解必定要使用到Java給咱們提供的四種元註解,用於註解其餘註解的。

@Target
 @Retention
 @Documented
 @Inherited

咱們重點關注@Target和@Retention.

@Target

說明定義的註解所做用的範圍(能夠用於修飾什麼)。

取值(ElementType)有:

意義
CONSTRUCTOR 構造器聲明
FIELD 屬性聲明(包括enum實例)
LOCAL_VARIABLE 局部變量聲明
METHOD 方法聲明
PACKAGE 包聲明
PARAMETER 參數聲明
TYPE 用於描述類、接口(包括註解類型) 或enum聲明
@Retention

表示須要在什麼級別保存該註釋信息,用於描述註解的生命週期(被描述的註解在什麼範圍內有效)

取值(RetentionPoicy)有:

意義
SOURCE 在源文件中有效(即源文件保留)
CLASS 在class文件中有效(即class保留)
RUNTIME 在運行時有效(即運行時保留)

自定義的註解

參數校驗定義的經常使用註解:

註解 意義
NotNull 參數不能爲空
On 數值的範圍
OnMax 最大值不能超過
OnMin 最小值不能低於
Email 郵箱格式

反射

反射中牽涉的類有Class,Method,Parameter,Annotation,Field

獲取方式
Class Class.forName("");
clazz.getClass();
Type.class;
Method clazz.getMethods();
Parameter method.getParameters();
constructor.getParameters();
Annotation clazz.getAnnotations();
method.getAnnotations();
field.getAnnotations()
Field clazz.getFields();

用好反射的關鍵在於瞭解反射的API,以後我會單獨一篇講下咱們經常使用的反射API。

Spring AOP的使用

我將藉助Spring AOP來實現找到這些註解的功能。我這裏只講講淺顯一點的,由於不少人對於Spring AOP的使用還不瞭解。這個輪子是基於Spring Boot構建,因此我只講聲明式編程,就是註解實現的。

使用比較簡單,只需三步走:

  1. 定義切面類
  2. 指定切入點
  3. 定義通知類型
@Component //聲明這是一個組件
@Aspect    //聲明這是一個切面
public class ServiceAspect {

    //定義切入點,沒有方法體
    @Pointcut("@annotation(定義的註解)")
    public void pointcut(){    }
    
    /*
     * 前置通知,使用pointcut()上註冊的切入點
     *  
     * @param joinPoint 接受JoinPoint切入點對象,能夠沒有該參數
     */
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
    }
    
    //後置通知
    @After("pointcut()")
    public void after(JoinPoint joinPoint){
    }
    
    //環繞通知
    @Around("pointcut()")
    public void around(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //反射就此打開序幕
    }
    
    //後置返回通知
    @AfterReturning("pointcut()")
    public void afterReturn(JoinPoint joinPoint){
        
    }
    
    //拋出異常後通知
    @AfterThrowing(pointcut="pointcut()", throwing="ex")
    public void afterThrow(JoinPoint joinPoint, Exception ex){
    }
    
}

AOP底層原理是使用動態代理,動態代理有JDK動態代理和cglib動態代理,這裏暫不細說了。

異常

自定義異常類

public class FastValidatorException extends RuntimeException {
    public FastValidatorException(String message) {
        super(message);
    }
}

設計時有兩種失敗模式:快速失敗和安全失敗

當參數校驗,不符合要求時,快速失敗將直接拋出此異常,安全失敗將收集全部失敗返回。

如:

private void emptyResult(String fieldName) {
        if (isFailFast) {
            throw new FastValidatorException(fieldName + "不能爲空");
        } else {
            formatResult(fieldName + "不能爲空");
        }
    }
    
    private void formatResult(String msg) {
        if (!msg.isEmpty()) {
            result.getErrors().add(msg);
        }
    }

處理異常

若是使用快速失敗模式,那麼使用者將要對異常作全局統一處理。

將參數異常類信息,封裝成比較友好的信息給前端。

@RestControllerAdvice
public class ErrorHandler {

    @ExceptionHandler(FastValidatorException.class)
    public JSONResult handle(FastValidatorException ex) {
        return new JSONResult(ex.getMessage(), ex.getStatus());
    }
}

造以後的感想

仍是hibernate validator作的好!(捂臉哭) 我服!

but

造輪子能迫使我去了解更多的知識點,能迫使我去了解輪子的原理,也能加深我對知識的理解,順便還能吹吹!
作的過程當中你會思考如何優化它,一遍遍的推倒重來,會想到用怎麼來解耦?用什麼提升擴展性,靈活性?

造輪子的意義在於能讓你不斷的思考和學習。不管造的好壞,行動就好。

輪子地址:https://github.com/flyhero/fa... 忘不吝指教!

發現這個面試視頻不錯,分享給你們,公衆號回覆: 面試視頻

更多精彩技術文章盡在微信公衆號:碼上實戰

相關文章
相關標籤/搜索