造个轮子,我学到了什么

栏目: 编程工具 · 发布时间: 6年前

内容简介:听说的最多的是不是“不要重复的造轮子”?不要被这句话蒙骗了,这句话应该还没说完整,在什么情况下不要造轮子?实际项目中由于工期和质量原因,肯定不希望你造轮子,你造轮子花费时间且质量不如现有的轮子。

阅读原文:造个轮子,我学到了什么

听说的最多的是不是“不要重复的造轮子”?不要被这句话蒙骗了,这句话应该还没说完整,在什么情况下不要造轮子?

实际项目中由于工期和质量原因,肯定不希望你造轮子,你造轮子花费时间且质量不如现有的轮子。

但是!不造轮子怎么去装X!不造轮子怎么去了解其中原理!不造轮子怎么成长!

那在造参数校验器轮子的过程中我学到了什么呢?

  • 注解的定义与使用
  • 反射的应用
  • Spring AOP的使用
  • 异常的抛出与处理

造之前的规划

雄心勃勃的规划,开干!我一定比hibernate validator做的好!

我要支持:

  • 属性验证
  • 方法参数验证
  • 方法验证
  • 方法内主动验证

注解

你初见注解时,是不是有种疑惑?为什么在某个类或方法属性上添加一个注解,它就能拥有某种功能呢?

那么我将为你慢慢解开这个迷惑。

注解就相当于一个标签,它本身并没有任何功能性,只是打个标签说明一下这是什么。那它怎么实现的某些功能呢?这就要说说反射了,只有注解和反射双剑合璧,才能发挥它的功效。我们先说注解,后说反射。

如何定义一个注解

格式

自定义注解的格式为:

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... 忘不吝指教!

发现这个面试视频不错,分享给大家,公众号回复: 面试视频

更多精彩技术文章尽在微信公众号:码上实战

造个轮子,我学到了什么


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

RESTful Web Services Cookbook

RESTful Web Services Cookbook

Subbu Allamaraju / Yahoo Press / 2010-3-11 / USD 39.99

While the REST design philosophy has captured the imagination of web and enterprise developers alike, using this approach to develop real web services is no picnic. This cookbook includes more than 10......一起来看看 《RESTful Web Services Cookbook》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具