AOP
什么是AOP
通俗的讲就是当你想要实现对象增强,就可以使用AOP。
不然的话还需要自己创建代理,AOP就是为了解决 非业务代码抽取 的问题。
它的底层技术实现是动态代理,在Spring内实现依赖的是BeanPostProcessor。
AOP在Spring中的几种实现方式
一共有4种方式:
- 注解
- XML
- JavaConfig
- 基于Groovy DSL配置
一般在实际应用中,主要是注解、XML,少部分会用JavaConfig。
比如常见的业务代码使用注解定义各种对象,责任链这种一般有的会配置定义在XML。
注解解决不了的就会用JavaConfig。
不同版本Spring的AOP执行顺序
Spring AOP常用的注解:
- @Before 前置通知:目标方法之前执行
- @After 后置通知:目标方法之后执行
- @AfterReturning 返回后通知:执行方法结束前执行(异常不执行)
- @AfterThrowing 异常通知:出现异常时执行
- @Around 环绕通知:环绕目标方法执行
Spring4 下AOP的执行顺序:
正常情况:@Before前置通知 -> @After后置通知 -> @AfterReturning正常返回 异常情况:@Before前置通知 -> @After后置通知 -> @AfterThrowing方法异常
Spring5 下AOP的执行顺序:
正常情况:@Before前置通知 -> @AfterReturning正常返回 -> @After后置通知 异常情况:@Before前置通知 -> @AfterThrowing异常通知 -> @After后置通知
Spring AOP实现原理
Spring AOP是通过代理模式实现的。
具体有两种实现方式,一种是基于Java原生的动态代理,一种是基于cglig的动态代理。
对应的代码实现分别是:CglibAopProxy和JdkDynamicAopProxy
- 同时Spring AOP默认使用的是JDK动态代理进行AOP代理。这使得任何接口都可以被代理。但是JDK动态代理有一个缺点,就是不能代理没有接口的类。所以Spring AOP使用CGLIB代理没有接口的类
- 但是要注意Spring Boot在2.x版本后默认使用的是CGLIB动态代理了。具体原因是为了解决使用JDK代理可能导致的类型转化异常而使用CGLIB。当然也可以通过参数
spring.aop.proxy-target-class=false
进行修改
为什么SpringBoot默认使用CGLIB作为代理的实现方式呢?
我觉得可以从两个切入点聊一聊这个事:一是兼容性,另外就是性能。
- 兼容性:
CGLIB动态代理可以适用于任何类型的目标类,无论它是否实现了接口。
而JDK动态代理只能适用于实现了接口的目标类。
这意味着CGLIB动态代理可以覆盖JDK动态代理的所有场景,而JDK动态代理不能覆盖CGLIB动态代理的所有场景。
因此,为了保证SpringBoot中的AOP(面向切面编程)功能可以应用于任何类型的Bean(无论它是否实现了接口),SpringBoot默认使用CGLIB作为代理的实现方式。
- 性能:
CGLIB动态代理在生成代理对象时需要消耗更多的时间和内存资源,因为它需要操作字节码;而JDK动态代理在生成代理对象时相对较快,因为它只需要操作反射。
但是,在执行代理方法时,CGLIB动态代理比JDK动态代理要快得多,因为它直接调用目标方法,而不需要通过反射。
而在SpringBoot中,通常只会在容器启动时生成一次代理对象,并缓存起来;而在运行时会频繁地执行代理方法。因此,在整体性能上,CGLIB动态代理比JDK动态代理要优越。
什么是JDK代理?
JDK动态代理是通过反射机制来实现的,它要求目标类必须实现一个或多个接口,然后通过java.lang.reflect.Proxy类来创建代理对象,并通过 java.lang.reflect.InvocationHandler接口来实现方法的拦截和增强。
什么是CGLIB?
CGLIB是一种基于ASM的代码生成库,它可以在运行时动态地生成和修改Java字节码,从而实现对Java类和接口的扩展和代理。CGLIB是一种高性能、高质量的代码生成工具,被广泛应用于Hibernate、Spring AOP等框架中。
CGLIB动态代理是通过继承机制来实现的,它不要求目标类必须实现接口,而是通过 net.sf.cglib.proxy.Enhancer类来创建子类对象作为代理对象,并通过net.sf.cglib.proxy.MethodInterceptor接口来实现方法的拦截和增强。
Spring AOP在业务中常见的使用方式
在实际业务场景中AOP的使用频率还是很高的,比如:
- 一个系统离不开监控,监控基本的的指标有QPS、RT、ERROR等等。只要利用注解+AOP的方式封装一套,主要方法/类上带有自定义的注解,方法被调用时,就会上报你想要的相关监控指标。实现了非业务代码与业务代码分离的效果。
IOC
什么是IOC
从个人理解简述来说:Spring IOC解决的是对象管理和对象依赖的问题。以前我们是自己手动new出来的对象,现在则是可以将对象交给Spring的IOC容器进行管理。
IOC容器可以简单理解为一个对象工厂,我们都把该对象交给工厂,工厂管理这些对象的创建以及依赖关系,等我们需要的时候,从工厂里边获取就好了。
IOC的两个重要概念
IOC有两个重要的概念就是控制反转和依赖注入。
- 控制反转:指的就是将原有的自己掌控的事交给别人处理,其体现更多的是一种思想或者可以理解为设计模式。
比如:本来以前有我们自己new出来的对象,现在交给IOC容器,把对象的控制权交给它了。
- 依赖注入:可以理解为控制反转的实现方式。通俗的讲就是:对象无需自行创建或管理它的依赖关系,依赖关系将被自动注入到需要它们的对象中去。
Spring IOC有什么好处?或者说为什么要将对象交由给Spring IOC容器进行管理呢?
其最主要的好处就是将对象集中统一管理,并且降低耦合度。如果理解了【工厂模式】,其实也就不难理解为什么我们不直接new对象了。
好处:
- 我们可以使用Spring IOC可以方便单元测试,对象创建复杂、对象依赖复杂、单例等等。什么都可以交给Spring IOC
理论上自己new出来的都可以解决上面的问题,Spring在各种场景下有可能并不是最优解。但是new出来的对象要自己管理,可能需要利用一些工厂模式等,需要自己实现一整套的东西才可以满足需求。其实这样就无限接近了Spring的那一套了。
当然,如果项目中的对象都是new一下就完事了。没有多个实现类,那也可以不用Spring也没什么问题
但是,Spring核心并不是仅仅IOC,除了把对象创建出来,还有一整套的生命周期管理,比如说AOP实现的对象增强。
暂无评论内容