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