Java 业务开发常见错误 100 例
朱晔
贝壳金服资深架构师
51940 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 48 讲
代码篇 (23讲)
Java 业务开发常见错误 100 例
15
15
1.0x
00:00/00:00
登录|注册

19 | Spring框架:IoC和AOP是扩展的核心

你好,我是朱晔。今天,我们来聊聊 Spring 框架中的 IoC 和 AOP,及其容易出错的地方。
熟悉 Java 的同学都知道,Spring 的家族庞大,常用的模块就有 Spring Data、Spring Security、Spring Boot、Spring Cloud 等。其实呢,Spring 体系虽然庞大,但都是围绕 Spring Core 展开的,而 Spring Core 中最核心的就是 IoC(控制反转)和 AOP(面向切面编程)。
概括地说,IoC 和 AOP 的初衷是解耦和扩展。理解这两个核心技术,就可以让你的代码变得更灵活、可随时替换,以及业务组件间更解耦。在接下来的两讲中,我会与你深入剖析几个案例,带你绕过业务中通过 Spring 实现 IoC 和 AOP 相关的坑。
为了便于理解这两讲中的案例,我们先回顾下 IoC 和 AOP 的基础知识。
IoC,其实就是一种设计思想。使用 Spring 来实现 IoC,意味着将你设计好的对象交给 Spring 容器控制,而不是直接在对象内部控制。那,为什么要让容器来管理对象呢?或许你能想到的是,使用 IoC 方便、可以实现解耦。但在我看来,相比于这两个原因,更重要的是 IoC 带来了更多的可能性。
如果以容器为依托来管理所有的框架、业务对象,我们不仅可以无侵入地调整对象的关系,还可以无侵入地随时调整对象的属性,甚至是实现对象的替换。这就使得框架开发者在程序背后实现一些扩展不再是问题,带来的可能性是无限的。比如我们要监控的对象如果是 Bean,实现就会非常简单。所以,这套容器体系,不仅被 Spring Core 和 Spring Boot 大量依赖,还实现了一些外部框架和 Spring 的无缝整合。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 业务开发常见错误 100 例》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(23)

  • 最新
  • 精选
  • Darren
    置顶
    一、注解区别 @Autowired 1、@Autowired是spring自带的注解,通过‘AutowiredAnnotationBeanPostProcessor’ 类实现的依赖注入; 2、@Autowired是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier; 3、@Autowired有个属性为required,可以配置为false,如果配置为false之后,当没有找到相应bean的时候,系统不会抛错; 4、@Autowired可以作用在变量、setter方法、构造函数上。 @Inject 1、@Inject是JSR330 (Dependency Injection for Java)中的规范,需要导入javax.inject.Inject;实现注入。 2、@Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named; 3、@Inject可以作用在变量、setter方法、构造函数上。 @Resource 1、@Resource是JSR250规范的实现,需要导入javax.annotation实现注入。 2、@Resource是根据名称进行自动装配的,一般会指定一个name属性 3、@Resource可以作用在变量、setter方法上。 总结: 1、@Autowired是spring自带的,@Inject是JSR330规范实现的,@Resource是JSR250规范实现的,需要导入不同的包 2、@Autowired、@Inject用法基本一样,不同的是@Autowired有一个request属性 3、@Autowired、@Inject是默认按照类型匹配的,@Resource是按照名称匹配的 4、@Autowired如果需要按照名称匹配需要和@Qualifier一起使用,@Inject和@Name一起使用 二:循环依赖: 直观解决方法时通过set方法去处理,背后的原理其实是缓存。 主要解决方式:使用三级缓存 singletonObjects: 一级缓存, Cache of singleton objects: bean name --> bean instance earlySingletonObjects: 二级缓存, Cache of early singleton objects: bean name --> bean instance 提前曝光的BEAN缓存 singletonFactories: 三级缓存, Cache of singleton factories: bean name --> ObjectFactory

    作者回复: 👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻

    7
    104
  • 左琪
    这里的代理类不是单例么,还是说会在增强逻辑里不断创建被代理类?

    作者回复: 代理类会来判断是否需要创建新的对象

    7
  • norman
    @Resource 和 @Autowired @Inject 三者区别: 1 @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。 2 @Autowired默认是按照类型装配注入的,如果想按照名称来转配注入,则需要结合@Qualifier。这个注释是Spring特有的。 3 @Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named

    作者回复: 👍🏻,也可以参考 https://stackoverflow.com/questions/20450902/inject-and-resource-and-autowired-annotations 这里的回复

    7
  • Demon.Lee
    连接点: 程序执行过程中能够应用通知的所有点;通知(增强): 即切面的工作,定义了What以及When;切点定义了Where,通知被应用的具体位置(哪些连接点) ----Spring实战(第4版)

    作者回复: 不错

    4
  • Joker
    老师,请教一下,那个sayservice里的data有啥用,那个单例是为了一种重复使用data对吧,那换成每次都生成一个新的bean,那个data还有效果吗。。

    作者回复: 只是为了模拟SayService是有状态

    3
  • 龙行秀
    “架构师一开始定义了这么一个 SayService 抽象类,其中维护了一个类型是 ArrayList 的字段 data,用于保存方法处理的中间数据。每次调用 say 方法都会往 data 加入新数据,可以认为 SayService 是有状态,如果 SayService 是单例的话必然会 OOM” -----为什么单例就会OOM,多例就不会呢?没看懂

    作者回复: 容器维护了这个单例,回收不了

    3
    2
  • 小学生
    老师,您好,您讲 的切面执行顺序好像不对啊,我的执行顺序和你说的不一致! [10:34:11.367] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.a.TestAspectWithOrder10:31 ] - TestAspectWithOrder10 @Around before [10:34:11.377] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.a.TestAspectWithOrder10:21 ] - TestAspectWithOrder10 @Before [10:34:11.377] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.a.TestAspectWithOrder20:31 ] - TestAspectWithOrder20 @Around before [10:34:11.378] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.a.TestAspectWithOrder20:21 ] - TestAspectWithOrder20 @Before [10:34:11.379] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.aopmetrics.MetricsAspect:79 ] - 【入参日志】调用 【class org.geekbang.time.commonmistakes.springpart1.aopmetrics.TestController】【public void org.geekbang.time.commonmistakes.springpart1.aopmetrics.TestController.test()】【http://localhost:45678/test】 的参数是:【[]】 [10:34:11.379] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.aopmetrics.MetricsAspect:88 ] - 【成功打点】调用 【class org.geekbang.time.commonmistakes.springpart1.aopmetrics.TestController】【public void org.geekbang.time.commonmistakes.springpart1.aopmetrics.TestController.test()】【http://localhost:45678/test】 成功,耗时:0 ms [10:34:11.379] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.aopmetrics.MetricsAspect:107 ] - 【出参日志】调用 【class org.geekbang.time.commonmistakes.springpart1.aopmetrics.TestController】【public void org.geekbang.time.commonmistakes.springpart1.aopmetrics.TestController.test()】【http://localhost:45678/test】 的返回是:【null】 [10:34:11.380] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.a.TestAspectWithOrder20:26 ] - TestAspectWithOrder20 @After [10:34:11.380] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.a.TestAspectWithOrder20:33 ] - TestAspectWithOrder20 @Around after [10:34:11.380] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.a.TestAspectWithOrder10:26 ] - TestAspectWithOrder10 @After [10:34:11.380] [http-nio-45678-exec-4] [INFO ] [o.g.t.c.s.a.TestAspectWithOrder10:33 ] - TestAspectWithOrder10 @Around after

    作者回复: 哪里不对?

    3
    1
  • track6688
    老师,请教一个问题,我使用这个注解,@Order(Ordered.HIGHEST_PRECEDENCE),使用@AfterThrowing这个时,报No MethodInvocation found: Check that an AOP invocation is in progress, and that the ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!,怎么处理呢?

    作者回复: 意思是ExposeInvocationInterceptor需要在前面执行,最新的ExposeInvocationInterceptor已经是PriorityOrdered了,你是不是老版本的Spring?把自己的类优先级调低点

    1
  • 看不到de颜色
    感觉Spring Intercepter的执行顺序和Servlet Filter的执行过程是一样的,一个递归调用栈。 有个疑问想请老师解答一下。采用创建内部类的方式获取默认注解配置,这样不会每调用一次就会在元空间中生成一个c的Class信息吗?

    作者回复: 这不会,会编译为 final class MetricsAspect$1c { MetricsAspect$1c(MetricsAspect this$0) { this.this$0 = this$0; } }

    1
  • David Mo
    @sevice 的坑踩过,代理类一开始不行白,后来说动态创建就懂了。当时是用一个类似工厂类解决的

    作者回复: 好吧

    1
收起评论
显示
设置
留言
23
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部