Spring 系列

什么是 Spring、为什么要使用 Spring


Spring 是一个开源的,轻量级的IOC,AOP容器框架,主要用于简化企业应用程序的开发,使开发者只需要关系业务需求,它可以将对象的创建和依赖关系的维护交给Spring容器来处理,降低程序耦合度,不仅可以提供面向切面编程,实现对程序进行权限拦截,运行监控等功能,而且还提供了事务支持,只需要通过配置就可以完成对事物的管理,此外它还能够集成各种框架,提高程序可扩展性。


Spring中的bean是什么


官方文档的解释是:在Spring中,构成应用程序主干并由Spring IoC容器管理的对象成为bean,bean是一个由Spring IoC容器实例化、组装和管理的对象。


Spring中的bean的生命周期


Spring中的bean的生命周期大概可以分为5个阶段,第一阶段是bean的创建前准备:这个阶段是在开始bean加载之前,从Spring的上下文和相关配置中解析并查找有关bean的相关配置,用来实现bean加载过程中的扩展机制;第二阶段是创建实例阶段,这个阶段主要是通过反射来创建bean的实例对象,并扫描和解析bean声明的一些属性;第三阶段是依赖注入阶段,在这个阶段,会检测被实例化的bean是否有其他依赖,如果有就需要对这些被依赖的bean进行注入,比如通过读取@Autowired、@Setter等依赖注入的配置。除此之外,这个阶段还会触发一些扩展的调用,比如常见扩展类BeanPostProcessors和BeanFactoryAware等等,第四阶段是容器缓存阶段,这个阶段主要是将实例化好的bean放到IOC容器中缓存起来,这个时刻的bean已经可以使用了;最后一个阶段叫实例销毁阶段,在容器关闭时,销毁所有的bean。


Spring中的bean是否是线程安全的


Spring中的bean除了内置的bean外都是通过我们的配置来声明的,这些 bean 是由 Spring容器来配置加载的,在bean的加载前根据我们的配置信息,比如说全类名(class),唯一标识(id),作用域(scope),延迟加载(lazy-init)等这些信息,来决定创建什么样的bean实例,其中和bean的线程安全相关的主要是作用域(scope),按作用域分的话可以将bean分为单例bean(singleton)和多例bean(prototype):多例bean在每次getBean的时候都会创建一个新的对象,所以线程之间不会出现共享的问题,而单例bean在Spring容器中只会存在一个全局共享的实例,所以单例bean可能会存在线程安全的问题。单例bean又分为无状态bean和又状态bean:无状态bean在多线程操作中对于bean的成员变量只会做查询操作,不会做修改操作,如此则不会有线程安全的问题,然而有状态bean则会对bean的成员变量做更新操作,所以最终的结论是:Spring中的单例有状态bean存在线程安全问题。

如何解决bean的线程安全问题:

①:把bean的作用域由单例改为多例。

②:在类的定义时,定义 ThreadLocal 的成员变量,把可能会造成线程安全的成员变量保存在其 中,因为 ThreadLocal 本身具有线程隔绝性,等价于为每个线程提供了一个变量副本。


Spring 是如何解决循环依赖的


(什么是循环依赖)Spring循环依赖是指一个或多个bean之间直接或者间接的存在依赖关系,这种依赖关系构成一个环形调用, (如何解决)Spring设计了三级缓存来解决循环依赖问题,一级缓存存放实例化,注入,初始化完成的bean实例,二级缓存用于保存实例化完成的bean,三级缓存保存bean创建工厂,以便后来创建代理对象。两个bean之间相互依赖,以下称A,B,当对A执行getBean ( )的时,发现没有,则准备创建一个,然后将A的代理工厂放入三级缓存(此时A是半成品,未完成属性注入),此时发现A的创建需要B,则先去创建B,创建B时发现又需要A,由于之前已经将A的代理工厂存放在三级缓存中,此时直接从三级缓存中获取A的代理对象,并将其放到二级缓存中,接着清除三级缓存,这时B在二级缓存中找到了A,则完成初始化,此时A拿到B,完成初始化,将其存放在一级缓存,清除二级缓存。


