1.什么是Spring
Spring是一个轻量级的、开源的javaEE开源框架,它实现了IOC和AOP。
2.IOC与DI的区别
IOC(反转控制):将对象的创建权交由spring管理,而解放手动创建对象的过程,达到低耦合度的目的。实现原理:将需要的类名配置(注入到)到配置文件中,然后在使用的时候spring利用反射技术动态的生成和创建这个类。
DI(依赖注入):在spring创建对象的过程中,把对象的属性注入到类中。依赖注入的三种方式:构造器注入、Setter方法注入、接口注入。
3.bean的自动装配
定义:Spring 容器能够自动装配相互合作的bean,这意味着容器不需要<constructor-arg>
和property
配置,能通过Bean工厂自动处理bean之间的协作。
Spring容器装配Bean的方式:xml配置和注解配置。基于xml自动装配的三种方式:ByName,ByType,ByConstructor( ByType要存在set方法);
基于注解的自动装配的方式:@Autowired,@Resource,@value。使用注解时必须启动注解驱动<context:annotation-config />
1.@Autowired 注解,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用标注到成员变量时不需要有set方法,它默认按ByType匹配的;2. @Autowried具备相同功效的还有@Resource,默认按 byName模式 自动注入;3.@Value上述两种自动装配的依赖注入并不适合简单值类型。
4.Spring有哪些模块
Spring框架至今已集成了20多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。
核心容器(应用上下文) 模块:是基本的Spring模块,提供spring 框架的基础功能,BeanFactory 是 任何以spring为基础的应用的核心。Spring 框架建立在此模块之上,它使Spring成为一个容器。
5.spring bean的生命周期
- 通过构造器或工厂方法(工厂方法不为空则用)创建 Bean 实例; (源码:doCreateBean(..)–>createBeanInstance(..))
- 执行Bean的属性依赖注入(利用BeanPostProcessor来解析Autowire注解,利用populate方法将依赖的对象注入到当前Bean中)
- 激活invokeAwareMethods(beanName, bean)(用于得到Spring中代表容器的beanFactory,并且可以根据得到的beanFactory获取容器中所有的Bean:如果这个Bean实现了BeanNameAware接口,会调用它的setBeanName(String beanId)方法;) 如果这个Bean实现了BeanFactoryAware接口,会调用它的setBeanFactory(BeanFactory beanFactory); 如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext applicationContext)方法。(如果是Spring工厂生命周期,此步骤不需要);
- 将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization 方法;
- 调用Bean的初始化方法(invokeInitMethods(…) ;
- 将Bean实例传递给Bean后置处理器的postProcessAfterInitialization 方法;
- Bean 可以使用了。当容器关闭时, 调用 Bean 的销毁方法(destroy-method);
注意:Bean装配完成后,它是single的,所以我们调用同一个ID的Bean会是在内容地址相同的实例。
6.BeanFactory
1.BeanFactory和applicationContext的区别
BeanFactory是Spring的最底层接口,包含bean的定义,管理bean的加载,实例化,控制bean的生命周期,特点是每次获取对象时才会创建对象。
ApplicationContext是BeanFactory的子接口,拥有BeanFactory的全部功能,并且扩展了很多高级特性,每次容器启动时就会创建所有的对象。
,它提供的功能更加丰富:国际化、统一的资源文件访问方式、AOP等。
两者装配Bean的区别:BeanFactory在启动的时候不会去实例化Bean,只有从容器中拿Bean的时候才会去实例化;ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化。
2.BeanFactory和factoryBean的区别
BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。 但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
7.bean的作用域
Singleton(spring默认的):每一个Bean的实例只会被创建一次,而且Spring容器在整个应用程序生存期中都可以使用该实例。因此之前的代码中spring容器创建Bean后,通过代码获取的bean,无论多少次,都是同一个Bean的实例;
prototype: 它代表每次获取Bean实例时都会新创建一个实例对象,类似new操符.
request和session作用域:对于request作用域,对于每次HTTP请求到达应用程序,Spring容器会创建一个全新的Request作用域的bean实例,且该bean实例仅在当前HTTP request内有效,整个请求过程也只会使用相同的bean实例。同理session也是每当创建一个新的HTTP Session时就会创建一个Session作用域的Bean,并该实例bean伴随着会话的存在而存在;
globalSession:类似于session作用域,相当于一个全局变量.
总结:显然singletonBean永远只有一个实例;PrototypeBean则每次被获取都会创建新的实例;RequestBean则在同一次Http请求过程中是同一个实例,当请求结束,RequestBean也随着销毁,在新的Http请求则会生成新的RequestBean实例;SessionBean在同一个浏览器中访问属于同一次会话,SessionBean实例都是同一个实例对象。(<bean>标签的scope属性来指定一个Bean的作用域)
8.Spring懒加载
通过lazy-init=true
配置。(true:懒,false:非懒,default:懒)<bean id="test1" calss="com.xie.Name" lazt-init="default"/>
懒加载:对象使用的时候才去创建对象,有利于节约资源,但不利于提前发现错误。
非懒加载:Spring启动的时候就去创建对象,这样比较消耗资源,但是有利于提前发现错误。
9.事物
Spring支持两种类型的事务管理:声明式事务管理和编程式事务管理。声明式事务管理:可以将业务代码和事务管理分离,只需用注解和XML配置来管理事务。编程式事务管理:通过编程的方式管理事务,带来极大的灵活性,但是难维护。
两者的比较:声明式事务管理:它对应用代码的影响最小,因此更符合一个无侵入的轻量级容器的思想。声明式事务管理要优于编程式事务管理,虽然比编程式事务管理少了一点灵活性
10.Spring 事物的隔离级别
ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应。
ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
ISOLATION_REPEATABLE_READ: 保证事务开始时和事务结束前督导的数据是一样的。这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
11.Spring 事物的传播特性
Propagation-Required 需要 如果存在一个事务,则支持当前事务。如果没有事务则开启。
Propagation-required_new 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
Propagation-Supports 支持 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行.
Propagation-Not_support 总是非事务地执行,并挂起任何存在的事务。
Propagation-Mandatory 必要的 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
Propagation-Never 绝不 总是非事务地执行,如果存在一个活动事务,则抛出异常
Propagation-Nested 嵌套的 如果有就嵌套、没有就开启事务。
12.AOP
AOP的出现解决了代码的横切性问题,将核心业务代码与外围业务代码(日志、事物控制、性能、权限等)分离。
AOP原理:Spring AOP的代理分为静态代理(比如AspectJ)和动态代理(比如jdk和cglib)。Spring AOP的实现原理是基于动态织入的动态代理技术:Java JDK动态代理和CGLIB动态代理,前者是基于反射技术的实现,后者是基于继承的机制实现。
jdk动态代理:Spring通过java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。cglib动态代理:CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程呢。
使用jdk还是cglib:如果被代理的对象是接口或者是实现接口的类,则默认使用的是jdk动态代理。否则使用cglib动态代理。
springAop的5种通知方式:前置通知、后置通知、异常通知、最终通知以及环绕通知。
JDK动态代理:
具体实现原理:
1、通过实现InvocationHandler接口创建自己的调用处理器;
2、通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;
3、通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;
4、通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入;
JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,Spring通过java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。
Cglib动态代理
CGLib是一个强大、高性能的Code生产类库,可以实现运行期动态扩展java类,Spring在运行期间通过 CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程呢。 参考文献:Spring AOP 之JDK动态代理和CGLIB代理的区别 https://youyu4.iteye.com/blog/2348704
13.Spring框架中的单例Beans是线程安全的么?
对于原型bean,每次都创建一个新的对象,也就是线程之间不存在bean共享,自然不会有线程安全问题。
对于单例bean,所有线程都共享一个对象实例,会存在资源竞争问题。但如果该单例bean是无状态的,也就是线程中不会对bean的成员执行查询以外的操作,那么这个bean就是线程安全的。
比如spring中的controller,service,dao等是无状态的,只关注方法本身。如果是有状态的bean,spring官方提供的bean,一般用threadLocal来解决。比如,RequestContextHolder、LocalContextHolder等。
14.Spring 框架中都用到了哪些设计模式?
Spring框架中使用到了大量的设计模式,比较有代表性的有:
单例模式:在spring配置文件中定义的bean默认为单例模式。
工厂模式:BeanFactory用来创建对象的实例。
代理模式:在AOP和remoting中被用的比较多。
模板方法模式:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
16.Spring 如何解决bean之间的循环依赖
Spring是通过递归的方式获取目标bean及其所依赖的bean的;
Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。
结合这两点,也就是说,Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,
直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的。
Spring框架是怎么解决Bean之间的循环依赖的