粉丝1.4万获赞15.7万

注解本身只是一个标记,如果不去处理它,它就没有任何价值。在 spring 中,要让自定义注解火起来,通常有三种主 流的一个打法, a o p 的 切面并 post processor 后置处理以及 component scan 扫描。今天我们就来盘点这三种方案,看看它们分别适用于什么 场景。如果你还在盲目刷题,不知道面试到底考什么,我已经把简历优化模板发古文,高频提库,面试全流程硬的策略,突击学习路线图 全都打包整理好了,覆盖从投递到谈心的每个环节,需要的评论区扣六六六直接领走。第一种也是最常用的,就是结合 a o p。 适合场景是需要在方法执行前后加逻辑,比如日制限流,权限交易等等。实现方式是定义注解,比如一个 log 注解实现千面 aspect, 使用 around 拦截所有标志了该注解的一个方法。这种方式的个优点是代码侵入性,小业务逻辑和增强逻辑完全分离。第二种,利用并初步的时候修改并的一个属, 或者对病进行一些包装。实现方式是实现病 post processor 接口在 post processor before initialization 或者 post processor after initialization 方法中反射扫描病的所有的一个字段或者方法。如果发现了你 的一个自定义注解,就执行相应的一个逻辑。填写的案例是 spring 的 auto world 的 注解就是通过 auto world, annotation and post processor 实现的 value, 它也是同理。如果你想实现类似注入自定义配置的一个功能,这是最佳的选择。第三种比较硬核,直接扫描 class pass。 使用场景是你的注解不是夹在病上的,而是夹在接口或者一些非 spring 管理的一些类上。比如 mybatis 的 一个 map, 实现方式是使用 classpath scanning database provider 配合 type field 手动扫描指定包下的所有类,找到标记了注解的一个类定义,然后动态注册到 spring 容器中。这通常用于开发中间件或者框架集成,比如自动扫描某个包 高下的一个 r p c 接口,并生成代理的一个对象。最后总结下,如果是运行时增强首选 a o p, 如果是出场配置,那么就首选并 post processor。 如果是动态注册并首选 class pass 扫描。掌握了这三种方法,你就能随心所欲地去制定这个 spring, 不 再局限于只会用官方提供的一个注解了。

为什么你回答完询问事物失效场景的奥题之后,面试官直接让你出门左转了?因为你回答的不全,一共有九大场景了,想想你才说了几个。接下来花一分钟把 transactional 注解这九大失效场景一起跟你讲清楚。第一种是最弱智的, microsoft 的 主流引擎用的不是阴谋 d b, 而是根本不支持事物的 mysim, 就算 split 事务配置对了也没用。第二个在内内部方法调用,因为 tryna 注解是基于 split aop 创建的代理对象实现的,类内部调用是通过 diss 点方法名调用的, diss 是 当前类的真实对象,根本没有经过 split 的 代理对象, aop 无法拦截,该调用事务肯定不生效。第三个事务方法用的不是 public, 在 split aop 的 底层源码中明确对方法修饰符做了校验,只对 public 修饰的方法生成事务代理切面。如果用的是 private protected default 修饰 split 会直接跳过事务处理。 第四个事务方法加了 stata 和 final stata 这个方法属于类,而不是实体对象。 final 方法无法被 aop 创建的代理对象子类化覆盖,代理对象无法对这两者进行拦截,事务肯定不生效。第五个, 捕获异常不抛出。在方法内部通过 chik 捕捉异常后并未抛出,而是随手打印了一条日记,子润感知不到该异常存在,事务也就无法进行回滚。 第六个异常类型不匹配 transactional 注解,只对 run time exception 和 io 触发回滚。对 java 中的受检异常 check exception, 比如像 io exception、 circle exception 部分是不生效的,如果业务代码抛出的这类受检异常事务也不会回滚。 第七个,多线上调用事务方法。由于 spin 的 事务上下文开启提交回滚是绑定在当前线上的,子线上无法进行主线头的事务上下文,所以事务不会生效。第八个, spin 的 事务传播机制配置错误,传播机制默认值是 required 的, 有事务就加入,没有就新建。如果设置为 request new, 每次都新起一个事务的话,可能会出现外层事务回滚了,内层事务提交了,引发业务数据不一致的情况。除此之外,也不能设置为 lot 的, 就是不支持事务。 最后一种手动溜出来的对象,没有词汇容器管理的,也会出现失误失效的情况。词汇失误失效的九大场景绝对是史上最全了!关注我,拿下更多面试题,咱们下期见!

提到 spring 事务,大家都会想到 transactional, 但面试官如果问你,除了这个注解你还知道什么?或者这个注解在什么情况下会失效?很多人就蒙了。今天我们不仅要会用,还要懂原理,还要知道怎么避坑。 如果你还在盲目刷题,不知道面试到底考什么,我已经把简历优化模板,把古文高频提库,面试全流程印的策略途径、学习路线图全都打包整理好了,覆盖从头递到谈心的每个环节,需要的评论区扣六六六直接领走。 spring 事务管理主要有两种方式,颠覆式事务,迭层式事务。它是使用 transaction template 的, 需要手动在代码里面写一个 zek 的 方法,虽然灵活,但代码侵入性太强,现在用的很少,除非你的一个事务逻辑极其复杂。申明式事务呢?它是使用 cmd 上的一个注解,这是目前的一个主流, 你只需要在方法或者内存加上这个注解, spring 就 会自动利用 aop, 在 方法执行前开启事务执行后提交或者回滚代码,干净利落。 cmd 的 一个注解,它里面有几个关键参数必须掌握。 transfer, 它是最重要的,它决定了事务方法互相 调用时,事务如何传递。默认是 required isolation, 它决定了事务之间的一个数据可见性。通常跟随数据库默认的一个配置 robert forr 呢?它默认情况下, spring 只有遇到 runtime exception, 它才会回过。 如果你想让 checkpoint exception 也回过,那必须显示配置 robert for exception 点 class。 你 始终经常问你遇到过失误注解失效的情况吗?这里列出三个最常见的一个场景,第一,方法内部调用。你在同一个类的一个普通方法里面调 调用了另一个带 transactional 注解的一个方法,这时候事务是不生效的,因为绕过了 a o p 的 一个代理对象,直接调用了目标对象的方法。第二,异常被吃掉。你在代码里手动 try catch 了异常,但没有抛出来 spring, 它捕获不到异常,自然就不会回滚。 第三,非 public 方法。 transactional 只能加在 public 方法上,如果你加在 private 或者 protect 的 方法上 spring 它会直接忽略。最后总结下, spring 事务虽然好用,但 它是建立在 a o p 代代理机制至上的,使用时一定要注意代理对象的一个存在,并且配置好回拱的一个规则。只要避开这几个坑,它就是你处理数据一致性最得力的一个助手。

