IoC

工厂模式
IoC(Inverse of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。
为什么叫控制反转?

  • 控制 :指的是对象创建(实例化、管理)的权力
  • 反转 :控制权交给外部环境(Spring 框架、IoC 容器)

将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。
这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。
在实际项目中一个 Service 类可能依赖了很多其他的类,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。
Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。

AOP前置知识

动态代理

实现方式

  • jdk动态代理,使用jdk中的Proxy,Method,Invocationhandlerl创建代理对象

jdk动态代理要求目标类必须实现接口

  • CGLib动态代理:目标类没有接口,第三方工具库,创建代理对象,原理是继承。通过继承目标类,创建子类。
  • 字节码 aspectJ

子类就是代理对象。要求目标类不能是final的,方法也不能是final的
有接口,但是要用CGLIB,配置一下

  1. <aop:aspectj-autoproxy proxy-target-class="true">

动态代理作用

  1. 在目标源代码不改变的情况下,增加功能
  2. 减少代码的重复
  3. 专注业务的逻辑代码
  4. 解耦和,让你的业务功能和日志,事物等非业务功能分离

    概念

    任何一个系统都是由不同的组件组成的,每个组件负责一块特定的功能,当然会存在很多组件是跟业务无关的,例如日志,事务,权限等核心服务组件,这些核心服务组件经常融入到具体的业务逻辑中,如果我们为每一个具体业务逻辑操作都添加这样的代码,很明显,代码冗余太多,此时我们需要将这些公共的代码逻辑抽象出来,变成一个切面,然后注入到目标对象中,aop正是基于这样的一个思路实现的,通过动态代理的方式,将需要注入切面的对象进行代理,在进行调用的时候,讲公共的逻辑添加进去,而不需要修改原有业务的逻辑代码,只需要在原来的业务逻辑基础上做一些增强功能即可。

使用aop目的

给已经存在的一些类和方法,增加额外的功能。前提是不改变原来的类的代码

术语

  • Aspect 切面 表示增强的功能 事物,日志
  • Join Point 连接点 连接业务方法和切面的位置
  • Point cut 切入点 多个连接点方法的集合 切入表达式execution( com.cx.store.service.impl..*.(..))
  • Target 给哪个类的方法增加功能
  • Advice 通知,表示切面功能执行的时机

    切面3要素

  1. 切面的功能代码 ,切面干什么 Aspect 切面
  2. 切面的执行位置,使用Pointcut表示执行的位置 切入表达式execution( com.cx.store.service.impl..*.(..))
  3. 切面的执行时机,使用Advice表示时机,在目标方法之前还是目标方法之后,有以下五种

    Spring中有哪些通知类型(advice)

  • Before(前置通知): 连接点之前执行,除非抛异常,否则没有能力中断执行流(@Before 注解)
  • After Retuning(返回通知): 在连接点正常结束之后(没有抛出异常正常返回)执行的Advice(@AfterReturning 注解)可以得到返回值 根据返回值做出其他的操作,在通知结束后更改返回值不会改变的
  • Around(环绕通知): 围绕连接点执行的Advice,就你一个方法调用(相对于合并前置后置)( @Around 注解)
  • After Throwing(异常通知): 如果方法通过抛出异常来退出的话,这个Advice就会被执行(@AfterThrowing 注解)
  • After(后置通知): 无论连接点是通过什么方式退出的(正常返回或者抛出异常)都会在结束后执行这些Advice(@After 注解)

在Spring AOP中关注点和横切关注点有什么不同?

关注点:我们在应用的模块中实现以解决特定业务问题的方法。比如库存管理、航运管理、用户管理等

横切关注点:贯穿整个应用程序的关注点。像事务管理、权限、日志、安全等。

Spring AOP的代理是什么?

Spring AOP是基于代理实现的,默认为标准的 JDK 动态代理。这使得任何接口(或者接口的集合)可以被代理。
Spring AOP 也使用 CGLIB 代理。如果业务对象没有实现任何接口那么默认使用CGLIB。

示例代码

  1. / * 切面方法修饰符 必须是public
  2. * 返回值 如果这个方法被@Aspect修饰 返回值必须是Object
  3. * 方法名 自定义 参数
  4. * ProceedingJoinPoint Around修饰的方法必须传递这个参数
  5. * aop不是spring内部封装技术,需要导入包
  6. * AspeccJweaver AspeccJtools ProceedingJoinPoint 连接点,目标方法的对象
  7. ProceedingJoinPoint pjp==invoke()中的method 参数必须在第一个,不然报错 无法绑定pointcut
  8. */
  9. // 将当前类标记为切面类
  10. @Aspect
  11. // 交给Spring容器管理
  12. @Component
  13. public class TimeAspect {
  14. @Around("execution(* com.cy.store.service.impl.*.*(..))")
  15. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  16. // 记录起始时间
  17. long start = System.currentTimeMillis();
  18. // 执行连接点方法,即切面所在位置对应的方法。本项目中表示执行注册或执行登录等
  19. // proceed() 调用目标方法 例如 login
  20. Object result = pjp.proceed();
  21. // 记录结束时间
  22. // TODO 插入数据库
  23. long end = System.currentTimeMillis();
  24. // 计算耗时
  25. System.err.println(pjp.getSignature().getName() + "这个功能耗时:" + (end - start) + "ms");
  26. // 返回连接点方法的返回值
  27. return result;
  28. }
  29. }
  30. //findHotList这个功能耗时:833ms
  31. //login这个功能耗时:7ms
  32. //findHotList这个功能耗时:3ms

[

](https://blog.csdn.net/weixin_39309402/article/details/100877521)

简述一下Spring AOP的设计原理

主要的分代理的创建和代理的调用两部分,比如UML图:

image.png

1)代理的创建
创建代理工厂:拦截器数组,目标对象接口数组,目标对象。
创建代理工厂时,默认会在拦截器数组尾部再增加一个默认拦截器 —— 用于最终的调用目标方法。
当调用 getProxy 方法的时候,会根据接口数量大余 0 条件返回一个代理对象(JDK or Cglib)。
注意:创建代理对象时,同时会创建一个外层拦截器,这个拦截器就是 Spring 内核的拦截器,用于控制整个 AOP 的流程。
2)代理的调用
当对代理对象进行调用时,就会触发外层拦截器。
外层拦截器根据代理配置信息,创建内层拦截器链。创建的过程中,会根据表达式判断当前拦截是否匹配这个拦截器。而这个拦截器链设计模式就是职责链模式。
当整个链条执行到最后时,就会触发创建代理时那个尾部的默认拦截器,从而调用目标方法,最后返回。
image.png