P59

1、Spring的两大核心是什么?谈一谈你对IOC的理解? 谈一谈你对DI的理解? 谈一谈你对AOP的理解?

  1. Spring的两大核心是:IOC(控制翻转)和AOP(面向切面编程) DI(依赖注入)
    2. IOC的意思是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。最直观的表达就是,IOC让对象的创建不用去new了,可以由spring根据我们提供的配置文件自动生产,我们需要对象的时候,直接从Spring容器中获取即可.
    Spring的配置文件中配置了类的字节码位置及信息, 容器生成的时候加载配置文件识别字节码信息, 通过反射创建类的对象.
    Spring的IOC有三种注入方式 :构造器注入, setter方法注入, 根据注解注入。
    3. DI的意思是依赖注入,和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖Io c容器来动态注入对象需要的外部资源。
    4. AOP,一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect). SpringAOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
    5. Spring AOP 中的动态代理主要有两种方式,JDK 动态代理和 CGLIB 动态代理:
    (1)JDK 动态代理只提供接口代理,不支持类代理,核心 InvocationHandler 接口和 Proxy 类,InvocationHandler 通过 invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起,Proxy 利用 InvocationHandler 动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
    (2) 如果代理类没有实现 InvocationHandler 接口,那么 Spring AOP会选择使用 CGLIB 来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现 AOP。CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的。

2、Spring的生命周期?

Spring默认对bean采用的是单例设计模式,bean创建完毕的时候回调用init-method指定的方法,然后bean对象会进入到spring的容器中,如果bean配置有id或者是name那么该bean存储到spring容器的时候会使用id或者name作为对象标记。当spring容器销毁之前会调用destroy-method指定的方法。

3、Spring支持bean的作用域有几种吗? 每种作用域是什么样的?

Spring支持如下5种作用域:
(1)singleton:默认作用域,单例bean,每个容器中只有一个bean的实例。
(2)prototype:为每一个bean请求创建一个实例。
(3)request:为每一个request请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
(4)session:与request范围类似,同一个session会话共享一个实例,不同会话使用不同的实例。
(5)global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中

4、BeanFactory和ApplicationContext有什么区别:

BeanFactory:
Spring最顶层的接口,实现了Spring容器的最基础的一些功能, 调用起来比较麻烦, 一般面向Spring自身使用
BeanFactory在启动的时候不会去实例化Bean,从容器中拿Bean的时候才会去实例化
ApplicationContext:
是BeanFactory的子接口,扩展了其功能, 一般面向程序员身使用
ApplicationContext在启动的时候就把所有的Bean全部实例化了

5、Spring的对象默认是单例的还是多例的? 单例bean存不存在线程安全问题呢?

  1. 在spring中的对象默认是单例的,但是也可以配置为多例。
    2. 单例bean对象对应的类存在可变的成员变量并且其中存在改变这个变量的线程时,多线程操作该bean对象时会出现线程安全问题。
    原因是:多线程操作如果改变成员变量,其他线程无法访问该bean对象,造成数据混乱。
    解决办法:1、在bean对象中避免定义可变成员变量;
    2、在bean对象中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中。