在日常开发过程中,对于读多写少的数据,并且数据读取比较频繁,我们一般会采用缓存技术, 会将数据放到 redis 中,直接查询 redis, 不需要再查询数据库,一般的做法是在新建修改删除数据,同时保存到 redis 中一份,保证 redis 和数据库一致。 但是这种方法呢,对代码入侵比较严重,那么有没有什么更好的办法呢?这边有两个方案,第一呢,可以通过 cdc 框架进行数据库和 redis 的同步,比如之前视频中说的 dbsm 框架。第二种呢,可以通过四分钟中的缓存注解进行数据同步。 今天主要讨论的是斯不认中的缓存注解,看下代码视力,这是一个斯不认布的项目。首先呢,引入相关依赖,并且在启动类中通过 nabo catching 开启缓存管理。 在配置文件中呢,配置缓存类型,并且指定缓存过期时间。在需要缓存的方法中添加开始 abo 注解,这里呢就是一个字典查询的方法,让咱们来看一眼他开始 abo 的原码, 通过原码咱们可以看到可以指定缓存的名称以及缓存的 k, 这个 k 呢默认是方法参数值,咱们可以通过 el 表达式进行编写。最后呢,咱们可以看到他支持义务方法,默认是同步的文档,比较详细,可以根据自己的实际情况使用。 这里我在查询字典的方法中添加了 cashab 注解, y 六值呢就是咱们的字典 k 值,就是数据的 id。 在添加和修改方法中添加了开始铺的注解,这个注解的含义呢,就是执行方法之后同步更新缓存,这个注解常用于添加和更新。 最后在咱们的删除方法中添加了 cash evict 注解,这个注解呢主要是用在删除方法中,通过 post me 调用,看一眼效果。咱们先保存一个字典, 调用一下查询接口,这里数据已经返回了,咱们看一眼后台日志,发现后台没有色扣,日志,说明已经将数据存到 reds 中了。通过它的原码可以看到 他实现缓存的方式,也是通过 aop 切面编程,如果有兴趣的小伙伴可以看一下他的原码。最后小伙伴们还有什么更好的办法吗?评论区讨论一下。最后有需要视频中原码的小伙伴关注并回复。

注解本身只是一个标记,如果不去处理它,它就没有任何价值。在 spring 中,要让自定义注解火起来,通常有三种主流的一个打法, a o p 的 切面并 post processor 后置处理,以及 component 的 scan 扫描。今天我们就来盘点这三种方案,看看它们分别适用于什么场景。 如果你还在盲目刷题,不知道面试到底考什么,我已经把简历优化模板,把古文高频题库面试全流程印的策略图集,学习路线图全都打包整理好了,覆盖从投递到谈心的每个环节,需要的评论区扣六六六直接领走。 一种也是最常用的,就是结合 a o p。 适合场景是需要在方法执行前后交逻辑,比如日制限流,权限交易等等。实现方式是定义注解,比如一个 log 注解实现切面。 aspect 使用 around 拦截所有标记了该注解的 一个方法。这种方式的一个优点是代码侵入性、小业务逻辑和增强逻辑完全分离。第二种,利用并 post processor 适用场景是需要在并 初始化的时候修改病的一个属性或者对病进行一些包装。实现方式是实现病 post processor 接口在 post processor before in neutralization 或者 post processor after in neutralization 方法中反射扫描病的所有的一个字段或者方法。如果发现了你的一个自定义注解,就执行相应的一个逻辑。 典型的案例是 spring auto world 的 注解,就是通过 auto world 的 annotation post processor 实现的 value, 它也是同理。如, 如果你想实现类似注入自定义配置的一个功能,这是最佳的选择。第三种叫硬核直接扫描 classpath 试用产品是你的注解不是夹在并上的,而是夹在接口或者一些 face spring 管理的一些类上。比如 my betty's 的 一个 map 实现方式是使用 classpath skimming editit 甲方 provide 配合 type field 手动扫描指定包下的所有类编辑,然后动态注册到 spring 容器中。这通常用于开发中间件或者框架集成。比如, 如自动扫描某个包下的一个 r p c 接口,并生成代理的一个对象。最后总结一下,如果是运行式增强,首选 a o p, 如果是初使化配置,那么就首选并控制处理器。如果是动态注册并首选 caspass 扫描。掌握了这三种方法,你就能随心所欲地去制定这个 seed, 不 再局限于只会用官方提供的一个注解了。

