1、什么是Spring?  

Spring是一个开源框架,为简化企业级开发而生,是一个IOC(DI)和AOP容器框架。使用Spring,JavaBean就可以实现很多以前要靠EJB才能实现的功能。同样的功能,在EJB中要通过繁琐的配置和复杂的代码才能够实现,而在Spring中却非常的优雅和简洁。

2、Spring都有哪些模块?

Spring框架至今已集成了20多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。

面试必问Spring知识点

3、Spring的优良特性有哪些?

[1]非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API。

[2]依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。

[3]面向切面编程:Aspect Oriented Programming——AOP。

[4]容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期。

[5]组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。

[6]一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。

4、什么是IOC? 

IOC(Inversion of Control) 翻转控制,将资源对象的创建权交给ioc容器,由ioc容器创建,然后推送给组件。以前是new一个对象,现在不用手动去创建对象,通过bean或注解自动创建了IOC容器,自行创建了对象。

传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率。反转控制的思想:反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。

  5、什么是DI?

DI(Dependency Injection) 依赖注入(翻转控制的补充说明) 注入动态关系各个层之间,组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器的资源注入。

6、IOC有哪两种实现方式?

1、基于xml,在spring.xml文件里 写一个组件<bean>并为其赋值 然后在需要的地方 通过实例化IOC容器 根据组件对应的类型或id值 从容器中提取 ClassPathXmlApplicationContext

2、基于注解,需要先在web.xml文件中配置监听器ContextLoaderListener, 再在dao层使用注解@Repository,在service层加注解@Service ,在WEB层加注解@Controller ,需要使用对象的时候,使用@Autowired注解 这样IOC容器就会自动创建好这个对象。

7、BeanFactory和ApplicationContext的区别是什么?

(1)BeanFactory:IOC容器的基本实现,是Spring内部的基础设施,是面向Spring本身的,不是提供给开发人员使用的。

(2)ApplicationContext:BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。

8、Spring配置有几种方式?

1.基于XML的配置

2.基于注解的配置

3.基于Java的配置

9、ApplicationContext的主要有哪几个实现类?

[1]ClassPathXmlApplicationContext:对应类路径下的XML格式的配置文件。

[2]FileSystemXmlApplicationContext:对应文件系统中的XML格式的配置文件。

10、@AutoWire注解查找规则(如何实现自动装配)?

根据指定的装配规则,不需要明确指定,Spring自动将匹配的属性值注入bean中

[1]根据类型自动装配:将类型匹配的bean作为属性注入到另一个bean中。若IOC容器中有多个与目标bean类型一致的bean,Spring将无法判定哪个bean最合适该属性,所以不能执行自动装配。

[2]根据名称自动装配:必须将目标bean的名称和属性名设置的完全相同。

[3]通过构造器自动装配:当bean中存在多个构造器时,此种自动装配方式将会很复杂。不推荐使用。

11、Springbean的作用域有哪些?

Spring容器中的bean可以分为5个范围:

(1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。ioc启动创建所有单实例的bean,每次获取到的是之前创建好的,多次获取都是同一个对象。

(2)prototype:为每一个bean请求提供一个实例。ioc启动的时候不会去创建多实例bean的对象,每次获取的时候,会创建bean的对象,每次创建都是新的对象。应用场景:struts的action设置为多例。   将属性scope设置为scope="prototype"。

(3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。

(4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。

(5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。

12、Spring常见的注解有哪些?

@Repository   @Service   @Controller   @Autowired   @Resource  @Component   @Qualifier

13、@Autowired和@Resource之间的区别?

(1) @Autowired注解是属于Spring的;默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。

(2) @Resource注解是属于J2EE的;默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。

14、什么是声明式事务?什么是编程式事务?

声明式事务:即在类上或者是方法上加上的@Transactional注解,建立在AOP之上的;其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明即可;

编程式事务:相比声明式事务的非侵入式的开发方式,编程式事务需要自己通过编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager来实现事务;Spring更推崇使用TransactionTemplate来实现编程式事务;

各自优缺点:

声明式事务:非侵入式的开发方式;业务代码不收污染;简单,方便;事务粒度最小在一个方法上。

编程式事务:相对于声明式事务唯一的优点就是事务粒度更精细。

15、Spring IoC 加载过程

Spring IoC 加载过程再简单地总结一下 Spring IoC 加载的全部过程,大致可分为定位、解析、注册、实例化四个步骤:

1)定位:就是资源文件定位,资源文件可以是文件、URL、二进制数组,和Bean配置有关的通常是 XML / @Configuration / 注解(Java文件);一般是在 ApplicationContext 的实现类里完成的,可以将外部的资源,读取为 Resource 类。

2)解析:解析就只对资源文件的解析;解析主要是在 BeanDefinitionReader 中完成的;比如最常见的 XML 配置文件,那么将解析工作委托给 XmlBeanDefinitionReader 来完成;解析最终解析的结果都封装为 BeanDefinitionHolder ;

3)注册:所谓的注册,其实就是将 BeanDefinition 的 Name 和实例,保存到一个 Map 中;bean 的注册是在 BeanFactory 里完成的;BeanFactory 接口最常见的一个实现类是 DefaultListableBeanFactory ,其中的 Map 就是 BeanDefinitionMap ,是一个 ConcurrentHashMap 。

4)实例化:注册完成后,在 BeanFactory 的 getBean() 方法之中,完成初始化;这时候应用程序就可以直接使用 Bean 了。

16、Spring 框架中都用到了哪些设计模式?

(1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;

(2)单例模式:Bean默认为单例模式。

(3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;

(4)模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。

(5)观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现--ApplicationListener。

17、Spring框架中的单例Beans是线程安全的么?

        Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。

18、Spring如何处理线程并发问题?

在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。

ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

20、谈谈你对Spring的AOP理解?

OOP面向对象,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。

AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。

AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

(1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。

(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

        ①JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例,  生成目标类的代理对象。

        ②如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

 InvocationHandler 的 invoke(Object  proxy,Method  method,Object[] args):proxy是最终生成的代理实例;  method 是被代理目标实例的某个具体方法;  args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。

 

 

 

 

相关文章: