spring 核心知识总结今天分享的内容是一张图带你学会静态代理。因为在 spring ioc 切面编程的底层 是使用了动态代理去作为一个实现,那我们今天分享代理模式,首先从静态代理开始去学习,学习完静态代理、动态代理之后,就能更好地去理解 brain ioc 切面编程底层, 他为什么要去使用动态代理?所以我们可以先看一下生活中的代理。一个生产厂家无需面向客户,无需提供专门的售前咨询及售后服务, 团队只需要专注自己的一个核心业,就是生产。比如说这边主板、 cpu、 内存、显卡厂家只关注生产,将原本由各个工厂完成的售前咨询、 售后服务工作都交由给代理团队完成,提高团队功能的复用性。也就是这里交给代理团队,把整个售前组装、售后服务都交给代理团队。我们只需要找代理团队,比如我需要电脑代理去帮你做, 而不会直接面向工厂。这就是代理模式设计的一个优点,将通用性的工作交给代理对象完成。 被代理对象是专注自己的核心业,今天通过一张图分享静态代理,代理累, 只能够为特定的类生产代理对象,不能代理任意类。我们可以关注一下这句话,代理类只能够为特定的类生产代理对象,也就是说静态代理他只能为他自己代理的这个类 去生产对象,而不能为其他的类去生产对象。所以静态代理他是有一定的局限性。静态代理在使用时需要定义接口,被代理对象及目标对象,与代理对象一起实现相同的接口, 或者是继承相同的负累,怎么理解呢?我们的步骤第一步是定义一个公共的借口,比如说这里我们定义了一个公共的借口, 里面有一色的电力 update 这些方法,然后目标对象实现公共接口。什么是目标对象?也就是这里我们可以看到 比如说 focal 以及 student 这个实现类,他们会去实现这个接口,其实在他们上层是还有一个接口,也就 就是 book job 以及 student job 都去实现这个接口,我们可以看到实现了一个这个公共的这个接口之后,我们在使用公共接口去调用的时候, 是不是就能够去通过副类调用此方法去进行一个实现。那什么是被代理对象的?也就是这里的 book dog 和 student dog 为被代理对象创建代理对象,也就是我们的这个代理类 会被代理的对象去创建,而我们而我们可以看一下,在这个代理类里面,他的实现是通过这个副基调, 也就是通用的这个道具创建对象,这里其实就是多态的一个实现,怎么说呢?也就是代理对象实现公共的结果,并且代理对象要聚合目标对象, 实际上就是接口的聚合多肽的特性,也就是这里他聚合的是这个超级接口,然后我们在使用的时候,如果我传一个不到给他 这里传了一个 book 照给他的话,那他创建出来的一个对象是不是负累胜于此类这个 book 照,然后通过他这个代理对象去调这个给力的方法的时候, 是不是就是调的是 book 到的定律方法,如果说我再给他传一个折腾的掉进去,那他是不是创建出来 是一个 student 招代理对象,然后通过他去调用他的一些方法?那这样是不是就是通过一个代理类,我们可以创建我们招的对象以及 student 招的对象,也就是通过代理对象 方法去调用目标对象的方法。也就是在这里传给了他之后,创建了一个代理对象,然后通过代理对象去调用目标方法的这个实现。那这里再说一下静态代理的优缺点, 比如说他的优点在不修改目标对象的功能前提下,能通过代理对象对目标进行一个扩展。 不修改目标对象的功能的前提下,能够通过代理对象对目标进行扩展,也就是我们这里 insert、 delete、 update, 我们可以在调查之前做一些方法,调查之后做一些方法,将通用的代码放到代理类中去进行实现,提高了代码的复用性。通用的代码,比如说一些 insert、 delete 等等。 update, 这些 通用的方法都放在代理类里面,都放在这个里面。将代理类中使用关注核心业务的实现,将通用的管理型逻辑,比如说事务管理、日志管理和业务逻辑进行一些分理, 比如我们这里开启事务关闭时,业务逻辑我们放在中间,那他是分离的缺点,因为代理对象需要与目标对象实现一样的结果, 所以会有很多的代理类,也就是他实现的是他的子类,为此类去做一些代理。如果说我们还有其他类型,那还要去写一个代理类, 所以说他是需要很多代理类的,一旦接口增加方法,目标对象与代理对象都要维护。一旦我这里增加了一个方法,那目标对象是不是也 要去增加方法?他要去通过这个方法去调研,是不是也得去增加方法,所以都要去维护,维护起来很麻烦,其实他不通用的一个原因。但是我们在学习代理模式的时候, 需要通过静态代理,然后再去学动态代理,然后再学 lc 底层。那今天是通过这个视频一张图给大家分享了一下 静态代理的一个过程,那我相信大家看到这个图之后,如果把这个图给记下来,一定能够去很好的去写一个静态代理, 那今天这些视频就分享到这里,接下来的视频会给大家去持续分享动态带以及 scream 底层设计模式的分享。如果觉得视频有帮助,就点个小爱心支持一下吧,你们的支持是我持续创作的动力。
粉丝3737获赞2.6万