好,那我们继续啊,下面看一下 spring 配置其他的一些注解啊,那下边要讲的这些注解呢,就是开发当中不是特别常用,但是偶尔可能会遇到一个一次半次的,是吧?那下面我们看一下,在这地方呢,主要给大家讲两个,一个叫 primary 啊,一个叫 perfume 啊,这个 primary 呢?翻译成中文叫什么呀?叫主要的啊,它主要的作用是提高并的优先级。 ok, 那下边给大家演示吧,你看啊, 呃,它这个还说这个,它使用在哪? primary, 它使用在产生病的地方,你比如说我们那个,那个,那个 component, 它就标注在我们这个内上,是吧?哎, ok, 它可以跟 primary 一起使用, 你看啊,比如说现在 ppt 这代码啊,我们这一代码是不是也是产生 u z d o n p l 的,是吧?下面这一代码是不是也是产生 u z d o 的 mpl 二档,是吧?但是它们的类型是不是都是 userdo, 对不对? ok, 那我们这 primary 标到这个位置的时候啊,如果在盖的背时,我根据 userdo 的类型去获取的话,对吧?优先,然后哪个,然后被获取到第二个,因为它标注这个 primary 呢, 所以优先级更高。还有就是 at b, 因为学 at b, 然后视频呢,配置,我们这个 b 的产生,它是用这种工厂的方式,是吧?主要配置什么呀?配置非自定义的这些 b, 但是自定义的病啊,这么配也行,是吧? ok, 那它也会产生病,所以 primary 也可以跟这个 at 病然后一起使用 啊,那这样的话,我们这个,呃,产生这个并的,然后这个方法就这个方法的返回值,比如这个地方的 u z d o, 它的优先级就高于上面这个方法返回的 u z d o, 因为它标注什么呀?标注 primary 能明白吧?好,下面给大家演示啊。还说打个比方,比如说这有 user d o r 啊,是吧?我们还有个 user, 是不是这个 do 对不对?好,那现在呢?我这么干啊,我找到我的 user service use service。 好,我把这一阵,哎呦,那走一点儿,我把这个打开,打开是吧?把这个打开, 那这不是注入吧,是不是 usb 要注谁?要注悠子 do 对不对?那这是根据什么注入?根据类型注入, 如果我当下容器当中有多个类型的 u z d o, 那是不是在根据名字再进行匹配一下是吧? ok, 其实说在这个过程当中,最终我在说方法当中去打印这个 u 字 d o, 打印的是谁啊?我们预测一下,这打印的是不是那个,就是那个 u 字 d o m p l, 并不是这个 u 字 d o m p l。 二, 为什么呀?因为它的名字跟我不是匹配吧? ok, 那现在我在这个二当中干这么一件事,是吧?在上面就加一个什么呀? 不是 profile primary, 加个它。这样啊,我先把它注掉是吧?咱先注掉,咱对比一下效果。那我现在在 server 当中是不注入这个 youtube 呢吧,并且受方法是不是打印这 youtube 对不对?好,在测试代码当中啊,我把这个就去掉吧,不注呢啊? vacation 点儿是吧? get 变 user service 或者 user service 是吧?那这个 user service 呢?再去调售方法,我看打印到底是谁?根据我们的预测是不是 user d o m p l 对不对?就是 那个一嘛,没有二对不对?好,那现在我再把这个 user d o n p r 二这个 primary 打开,它的优先一一下是不是提上去了吧?好,再去执行这样的答案,它是谁? 是变成二的吧?因为它优先被注入,能明白吧?哎,就是我关于我们这个 primary, 再看第二个 perfume, 对吧?这个 perfume 呢?其实我们之前讲过,还记得吧?并标签,并啊,不是并并词标签,我给大家是不是讲过,就是这个 perfume, 它主要作用干什么呀?用于进行换界,就是切换镜的 啊,就开发时可能有测试环境,有开发环境,是吧?有一些病呢?他可能只存在于我们的测试环境,并不存在开发环境啊,或不存在最终的我们的上线环境。所以我可以通过这个 profile, 然后进行标注,那在这个地方他这个注解 啊,注解这个 per profile 标注在哪?同样标注在产生并的位置,比如说内上,或是那些用 at 并,然后修饰那些方法上, 明白吧?就是那个工厂方法上,是吧?那标注的然后这个这个病呢?他就标定了从属于哪个环境,只有激活当天环境,这个病才能被注册到 spa 容器当中, 能明白吧?如果你什么,比如有些币什么都不指定,我不指定环境,那意味着他在哪个环境下干什么都能被注册到死命容器当中,就是他是个共用的,是这意思吧?你比如说啊,下边这有代码看着啊,哎,比如这这个代码,这个代码标注的是 profile, 是 test, 那只有太子的环境被激活的情况下,这个 user d e o 是不是才能注到 s 杯容器当中能明白。而下 下边这个 u 字丢二呢?它不管在什么环境下都能被注册到死命环境当中啊,就都能被注册到死命容器当中,因为它并没有标注它从属于哪个环境,那它就是一个公共的环境, 这,这能明白吧? ok。 那怎么去支激活我这个环境的?我们之前是不是也学过吧?是吧,通过,然后这种然后行动参数 的方式,就命令参数的方式,或者说你自己去写一个环境,就是 settlem 点 system 啊, set up, set property, 去通过代码去设置一个环境面料也是可以的啊,我们就在这图上写一个啊。 嗯,我这样吧,我跟这一致吧,要不大家一会拧吧。那就啊,我在这啊,把这个 primary, 把这个注掉,注掉啊,然后呢?我在这个 user d o, m, p, l 这个位置 都住掉吧,这都住掉啊,我在这加个什么东西?艾特我加一个叫 perfume 行不行?指定当前这个环境是个 test 环境。 好,那大家告诉我啊,那现在我测试代码在不指定任何环境的情况下啊,在不任指定任何激活环境情况下,这个 use 的 d o 能不能被注册到 speed 容器当中? 就现在我测试代码没有指定任何环境,这代码还这么去跑,我这个 u z d o 能不能被注入到 smart 环境当中? 我这个 user deal 二能不能被注册到 spring 容器当中啊?现在问题啊,就是说我这代码现在还这么跑, 靠端代码还这么跑,没有指定任何什么呀?环境没有激活任何环境,那现在我的 userdo 跟 userdo 二能不能都被注册到 spring 的容器当中,这问题听明白了吧? ok, 我先问啊, user d o 能不能被出色到 spa 中心当中,能不能?不能?为什么?因为它只有在哪个环境下可以用,只有在太子环境下可以用,明白吧?而 use d o 二 能不能被注入到 sp 容器当中?可以,因为他并没有标注任何环境,那代表他是个公共环境,是不是不管在哪个环境下他都能去,可以去使用, 何况你现在没有指定环境,他更可以去使用的,明白不?好,那现在我们测试啊,现在呢?我在这把它注掉, application 第二 get 变,我现在去获取 user d a o 是不是?那这执行是不肯定报错啊,是不?找不到对应的名字对不对?哎,报错 no name 的是不? u z d o 八好,把它关掉,我现在找 u z d o 二 是不是改成二的吗?我在执行,这是不是能找到?因为它是个公共环境的架子,是吧?哎,二是不是有,这没问题,是吧?好,那现在我干一件事。干什么事呢?看着啊, 就指定一个激活一个环境嘛。 system 加 set property, 我还用这种方式啊,然后这个叫是叫 sporting profuse 吧,然后点 active, 对吧?你指定那个激活的环境 test。 好,那么大家,现在我在获取 user d o 能不能获取到?可以了吧,因为现在 user d o 是不是就属于 test 环境的?好,现在我执行。 哎,是不能获取到吧?好,那先问大家,我现在获取 u 的调二能不能获取到?能不能, 是不是也可以,你看为什么它也可以?因为孩子说他没有标注任何环境,那没有标注任何环境的病就是在任何环境下是不是都能使用? ok 吧?哎,这是关于我们第二个这个 profil 啊,这个 profil 呢?后期你在 spring 做项目的时候可能还会要用到一些啊。行吧,这是两个给大家补充的扩展的啊,其他的一些 spring 的注解。

家人们很多人可能不太清楚 at post construct 的 注解到底有啥用,甚至会把它和普通的方法调用混为一谈。其实啊,这个注解在 java 的 开发里有着非常重要且独特的作用,咱们先来说说它具体是干啥的。 at post construct 的 注解是用来标注一个方法的, 当一个 bin 可以 简单理解成 java 里的一个对象被 spring 容器创建并且完成依赖注入之后,被 at post 的 construct 注解标注的这个方法就会自动执行。我给大家打个比方,这就好比建房子, 依赖注入的过程就像是把各种建筑材料都运到了工地,并且搭建好了房子的框架,就像是房子框架搭建好之后马上要做的一些基础装修工作,比如给墙面刷上底漆, 这是入驻前必不可少的一步。在实际开发场景中,我们常常会有这样的需求,在对象创建并完成依赖注入之后,要进行一些初步的操作。举个例子,假如我们开发一个电商系统,有一个商品服务类,这个类依赖了商品数据库的连接信息。 当 spring 容器创建这个商品服务类的对象,并且把数据库连接信息注入进去之后,我们就可以用 at post 的 construct 的 注解标注一个方法,在这个方法里去出使化一些商品数据的缓存, 这样后续使用商品数据的时候就能更高效。使用。 at post construct 的 注解有很多好处,它能让代码的逻辑更加清晰,我们不用在其他地方手动去调用出使化方法, spring 容器会自动帮我们处理,减少了出错的可能性。朋友们,现在大家明白 atpos 的 construct 的 注解的作用了吧?那你们在开发中有没有遇到过需要使用这个注解的场景呢?欢迎在评论区留言分享。

提到 spring 事务,大家都会想到存在是 no, 但面试官如果问你,除了这个注解你还知道什么?或者这个注解在什么情况下会失效?很多人就蒙了。今天我们不仅要会用,还要懂原理,还要知道怎么避坑。如果你还在盲目刷题,不知道面试到底考什么,我已经把简历优化模板,八股文高频提库,面试全流程硬的策略突击学习路线图 全都打包整理好了,覆盖从头递到谈心的每个环节,需要的评论区扣六六六直接领走。 spring 事务管理主要有两种方式,编程式事务和声明式事务。编程式事务,它是使用 transition template 的, 你需要手动在代码里面写 excel 的 方法,所以 灵活。但代码侵入性太强,现在用的很少,除非你的一个事物逻辑极其复杂。申明式事物呢?它是使用 chainson 的 一个注解,这是目前的一个主流,你只需要在方法或者内上加上这个注解, spring 就 会自动利用 a o p 在 方法执行前开启,事务执行后提交或者回滚代码,干净利落。 chainson 的 一个注解,它里面有几个关键参数,必须掌。 progression, 它是最重要的,它决定了事物方法互相调用时,事物如何传递。默认是 required isolation, 它决定了事物之间的一个数据可见性。通常跟随数据库默认的一个配置 rowback four 呢?它默认情况下, spring 只有遇到 run time exception, 它才会回滚。如果你想让 check exception 也回滚呢?必须显示配置 rowback four exception 点 plus。 面试中经常问你遇到过失误注解失效的情况吗?这里列出三个最常见的一个场景,第一,方法内部调用。你在同一个类的一个普通方法里面调用了另一个代,却在试图注解的一个方法,这时候失误是不生效的,因为绕过了 a o p 的 一个代理对象,直接调用了目标对象的方法。第二,异常被吃掉。你在代码里说 抖动 try catch 的 异常,但没有抛出来 spring 它捕获不到异常,自然就不会回滚。第三,非 public 方法。 transactional 只能加在 public 方法上,如果你加在 private 或者 protect 的 方法上 spring 它会直接忽略。最后总结下, spring 事物虽然好用,但它是建立在 a o p 代理 机制之上的,使用时一定要注意代理对象的一个存在,并且配置好回滚的一个规则。只要避开这几个坑,它就是你处理数据一致性最得力的一个规则。只要避开这几个坑,它就是你处理数据一致性最得力的一个助手。

