文章所属专区 日积月累
本文主要针对Spring中两大特性,AOP和IOC,并针对他们的使用常见,结合面试常见问题,实现代码,进行解析。
在使用Java语言进行代码编写时,由于Java语言的特性,会有一些弊端,比如在处理一些不具有继承关系的一些类的公共行为时,只能在每个对象引用公共行为,会出现大量重复代码,会造成大量代码冗余,这样不仅浪费时间,也不方便维护,AOP的出现解决了这一个问题。
Spring中的AOP基于代理模式,首先会自定义一个注解;
其次,定义一个切面(Aspect)类,在切面中定义切点和通知,切点(方法的拦截规则),在使用了这个注解的方法会被拦截下来,拦截下来之后;
最后可以进行前置通知、后置通知、异常通知、返回通知还是环绕通知等。
代理类可以分为两类 动态代理(Dynamic Proxy)和静态代理(Static Proxy)Spring AOP(面向切面编程)中主要是运用了动态代理的方式来实现:在运行过程中通过反射机制动态创建而成,无需手动编写代码。
JDK动态代理是Spring AOP默认使用的方式,主要用于对实现了接口的类生成代理。JDK动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。Prox则利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象
CGLIB(Code Generation Library)是针对类实现代理的,主要是对指定的类生成一个子类,覆盖其中的方法(继承)。CGLIB是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口。CGLIB封装了asm,可以再运行期动态生成新class
cglib底层是基于继承被代理类来做代理的,而jdk则是通过接口的形式来做代理的。
jkd动态代理只提供接口的代理,不支持类的代理
如果代理类没有实现接口,那么Spring AOP会使用cglib来动态代理目标类
比如日志记录,性能优化,权限控制,内容传递,错误处理,事务管理,限流等。
在Spring AOP中,可以使用@AspectJ注解定义一个切面,然后在切面方法中添加@Before或@After注解,用于在方法执行前后插入相应的日志记录逻辑
AOP是Spring框架中最核心的两个点之一,它可以减少重复代码,降低模块间的耦合性,提高代码的可操作性和可维护性。在实际工作中,除了业务代码之外,还经常会接触到与业务无关的一些组件,比如日志,权限,事务等常见的核心服务组件,如果为每个业务代码单独添加这些组件,会出现大量的冗余代码,因此我们将这些公共的代码逻辑抽象出来成为一个切面,然后注入到具体业务中去。AOP就是通过这样一种方式,通过动态代理的方式,来对需要注入切面的对象进行代理,在进行调用时,直接将公共逻辑添加进去,而不需要修改原有的业务代码,在不改变原有业务代码的情况下做了代码功能的增强。
在传统的软件设计过程中,通常由调用者来创建被调用者的实例。但在Spring中创建被调用者的工作不在由调用者来完成,这就是控制反转。IOC是一种设计思想,即把原本在程序中手动创建对象的控制权交给了Spring框架中的IOC容器,让它去创建和管理这些对象。在Spring中实现IOC主要依靠DI(Dependency Injection 依赖注入) 来实现。
在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。
属性注入(property)、构造器注入(constructor-arg)、自动装配通过对bean的autowrite属性指定(byName、byType)
这种方式后来在 SpringBoot 中常用 ,@autowrite @resource @component等
IOC 控制反转:
在没有使用IOC容器之前,都是由程序员来控制对象,而有了IOC容器之后,则由IOC容器来控制对象;
控制的是实现过程中所需要的对象以及依赖的对象;
在没有使用IOC之前,我们都需要主动在对象中创建依赖的对象,这种正转的,而有了IOC之后,依赖的对象由IOC创建后注入到对象中,由主动创建变成了被动接受,这是反转;
IOC是一种思想,DI(依赖注入:把对应的属性的值注入到对象)是具体的实现方式 @AutoWried
IOC 容器(Spring用来实现IOC的载体,实际是个Map(Key,value),Map中存放的是各种对象):
在Spring中一般存在三级缓存,singletonObject存放完整的Bean对象,整个Bean的生命周期,从创建到使用到销毁全部都由容器来控制。
1.IOC容器的创建(beanFactory根接口的DeafultListableBeanFactory)优先创建bean工厂,向bean工厂设置一些属性(BeanPostProcessor,Aware接口的子类)等属性
2.加载解析bean对象,准备创建的定义对象beanDefinition(会涉及到xml或者注解的解析过程)
3.BeanFactoryProcessor的处理,此处是扩展点!!!(PlaceHolderConfigurSupport 处理占位符,ConfigurationClassPostProssor)
4.BeanPostProcessor的注册功能,方便后续对bean对象完成具体的扩展功能
5.通过反射的方式将BeanDefinition对象实例化成具体的bean对象
6.bean对象的初始化过程(填充属性,调用Aware子类的方法,调用BeanPostProcessor前置处理方法,调用init-method方法,调用BeanPostProcessor的后置处理方法–Bean的生命周期)
7.生成完整的bean对象,通过getBean方法可以直接获取
8.销毁过程
以上就是我对于ioc的整体理解,包含一些细节,如果有什么问题,请小伙伴指点一下
总结:
spring中的Bean都是通过反射生产的,其中包含了很多的扩展点,比如常见的对BeanFactory的扩展,对Bean的扩展,此外,ioc中最核心的就是填充具体Bean的属性和Bean的生命周期
底层实现:工作原理,过程,数据结构,流程,设计模式,设计思想
方法:
createBeanFactory
getBean
doGetBean
createBean
doCreateBean
1.先通过creatBeanFactory方法中的DeafultListableBeanFactory创建一个Bean工厂
2.开始循环创建对象,因为容器中的Bean都是单例的,所以优先通过getBean,doGetBean从容器中查找,找不到的话,
3.通过createBean,doCreateBean方法,以反射的方式创建对象,一般情况下使用无参的构造方法(getDeclaredConstructor,newInstance)
4.通过polulateBean进行对象的属性填充
5.进行其他的初始化操作(initializingBean)
1.通过反射实例化Bean对象:通过反射的方式生成对象
2.通过polulateBean设置对象属性:populateBean(),循环依赖的问题(三级缓存)
3.调用aware接口的相关方法:invokeAwareMethod(完成BeanName,BeanFactory,BeanClassLoader对象的属性设置)
4.调用BeanPostProcessor中的前置处理方法(ApplicationContextPostProcessor,设置Application的Context,Environment,ResourceLoader等对象)
5.调用init-method方法:invokeInitMethod() 判断是否实现了initiazingBean接口,如果有就调用afterPorpertiesSet()方法,没有就不调用
6.调用BeanPostProcessor的后置处理方法:Spring的AOP就是在此处实现的 AbstractAutoProxyCreator()
7.获取到完整的对象,可以通过getBean的方式来进行对象的获取
8.销毁流程:1.判断是否实现了DispoableBean接口2.调用destoryMethod()方法。
谈谈对IOC的理解
Spring AOP的理解与使用
面试被问了几百遍的 IoC 和 AOP ,还在傻傻搞不清楚?
给个三连吧 谢谢谢谢谢谢了