什么是AOP


AOP又叫面向切面编程,是面向对象编程的一种补充,用于将那些与业务无关,却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,能够减少系统中重复的代码,降低模块间的耦合度,同时提高了系统的可维护性,一般用于权限认证,日志,事务处理等。AOP的底层实现是动态代理,动态代理的意思就是AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个对象包含了目标对象的所有方法,并在特定的切点做了增强处理,并回调原对象方法,动态代理的方式主要为JDK动态代理和CGLIB动态代理,JDK动态代理只提供接口的代理,不支持类的代理,要求被代理的类必须实现接口,核心是InvocationHandler接口和Proxy类,在获取代理对象时,使用Proxy类来动态创建目标类的代理类,当代理对象调用真实对象的方法时, InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;如果被代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。


AOP中有什么参数


AOP中的名词:

连接点(Join point),切面(Aspect),切点(Pointcut),通知(Advice),目标对象(Target)


Advice有哪些类型


(1)前置通知(Before Advice):在连接点(Join point)之前执行的通知。

(2)后置通知(After Advice):当连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

(3)环绕通知(Around Advice):包围一个连接点的通知,这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也可以选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。

(4)返回后通知(AfterReturning Advice):在连接点正常完成后执行的通知(如果连接点抛出异常,则不执行)

(5)抛出异常后通知(AfterThrowing advice):在方法抛出异常退出时执行的通知


什么是IoC


控制反转,指将对象的控制权转移给Spring框架,由 Spring 来负责控制对象的生命周期(比如创建、销毁)和对象间的依赖关系。

最直观的表达就是,以前创建对象的时机和主动权都是由自己把控的,如果在一个对象中使用另外的对象,就必须主动通过new指令去创建依赖对象,使用完后还需要销毁(比如Connection等),对象始终会和其他接口或类耦合起来。而 IOC 则是由专门的容器来帮忙创建对象,将所有的类都在 Spring 容器中登记,当需要某个对象时,不再需要自己主动去 new 了,只需告诉 Spring 容器,然后 Spring 就会在系统运行到适当的时机,把你想要的对象主动给你。也就是说,对于某个具体的对象而言,以前是由自己控制它所引用对象的生命周期,而在IOC中,所有的对象都被 Spring 控制,控制对象生命周期的不再是引用它的对象,而是Spring容器,由 Spring 容器帮我们创建、查找及注入依赖对象,而引用对象只是被动的接受依赖对象,所以这叫控制反转。


什么是依赖注入


IoC 的一个重点就是在程序运行时,动态的向某个对象提供它所需要的其他对象,这一点是通过DI(Dependency Injection,依赖注入)来实现的,即应用程序在运行时依赖 IoC 容器来动态注入对象所需要的外部依赖。而 Spring 的 DI 具体就是通过反射实现注入的,反射允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性


IoC容器有哪些


(1) BeanFactory : IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用, BeanFactory 在加载配置文件的时候不会创建对象,在使用对象或者获取对象的时候才会去创建对象

(2) ApplicationContext: BeanFactory 接口的子接口,提供更多强大的功能,一般是由开发人员进行使用的,ApplicationContext 在加载配置文件的时候就已经创建好对象了

两者区别:

BeanFactory是Spring里面最底层的接口,是IoC的核心,定义了IoC的基本功能,包含了各种Bean的定义、加载、实例化,依赖注入和生命周期管理。ApplicationContext接口作为BeanFactory的子类,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能。

①BeanFactroy采用的是延迟加载形式来注入Bean的,只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能提前发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。

③ApplicationContext启动后预载入所有的单实例Bean,所以在运行的时候速度比较快,因为它们已经创建好了。相对于BeanFactory,ApplicationContext 唯一的不足是占用内存空间,当应用程序配置Bean较多时,程序启动较慢。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值