ok 啊,我们来看我们的第二题啊, spring boot 的 核心注解有哪些?当然啊,我知道这个题目呢,可能会引起一些争议,什么争议呢?所以我把题目稍微改了一下,叫做 spring boot 源码的核心注解有哪些? 因为其实 spring boot 的 核心注解啊,它有很多,像什么 rest control 啊,然后像什么 spring boot application 呢?然后甚至说你像 altwoord, 甚至像 compile, 类似于这种注解都算是核心注解。 但是呢, spring boot 它的原码的核心注解呢,却只有这四个啊,却只有这四个,所以呢,在这里呢,我们强调是 spring boot 和原码的核心注解,它有哪些?那么首先我们来看啊,就是我们的第一个啊,第一个注解就是我们的 spring boot application, 大家可以看啊,在我们的 spring boot 当中,这是一个空的这样的一个 spring boot 工程啊,这个空的 spring boot 工程呢,其实里面没有任何的东西啊,这种文件夹下面也没有任何的东西, 只有一个启动器,而启动器当中呢,我们有一个闷方法,闷方法当中有一个让方法,而注解呢,其实在我们眼中能看到的就只有一个,叫做 spring boot application 这样的一个注解,而这个注解是用来干嘛的呢?它是我们的一个 spring boot 的 一个应用 启动的核心注解啊,它是我们 spring boot 启动的核心注解,并且它还是一个 组合注解啊,它是一个组合注解,组合了哪些呢?各位同学,我们来看一下啊,我们来看一下。 ok, 我 们打开我们的 spring boot 工程,点击进去,大家会发现啊,它组合了上述这些注解啊,这些注解,我们把它括笔下来, 括笔下来了之后呢,这个是一些属性排除信息,我们把它去掉,大家会发现啊,前面四个呢,其实是我们的原注解啊, 圆柱形,这个圆柱形呢,不作为我们主要讲解的一些内容,但是呢,还是简单的跟大家去提一下,这四个圆柱形到底是干啥的啊?到底是干啥的?那么第一个柱形呢,表示这个柱形,表示这个柱形。 讲一遍啊,因为后面我们还会不断的去看到这个柱形,表示这个柱形用到什么地方。 ok, 然后呢,它可能的值 在这个每一举类啊,这个每一举类之间。 ok, 我 们简单地去看一下啊,看一下有哪些值啊? 比如说我们可以去看一下啊,它有 tape, 有 field, 有 message 方法啊,有 param 参数,还有结构体,然后呢,还有我们的 local variable 本地参数,然后还有注解类型,然后还有包,还有一些其他的,我就不一个一个看了啊, ok, 第二个注解呢,也是我们原注解之一,表示在什么级别存储我们的一个该注解的信息, ok, 而可选的参数呢,也是在这个美角到值当中,这里就是运行时状态啊。第三个呢,表示这个注解啊,包含在 d o c 中,什么意思呢?也就是说这个注解 代表可以被 java 的 doc 工具抽取成文档。 这第三个,而第四个呢,这个是最常见的啊,它是允许子类干嘛呢?继承父类中的 注解, ok, 允许子类,继承父类中的注解,代表的是传递性,可继承。 ok, 这四个是圆柱解,而下面三个呢,则是我们的一个,就是说组合起来,组合成 spring boot application 的 三个注解啊, ok, 那 么这个就是我们的一个 spring boot application 注解啊。 spring boot application 注注解, 那么它的功能是什么呢?它的功能有很多啊,各位同学,因为它的功能来源于它这么多的子注解的这样子的一个功能啊,子注解的一个功能, ok, 我 们可以一个一个的去看啊,一个一个的去看,那么怎么去看呢?我们先去点击,点击到 第四个啊,就是我们的 spring boot 呃, application, 大家可以看啊,而这个注解呢,前三个又是我们的原注解啊, index 呢,其实是加速锁影注解啊,加速锁影注解,它是为了提前的去扫描,我们要去扫描很多的这种要加入 i o c 容器当中的一些,就是说呃类,所以呢,此时我们会提前去扫描一些啊,这是 index, 它的一个作用。而 config 呢, config 是 被当前注解,会被标名为配置类啊,标名为配置类,可注册币,所以其实它是一个封装过后的 spring boot configuration 的 这样子的一个注解啊, spring boot configuration 的 这样子的一个注解,而这个注解呢,这个注解呢,其实就很简单啊,被 configuration 注解所修饰过的类啊,被 configuration 所修饰过的类,实际上就是我们的 java 配置类啊,被 configuration 注解所修饰的 类,实际上就是 java 的 配置类啊。 ok, 这是我们的一个,就是说 spring boot configuration 它的核心的一个作用啊, 然后再往下看啊,有一个 enable auto configuration 的 注解啊, enable auto configuration 注解,我把它单独的列出来了,我们这个注解呢,先把它往后放啊,把它往后放,我们先去看我们下面这个注解, complement scanner 啊, complement scanner, 而 complement scanner 这个注解它是用来干嘛的呢?各位同学,这个是用来指定我们的扫描路径的啊,指定我们扫描路径的,而它默认的扫描范围 是什么?扫默认的扫描范围,或者默认的扫描路径是当前的 java 类 以及其所在路径的子类啊,或者叫子路径啊,子路径都是被扫描的范围,都是被扫描的范围。嗯, ok, 那 么它注解里面的信息,刚才我们看到一些注解信息,实际上都是一些属性信息或者排除信息啊,那么我们回过头来再来看第二个注解,叫做 enable auto configuration 这样的一个注解, 这个注解是用来干嘛的呢?各位同学啊,因为有可能我们没有学过这个注解啊,但是呢,我们可能学过一些 enable 开头的这样的一些注解啊, enable, 比如说像 catch, 对 吧?开启缓存, 其实它本质上是用来开启某一些功能的注解,因为 enable 它的意思就是开启某些功能,那么我们如果把它翻译成就是说中文呢?就是开启 auto 是 什么意思啊?自动的啊,开启自动的 configuration 配置,开启自动的配置,实际上呢,呃,我们去翻译过来的时候呢,我们的音译还会稍微的那个一点啊,所以实际上这个注解呢,它的名字叫什么呢?叫做开启自动装配的注解。 ok, 这是一个开启自动装配的这样的一个注解,而实际上这也是我们的一个 spring boot 非常重要的一个面试点之一啊, 非常重要的面试点之一,为什么说它会非常的重要呢?其实我们可以点进去看一下,看一下它是被哪些注解所组合的, ok, 我 们来看一下,因为看注解最关键的一点就是,你看这个注解被哪些注解所组合。 ok, 我 们来看一下,这里呢,我们又可以发现啊,首先前面四个不用看,为什么呢?因为前面四个就是原注解,对吧?然后呢,这里有一个 auto configuration package, 有 一个 import 注解,那么这个 auto configuration package 是 干嘛的呢?我们可以再去看一下啊,再去看一下, ok, 点击进去,我们发现这个注解又被这几个注解所修饰, ok, 写在这里啊,那么这上面四个注解呢?也是圆柱解,是不是此时摆在我们面前的只有一个问题,什么问题呢?就是这个 input 的 注解干嘛的?甚至说我还用了两次,对吧?所以这个时候呢,各位同学啊, 各位同学,首先我们明白了, n a 部 auto configuration 注解,它是开启自动装备的注解,而现在距离我们理解注解只有一步了,什么呢?就是这个音破的注解,它到底是干嘛的?到底是干嘛的? ok, 那 么我们继续往下去聊啊,这个音破的注解它到底是干嘛的呢?嗯, 其实我们可以给大家去演示一个 demo 啊,这个 demo 是 怎样的呢?给大家来看一下。首先呢,我打开了一个 idea 的 一个工程啊,大家来看,这是基于 java 配置类的一个形式,在配置类当中呢,我们可以使用 configuration 这个注解被这个注解所修饰的呢,就是当前的一个, 就是说配置类啊,其实就等同于我们的配置文件啊,然后我通过在我们的方法当中去加上一个这样并的注解,就可以显示的将方法的返回的一个对象去添加到我们的 ioc 容器当中去,而我在这里呢做了一个输出,我们来看一下是不是添加进去了啊? ok, 我 们绕一下, ok, 大家可以看到啊,这里 person 跟 user 都已经被显示的去添加进我们的 ioc 容器当中去了 啊。 ok, 那 么此时我们的 input 注解它到底是干嘛的呢?嗯, input 注解到底是干嘛呢?其实它就是去干嘛? 对于我们的这样子的一个就是说导入方式做了一个封装,什么意思呢?比如说我们将这里的一个两个被病注解所修饰的这样的一个方法,把它注视掉,注视掉了之后我们再运行一下,其实它就会报错,知道吧? ok, 是 不是报错了就已经找不到了?而此时我们可以通过我们的 import 注解去进行一个添加,比如说添加我们的 person 点 class, 然后我们还可以去添加我们的 user 点 class, 当我们添加完成之后保存,我们再去进行一个运行, ok, 是 不是它又添加进来了?实际上这个 import 注解就相当于什么呢?就相当于我们通过比如说像 new 了一个 classpath comma application context 这样的一个方式, 去将我们的一个就是说,呃,这两个对象进行一个读取了,其实它就相当于这种方式啊,相当于这种方式。而我们这里加载的配置文件呢,其实就是我们刚才就是说在这里去加载这种配置文件,我相当于是换了一种方式去将这两个对象去导入了我们的 ioc 容器当中, 这是我们的第一种方式啊,第一种方式,这种方式呢,它的名字叫做静态的导入,而静态导入的方式呢,相当于 相当于什么?相当于直接把类实体化为并, 然后呢并且注册到 ic 容器中。 ok, 这是我们的第一种方式,而这种方式呢,其实大家会发现啊,呃,虽然说很直接啊,很直接,但是呢,它也会有一些问题,什么问题呢?假设我要导入的类很多很多很多,那么这个时候呢,我的 input 后面是不是会写很很长的类, 那么这个时候呢,就不便于我们的一个管理啊,不便于我们的一个管理。那么这个时候呢,我们其实就可以采用第二种方式,那么第二种方式是什么方式呢? ok, 那 么这个时候我们去看一下。 那么呢,我们首先去来到我们的项目啊,我们去创建一个我们的 java config 这样的一个配置类啊, java config, 那么我们自然而然的要给它去加上一个注解, configuration 啊。声明,当前类为配置类, ok, 声明了当前类为配置类了之后,我们还要去创建一个类啊,什么类呢? my import select, ok, 创建这个类之后,我们要去实现一个接口,这个接口的名字呢叫做 import select, 而实现了这个接口之后呢,我们去实现它需要的一个方法啊, ok, 它需要的一个什么方法呢?叫做 select import 这样的一个方法啊? ok, 而这个方法是干嘛的呢?我们可以尝试在 java config 当中去进行导入一下,我们来看一下 导入 my input select 点 class, 导入完成了之后呢?呃,我们可以去就是说,呃,跟大家去讲一下先,如果导入的这个类实现了 input select 的 接口,那么实际上我们不会将这个类的对象去加入到容器当中,而是会把这个类 所嗯所在的 select import 方法,它的返回结果所对应的类型去加入到容器当中去。而这个时候我们看到啊,我们这个方法其实它返回的是什么呢?是这个对象对应类型的全类路径名称啊,比如说我们可以去 呃给它去加上一些效果啊,比如说我们在这里 logger 点 class ok, 呃,这里必须是群类型,点 get name, 好 嘞,然后在这里我们就可以去 new another config application context 给个返回值,然后名字稍微短一点点,然后在这里去加上 java config 点 class ok, 然后此时我们就可以去获取到,比如说 a c 点 get 兵 definition ness ok, 然后我们通过这个兵 definition ness, 然后呢去点 for each ok, 然后输出 运行 好,大家就可以发现啊,我们的 java config 就 已经进来了啊,同时我们用这样的方式,其实我们完全可以在我们的一个 my in input select 里面去加上各种各样的 if else 的 这样子的一个逻辑,知道吧?所以在这种情况下呢,它就会更加的一个灵活,明白吗? 啊?它会更加的灵活,比如说我再去加上一个啊,呃,在这里我再去加上一个,就是说,呃, catch 点 class, 点 get neck ok, 是 不是就 ok 了,对不对?同样也能看见效果,对比前面静态的方式呢?静态的方式它的好处是什么?写起来会比较简单,但是呢不够灵活,当我们的字串太多的时候,写起来也很恶心。相对而言,我们实现接口的方式会比较灵活, 我们可以在方法当中定义各种各样的逻辑,符合我们的业务要求啊。同时其实我们的 import 还不止这两种用法啊,我们 import 一 共是有三种用法啊,给大家写一下啊,我们去干嘛呢?就是说做一个再去写一个接口啊? my import select 呃, import bing definition。 呃,这里我就揭晓了, ok, my import bing definition register 啊,我们要去实现一个接口,呃, import bing definition register ok。 而这种方式跟上面的方式最本质的区别是什么呢?它最本质的区别是它会额外的去多加一个参数。大家看啊,我们就是前面这个接口呢,它只有一个参数,就是我们的注解的原数据。 而在这里呢,我们可以看到啊,不仅有注解的原数据,还会有一个 register 叫做注册器的东西,而这个注册器它是干嘛的呢? 嗯?注册器它是干嘛的呢?我们来猜想一下啊,其实这个就相当于是,呃,你去银行存钱,一个是你把钱交给银行让他帮你操作,还有一个就是什么呢?就是你把钱放进自动取款机自己去存,知道吧,所以各位同学请注意啊,而且 import 它是什么呢?就是说它不是你业务开发当中的一个接口啊,它是一般是在你写组建或者原码当中才会用到的一个接口啊,一个就相相当于银行给你一台自动取款机,你自己去存钱,一个你柜去柜台操作。 那么这个时候呢,我们可以去尝试看一下效果啊。怎么看效果呢?我们去搞一个 bing definition 啊,六、一个 root bing definition ok, 然后在里面比如说我随意的去加上一个我要导入的类啊,呃, catch 点 class, 嗯, catch 点 class ok, 然后我把这个 bin definition 去包装一下,包装一下了之后我怎么办呢?我通过这个注册器 register 去注册上去 regretry 点,比如说 regretry bin definition, 然后它这里要给一个名字 catch, 然后呢把我们的这个 root bin definition 传输进去,然后我们在 java config 当中改变一个输入 my import select d, 嗯, my import bin definition, ok, 好,是不是我们的 catch 也进来了,对吧?那么我们来总结一下啊,我们来总结一下,第一种方式呢,是静态导入,静态导入呢,相当于是什么呢?相当于我们直接就是说将类实体化了,并且 干嘛呢?把它实体化为并注册到了 i o c 容器当中去。而第二种呢,其实是相当于我们动态的一个导入,我们要去要去实现我们的一个接口是 input select 的 一个接口, 实现 input select 接口,而实现这个接口呢,它的返回是给到的,咱们的一个就是说类的返回的是类的 全路径名宿组, ok, 而第三个呢,也是动态导入啊,第三个它也是动态导入,但是呢,它是手动地去注册并啊,手动去注册并要去实现我们哪个接口呢? import bin definition register 这样的一个接口 啊,要去实现这个接口,对比第二种方式要手动注册, ok, 那 么这就是我们的一个什么 spring boot 核心源码的注解。 nice 加满面试手册二十四把字 java 学习路线,从 p 五到 p 八架构师加满面试场景题私信我或评论区留言。