英俊潇洒,气宇轩昂,才貌双全,没错,说的就是你,不仅如此,你还有个漂亮的女朋友,对你还特别的贴心,每次你外出前都会给你挑选一套干净帅气的衣服,在代码中就是这个样子, 看着没有什么特别的地方,接着女朋友对你更好了,在你出去之前又帮你挑选了一双干净的鞋子,那么在代码中就要加上干净鞋子的逻辑。会发现女朋友帮你挑选衣服和鞋子的逻辑和外出工作逻辑是两个独立的功能, 当加上挑选干净鞋子代码时,实际上是在外出方法里面改的,其实也就是在修改外出方法的逻辑了,这违背了开闭原则,如果以后女朋友再给你弄个帅气的发型, 那在代码中不就又得修改了吗?所以要把这两个功能分开,彼此不影响,而这就用到了代理功能,代理分为静态代理和动态代理。首先来看静态代理,在外出方法里把女朋友帮你挑选衣服和鞋子的逻辑去掉, 接着要有一个 boy purpose 类来做代理,实现 person 接口,里面有一个 person 类型的成员属性,再有个构造方法来把 person 类型对象传入进去,也就是 boy 对 象。接着就是实现 go out 的 方法, 在这里调用原有 person 类型对象的方法,而在这之上就可以加上女朋友帮你挑选衣服和鞋子的逻辑了。 接着来调用一下,创建出 boss 对 象,再创建出 boss 代理对象,把 boss 传入进去,得到代理对象后,直接调用 go out 方法。为了方便你梳理,我把所有的代码结构拿过来看一下输出结果,这样就把挑选衣服和外出给分离开了, 其实它是有致命问题的,就像功能简单的机器人一样,太死板了,不够灵活。比如说在代码中再多个方法外出工作, 那么在代理对象报 a p p 上也要多个外出工作的方法,那要是有外出吃饭,外出出差、外出打球,每个方法都要加一遍,这也太不灵活了。 不要忘了除了静态代理,还有动态代理了,所以动态代理就要登场了。动态代理有两种,分为 zdk 和 cdlive。 首先是 zdk, zdk 要求被代理的对象必须实现接口,因为 boy 已经实现了 person 接口,所以没问题方法里就只有外出相关的输出了。 接着创建一个 zdk handler 类,实现一个重要的接口 inokson handler, 就 靠它才能实现。 zdk 动态代理这里的成员属性,这是要被代理的目标对象,再弄个构造器,把目标对象传入进去。 接着就是要实现 inokson handler 中的 inok 方法了,第一个参数是调用该方法的代理时历,第二个参数是目标对象的方法参数。 方法中的 master 的 点 in work 就是 执行被代理对象中原本的方法了,在这执行之前就可以加上女朋友给你挑选衣服和鞋子的逻辑了。 到这里代理增强的执行就已经搞定了,但我们需要得到这个代理对象才能够执行。所以再来一个得到代理对象的方法, 里面调用 purpose, 点 new purpose, instance 方法参数分别是实现了 instance handler 接口对象的类加载器,也就是当前对象的类加载器,目标被代理对象的接口实现了 instance handler 接口的对象也就是当前对象, 然后写个 man 方法来调用就可以了。先把暴力对象创建出来,再创建出 zdk handler 代理对象,把暴力对象传入进去, 调用 get property 得到代理后的对象,这里要转成 person 接口类型,接着就可以执行方法了。我再把整个代码拿过来看一下调用后的结果,到这里 zdk 的 代理就结束了,你也能看出来他的缺点 就是被代理的对象必须要实现接口才可以,这不就有局限性了吗?如果原本业务不需要接口,为了代理还得特意弄一个接口出来,这有点不爽啊。所以不要忘了我们还有另一个动态代理 cdlive, 看看他是什么样子, 也是要有个被代理的对象 boy, 这里就不用有 person 接口了。接着创建一个类叫 cdlive interceptor, 同样也要实现一个重要的接口 master interceptor, 靠它实现 cdlive 动态代理。这里的成员属性就是要被代理的目标对象,再弄个构造器把目标对象传入进去。接着就是要必须实现 master interceptor 中的 intercept 方法了。 第一个参数是由 cdlive 动态生成的代理对象,第二个参数是目标对象的方法,第三个参数是目标对象的方法参数,第四个参数是生成的代理类对方法的代理。引用 方法中的 masterpurpose 点 enwork, 就是 执行被代理对象中原本的方法了,在这执行之前,可以加上女朋友给你挑选衣服和鞋子的逻辑, 到这里代理增强的执行就已经搞定了,但是我们还是需要得到这个代理对象才能够执行。所以再来一个得到代理对象的方法, 创建一个 insert 对 象,接着设置副类类型,就是要被代理的对象类型,设置拦截器,回掉对象为本身。最后调用可瑞特就可以生成代理对象了。再写个慢方法来调用,先把包类对象创建出来, 再创建出 c g lab intercept 代理对象,把报应对象传入进去,调用 get privacy, 得到代理后的对象 转换为报应类型,这时得到的就是代理对象了,就可以执行方法了。我再把整个代码拿过来,让你更好地梳理 c g lab 整个代码结构。我们看一下调用后的结果。到这里就可以来总结一波,先是静态代理, 要求每一个被代理的类都需要有一个对应的代理增强类,确定的时机是在变异时,如果要添加新的方法,只能手动再添加代理,不够灵活。 接着就是动态代理,首先是 zdk 方式,通过实现 user case and handler 接口来得到代理类,要求被代理的类必须实现接口才可以。然后是 cdlive 方式,通过实现 master intercepter 接口得到代理类,被代理的类可以没有接口, 它是通过继承类来创建出子类的方式。到这里你应该对静态代理和动态代理的理解更加深刻了。那么在下期和你详细介绍 spring 的 a o p 功能以及它是如何利用动态代理来实现的,关注阿星,和你分享更多硬核干货。

