资讯专栏INFORMATION COLUMN

造个轮子,我学到了什么

Acceml / 3122人阅读

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

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

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

但是!不造轮子怎么去装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构建,所以我只讲声明式编程,就是注解实现的。

使用比较简单,只需三步走:

定义切面类

指定切入点

定义通知类型

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

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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74142.html

相关文章

  • 用Vue自己造个组件轮子,以及实践背后带来的思考

    摘要:用造个组件轮子吧闰土大叔如果你掌握了的组件知识,相关的指令事件,花点时间你也可以造出这么个入门级的小轮子。接下来,抛出造轮子实践背后带来的一些思考。以上三部分内容构成了的整个执行过程。 showImg(https://segmentfault.com/img/bV1Tnu?w=754&h=500); 前言 首先,向大家说声抱歉。由于之前的井底之蛙,误认为Vue.js还远没有覆盖到二三线...

    icyfire 评论0 收藏0
  • 厌倦 Redux,那就造个轮子 Rectx:第三集

    摘要:呵呵,你没想到吧,这玩意儿竟然有第三集我靠,我自己都没想到,让我们悄悄的回顾一下前两集完全没想到,竟然会有第二集我厌倦了,那就造个轮子第二集痛点分析第一集在这里我厌倦了,那就造个轮子算了,我都懒得写了,自己看吧,当然不看也无所谓,正式开始。 仓库:215566435/rectx 前言 麻烦快去我的仓库里面喷: 老子学不动了,求不要更新。 呵呵,你没想到吧,这玩意儿竟然有第三集!我靠,我...

    adam1q84 评论0 收藏0
  • 厌倦 Redux,那就造个轮子 Rectx:第三集

    摘要:呵呵,你没想到吧,这玩意儿竟然有第三集我靠,我自己都没想到,让我们悄悄的回顾一下前两集完全没想到,竟然会有第二集我厌倦了,那就造个轮子第二集痛点分析第一集在这里我厌倦了,那就造个轮子算了,我都懒得写了,自己看吧,当然不看也无所谓,正式开始。 仓库:215566435/rectx 前言 麻烦快去我的仓库里面喷: 老子学不动了,求不要更新。 呵呵,你没想到吧,这玩意儿竟然有第三集!我靠,我...

    eternalshallow 评论0 收藏0
  • 造个轮子」——cicada 设计一个配置模块

    摘要:同时也新增了一个。将不同的配置文件用不同的对象进行管理。由于需要支持多个配置文件,所有需要定义一个抽象类供所有的配置管理实现。其实就是一个结构的缓存,用于存放所有的配置。总结这就是本次中的升级内容,包含了配置支持以及代码重构。 showImg(https://segmentfault.com/img/remote/1460000016392132?w=2048&h=1365); 前言 ...

    fsmStudy 评论0 收藏0
  • 造个轮子,基于 Laravel5.4 的下一代 PHP 开发框架 (API/SPA/Vue2/iVi

    摘要:像操作系统一样,你可以通过安装软件,成为适用于你的电脑。先进的技术方案,使得你无需担心后期功能拓展与迭代问题,大大降低了维护成本。对于一个超过三年生命周期的项目来说,最适合不过。总之,是新的技术方向标,能让每个艺术家像构建工程一样构建程序。 这是我们团队的一个非盈利项目,以Apache2.0协议开源...不限制商用 Notadd是什么 Notadd 是基于Laravel 和 Vue 的...

    Rocture 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<