spring boot 之所以能一键启动,不像以前那样写一大堆叉 ml 配置核心就是空地渗透系列注解,它是 spring 四点零引入的,作用很简单,只有满足特定条件才创建这个病。今天我们就来看看这个简单的一个机制,它是如何撑起庞大的一个自动装配生态的。如果你还在盲目刷题,不知道面试到底考什么,我已经把简历优化模板,把古文高清题库、 面试全流程印的策略铺垫、学习路线图全都打包整理好了,覆盖从投递到谈心的每个环节,需要的评论区扣六六六直接领走。 首先, coindenum 的 一个原理其实非常直观,它的原码里只定义了一个属性,这个 coindenum 是 一个接口,里面只有更 max 的 一个方法。 spring 在 解析配置类时会调用这个 max 的 一个方法,如果返回处,则要注册这个病, 如果返回 false, 则直接忽略,就这么简单。 spring 容器在加载病待分离生的一个阶段,就是通过这一道光卡来筛选这个病的。在 spring bug 中,我们很少直接用这个 coindenum 的 一个注解 是用它的一个太深注简最常用的有三个,第一个 conditional on class, 当 class pass 下存在某个类时才生效。比如你有 jessica, spring 就 会给你配这个 register。 第二, conditional on property, 当配置文件中有某个属性且值为 true 的 时候才生效。比如 serial import 三个 conditional on missing, 当容器里面没有某个病时,它才会生效。这是 spring boot 能够允许用户覆盖默认配置的 关键。在实战中,我用它解决过最棘手的问题就是多环境的一个配置,假设我们有一个消息发送服务 message service, 在 开发环境我们要把消息打印到控制台,方便调试。在生产环境,我们要把消息真正发送到 mq, 我 们可以定义两个实现类,分别加上注解,这样只需要在 application 点 properties 里面改一个配置, spring 就 会自动帮我们切换时间类,完全不需要去改代码。最后总结下, conditional 是 spring 动态装配的一个灵魂,是把硬编码变成了可配置。建议大家没事多翻翻 spring boot 的 auto configuration 的 源码,看看官方是怎么花式使用 on class on being on expression 的, 这不仅能加深理解,还能学到很多优雅的配置技巧。