我亲眼见过一个转账接口,代码写得挺规范, at transactional 也加了,结果上线第一周, a 账户扣了钱, b 账户没收到,十万块钱就这么没了。 查了三天三夜,最后发现事务压根儿没生效,你猜问题出在哪儿?一个 try catch 把异常吞了。 这种 bug 恶心的地方在于测试环境跑得好好的,一上线就出事。今天聊聊 at transactional 失效的七种情况。你的项目里八成有。第一个方法不是 public, spring 事务靠 a o p 代理实现,代理只认 public 方法。你把注解加在 private 的 方法上, spring 看都不看一眼。 protected 的 也一样,别问我怎么知道的。第二个,同一个类理方法互相调用, 这个坑我踩过, a 方法挑 b 方法, b 方法上有 action 呢,你觉得有事务没有,因为内部调用走的是 this, 不是 代理对象, 注解等于白加。想解决的话,要么把 b 方法挪到别的类,要么注入自己用代理调,后者写出来挺丑的,一般不这么干。第三个,异常被吃掉了, 这是我见过最多的坑。 spring 默认只对 run time exception 回滚,你抛个普通 exception 他 不管。更要命的是,很多人习惯 try catch 打个日制就完事了,事务以为执行成功直接提交,开头说的那十万块钱就是这么没的。 转账逻辑里开始了异常,日制打了钱没了。解决办法要么别吞异常,要么 catch 里手动调 setback 内括号, 要么注解上加 rowback four 等于 exception class。 第四个,传播机制搞错了, at transactional 有 个 propagation 参数,默认 required, 有 事务就加入,没有就新建,这个没毛病,但有人改成 requires new, 以为新事物更安全, 结果外层回滚了,内层早提交了,数据就不一致了,还有人又 not supported, 直接不要事务。你确定知道自己在干啥?不懂传播机制就别动,这个参数默认的够用。第五个,数据库引擎不支持现在少见了,但老项目可能有 myiscam, 不 支持事务,你注解加的再对也白搭。迁移老项目的时候检查一下表引擎,别被坑了。第六个,多数据源没指定事务管理器, 项目里配了多个数据源。 at transactional 默认只管主库,你操作从库事务是不管的。微服务架构里这个问题特别常见,要在注解里指定 transaction manager。 第七个类没被 spring 管理,没加 at service or at component, 或者自己扭出来的对象。 spring 不 认识他, 哪来的代理哪来的事务?还有就是 final 类和 final 方法, c g l i b 代理不了,自己对照检查一下,方法是 public 的 吗? 有没有内部调用异常吞了没?传播机制改了没?表引擎对不对?多数据源指定了没类,被 spring 管着没七条过一遍能排除大部分事物问题。面试被问到这个怎么答? 先说七种情况,然后重点说内部调用和异常被吞,因为这俩最常见,而且不报错,出了事才知道。 面试官要是追问怎么排查,就说开 d e b u g 日制 logging dot level, dot org, dot spring framework, dot transaction equals debug, 能看到事物什么时候开,什么时候提交,一眼就知道生没生效。事物这东西看着简单,一个注解的事,但真出了问题,轻的数据错乱,重的资金损失, 半夜被叫起来查问题的滋味不好受。这就是 at transactional 的 七个坑,觉得有用就点个赞。我是程序员 mike, 专门聊那些文档里不写出事才知道的坑。下期见。

记录一下我刚完成的 java web 大 作业。首先登录一下系统,登录成功以后,我点击返回是退回不了登录页面的, 退出状态下,即使手动输入路径也是会被重定向到登录页面的。这个首页里面记录的是一些静态内容,我使用的是 ssm 框架,然后加上 gsp, 页面还使用到了 msc。 下面是具体模块的展示 订单,这里的订单金额是根据选择的商品来进行动态计算的,小计也是动态变化的 个人中心,这里的头像可以上传本地的图片,这里文件上传功能我也实现了。 这个项目需要配置一下 tomcat, 我 使用的是 tomcat 九。