在早期的 spring 开发中,最让人头疼的其实不是写业务逻辑,而是维护那些永远写不完的变关系。 那是为了注入一个简单的 service, 我 们要在 excel 里写上百行配置,一旦项目膨胀,这简直就是一场维护灾难。 今天我们就来聊聊 spring 是 如何一步步通过自动装配机制,把我们从那个配置地域中解救出来的。视频涉及的详细资料,我整理进了两百万字的 java 等三十多个技术站,与一百多个项目场景实战笔记 不同工作年限同学的简历模板,以第一份 java 加 ai 三十天面试途径给出路线,选的话直接拿去回顾。技术引进时,我们经历了两个阶段。早期是手动配置时代,本质是硬编码,需要显示的指定 a 一 类 b、 b 一 类 c。 这种方式不仅繁琐,而且极度脆弱, 令的 id 稍有变动,整个依赖链条就会断裂。为了解决这个问题, spring 引入了自动装配的核心理念,从显示配置转向了约定优于配置 从器开始,具备感知能力,它能像磁铁一样自动扫描并吸附所需的依赖项,不再需要人工介入牵线搭桥。在 x mail 时代, spring 首先尝试按名称匹配。这种机制的逻辑非常直观, 他直接提取家务类的 set 方法的名称,比如代码里写的是 set 到容器就会去查找 id 为到的病。虽然省去了 property 标签,但它埋下了一个巨大的隐患,代码重构风险。由于匹配完全依赖字,不串名称,如果你觉得变量名不合适,顺手重构了代码却忘记同步修改成表,配置 运行时的注入就会直接失败。这种强藕合显然不是最优解。既然名字不可靠, spring 随机推出了按类型匹配。这次容器不再看名字,而是看形状。只要容器中存在一个病,实现了你需要的接口,无论它叫什么都能自动注入。这在一定程度上解决了虫垢问题,让它带来了新的致命伤。 奇异性,一道容器中同时存在两个实现的同一接口的病,比如一个主库实现,一个存库实现, spring 就 会陷入选择困难症,因为无法确定该用哪一个,最终只能抛出异常,导致启动失败。 为了解决上述所有痛点, spring 官方最终确定了最佳实践标准。构造器注入。这种方式不仅仅是注入语法的改变,更是一种器位架构。它强调强制依赖,向工业总装核心部件缺失时,产品绝对不允许下线。 通过构造器注入,我们确保了病在实力化那一刻,其内部状态就是完整的。这也带来了浪安全的优势,我们彻底杜绝了对象创建成功,但一类像却是孔子的半成品状态, 从根源消灭了孔子人异常的隐患。进入注解时代, o d、 y 的 成为了事实标准。它融合了之前的经验,默认按类型匹配,失败时回退,按名称匹配。 它的使用时依然存在三种牛派的博弈。这段注入虽然写起来最快,但它破坏了类的封装性,让单元测试变得困难,属于不推荐的做法。 c 的 注入保留了加瓦,并规范适用于那些非必需的可选依赖。而构造器注入依然是不可动摇的首选, 它能保证依赖的不可变性,让代码回归存在的加码与意,即使脱离 spring 容器也能轻松进行单元测试。而当我们在高阶场景下遇到多时限内的冲突时, spring 提供了两把钥匙。第一把是后来 fire, 用于精准打击, 允许我们通过指定病的名称在多个后选中强制锁定目标。第二把是 primary, 用于设置默认,在没有特殊指定的情况下,被标记为 primary 的 病会获得最高优先级。第二者配合完美解决了自动装备中的奇异难题。 最后,梳理一下实战中的关键决策点。首先,除非维护遗留系统,否则彻底摒弃常规配置。一次在日常开发中坚定的执行构造期注入,这不仅是为了规范,更是为了代码的健壮性和可测试性。 最后,面对复杂依赖场景,灵活运用 callify 和 primary 来消除歧义。掌握这些原则,你的 spring 代码将会变得既干净又稳固。

注解本身只是一个标记,如果不去处理它,它就没有任何价值。在 spring 中,要让自定义注解火起来,通常有三种主流的一个打法, a o p 的 切面并 post processor 后置处理以及 component scan 扫描。今天我们就来盘点这三种方案,看看它们分别适用于什么 场景。如果你还在盲目刷题,不知道面试到底考什么,我已经把简历优化模板,八股文高频提库,面试全流程硬的策略,突击学习路线图全 都打包整理好了,覆盖从投递到谈心的每个环节,需要的评论区扣六六六直接领走。第一种也是最常用的,就是结合 a o p 适合场景是需要在方法执行前后加逻辑,比如日制限流,权限交易等等。实现方式是定义注解,比如一个 log 注解实现千面 aspect, 使用 around 拦截所有标志了该注解的一个方法。这种方式的一个优点是代码侵入性、小业务逻辑和增强逻辑完全分离。第二种,利用并 post processor 适用场景是需要在并出 不识话的时候修改病的一个属性,或者对病进行一些包装。实现方式是实现病 post processor 接口在 post processor before initialization 或者 post processor after initialization 方法中反射扫描病的所有的一个字段或者方法。如果发现了你 的一个自定义注解,就执行相应的一个逻辑。填写的案例是 spring 的 auto world 的 注解就是通过 auto world, annotation and post processor 实现的 value, 它也是同理。如果你想实现类似注入自定义配置的一个功能,这是最佳的选择。第三种比较硬核,直接扫描 class pass。 适用场景是,你的注解不是夹在病上的,而是夹在接口或者一些非 spring 管理的一些类上。比如 mybatis 的 一个 map, 实现方式是使用 classpath scanning candidate provider 配合 type field 手动扫描指定包下的所有的类,找到标记了注解的一个类定义,然后动态注册到 spring 容器中。这通常用于开发中间件或者框架集成,比如自动扫描某 包下的一个 r p c 接口,并生成代理的一个对象。最后总结一下,如果是运行时增强首选 a o p, 如果是出场配置,那么就首选并 post processor。 如果是动态注册并首选 class pass 扫描。掌握了这三种方法,你就能随心所欲地去制定这个 spring, 不 再局限于只会用官方提供的一个注解了。