说说你对spring的理解?
Spring框架是一个轻量级的企业级开发的一站式解决方案,所谓一站式解决方案就是可以基于Spring解决Java EE开发的所有问题。Spring框架主要提供了IoC容器、AOP、数据访问、Web开发、消息、测试等相关技术的支持。
使用Spring框架有什么好处呢?
框架能更让我们高效的编程以及更方便的维护我们的系统。
(1)轻量级:相对其他框架来说,Spring的大小和开销是轻量的。
(2)控制反转(IoC):Spring通过控制反转实现了松散耦合。
(3)面向切面编程(AOP):将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证,日志,事务处理。
(4)Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问。
(5)Spring并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部。
解释下DI,IoC,AOP
Spring的核心是控制反转(IoC)和面向切面(AOP)。
DI(Dependency Injection,依赖注入)
指的是容器负责创建对象和维护对象间的依赖关系,而不是由对象本身负责自己的创建和解决自己的依赖。
IoC (Inversion of Control,控制反转)
不是一个具体的技术,而是一种设计思想。传统的Java开发模式中,当需要创建一个对象时,我们会使用NEW或者getInstance等方法直接或者间接调用构造方法去创建一个对象。而在Spring中,是将原本在程序中手动创建对象的控制权,交由Spring框架来管理 (通过容器负责创建对象和维护对象间的依赖关系,而不是由对象主动去找)。
补充理解:
(1) 在Spring环境下依赖注入和控制反转是等同的概念(是同一个概念从不同角度的描述的),控制反转是通过依赖注入实现的。由于控制反转这个概念比较含糊(可能只理解成了容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年被开发者尊称为“教父”的MartinFowler(世界顶级专家,敏捷开发方法的创始人之一)又给出了一个新的名字“依赖注入”,相对IoC而言,“依赖注入”明确描述了“被注入对象依赖 IoC 容器配置依赖对象”。
(2) 比如说传统找对象,先要设定好你的要求,如身高、体重、长相等,然后再一个一个的主动去找符合要求的对象,而IoC相当于,你把这些要求直接告诉婚介中心,由他们直接给你匹配到符合要求的对象,理想情况下是直接会帮你找到合适的对象,这就是传统编程模式和 IoC 的区别。
AOP (Aspect Oriented Programming,面向切面编程)
作为面向对象的一种补充,用于解剖封装好的对象内部,找出其中对多个对象产生影响的公共行为,将其封装为一个可重用的模块,这个模块叫做”切面(Aspect)”,切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证,日志,事务处理。
Spring AOP 目前提供了三种配置方式:
(1)基于 Java API 的方式;
(2)基于 @AspectJ(Java)注解的方式;
(3)基于 XML <aop /> 标签的方式。
Spring IoC的优点?
(1) 使用更方便,拿来即用,无需显式的创建和销毁的过程;
(2) 更符合面向对象的设计法则;
(3) 提供了 AOP 抽象,利用它很容易实现权限拦截、运行期监控等功能;
(4) 可以很容易提供众多服务,比如事务管理、消息服务等;
(5) 提供了单例模式的支持;
(6) 低侵入式设计,代码的污染极低,降低了业务对象替换的复杂性。
Spring IoC 注入方式?
IoC 的注入方式有三种:构造方法注入、Setter 注入和接口注入。
(1) 构造方法注入
构造方法注入主要是依赖于构造方法去实现,构造方法可以是有参的也可以是无参的,我们平时new对象时就是通过类的构造方法来创建类对象的,每个类对象默认会有一个无参的构造方法, Spring 通过构造方法注入的代码示例如下:
public class Person { public Person() { } public Person(int id, String name) { this.id = id; this.name = name; } private int id; private String name; // 忽略 Setter、Getter 的方法 }
applicationContext.xml 配置如下:
<bean id="person" class="org.springframework.beans.Person">
<constructor-arg value="1" type="int"></constructor-arg>
<constructor-arg value="Java" type="java.lang.String"></constructor-arg>
</bean>
(2) Setter注入
Setter方法注入的方式是目前Spring主流的注入方式,它可以利用JavaBean规范所定义的Setter/Getter方法来完成注入,可读性和灵活性都很高,它不需要使用声明式构造方法,而是使用 Setter 注入直接设置相关的值,实现示例如下:
<bean id="person" class="org.springframework.beans.Person">
<property name="id" value="1"/>
<property name="name" value="Java"/>
</bean>
(3) 接口注入
接口注入方式是比较古老的注入方式,因为它需要被依赖的对象实现不必要的接口,带有侵入性,因此现在已经被完全舍弃了,所以本文也不打算做过多的描述,大家只要知道有这回事就行了。
IOC的原理?(IOC容器是怎么工作的?)
几个概念
Bean:在 Spring 中,构成应用程序主干并由Spring IOC容器(ApplicationContext)实例化、组装(assembled)和管理的对象称为bean。
BeanDefinition:是Spring中关于bean的元数据的定义和描述。
元数据:即描述数据的数据。元数据本身不具备任何可执行能力,只能通过外界代码来对这些元数据行解析后进行一些有意义操作。
配置元数据:无论是通过xml配置、注解配置还是Java配置的方式(来注册Bean),都被称为配置元数据,Spring IOC容器解析这些配置元数据进行Bean初始化、配置和管理依赖。
工作原理:
(1)准备配置文件:配置文件中声明Bean定义也就是为Bean配置元数据。
(2)Spring IOC容器解析配置元数据进行Bean初始化、配置和管理依赖:Spring IOC容器的Bean Reader读取并解析配置文件,根据定义生成BeanDefinition配置元数据对象,Spring IOC容器根据BeanDefinition进行Bean初始化、配置和组装。
(3)实例化IOC容器:由客户端实例化容器,获取需要的Bean。
@Test public void testHelloWorld() { //1、读取配置文件实例化一个IoC容器 ApplicationContext context = new ClassPathXmlApplicationContext("helloworld.xml"); //2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现” HelloApi helloApi = context.getBean("hello", HelloApi.class); //3、执行业务逻辑 helloApi.sayHello(); }
解释一下AOP中的名词
1) Aspect :将对多个对象产生影响的公共行为封装为一个可重用的模块,这个模块叫做”切面(Aspect)”,比如日志管理就是一个切面;
2) Join point :连接点,指方法,类里面哪些方法可以被增强,这些方法被称为连接点,在spring的AOP中,指的是所有现有的方法;
3) Advice :通知,在切面的某个特定的连接点(Join point)上执行的操作。
通知分为:
前置通知:在原来方法之前执行。
后置通知:在原来的方法之后执行。特点:可以得到被增强方法的返回值。
环绕通知:在方法之前和方法之后执行。
异常通知:目标方法出现异常执行,如果方法没有异常,不会执行。特点:可以获得异常的信息。
最终通知:指的是无论是否有异常,总是被执行。
4) Pointcut :切入点是指我们要对哪些连接点(Join point)进行拦截。分为注解式拦截(拦截带有某个注解的方法)和方法规则拦截(拦截指定的方法)。
spring aop的原理吗?
spring aop就是基于代理模式中的动态代理实现的,其中动态代理的实现方式有JDK Proxy和CGLib(Code Generation Library)两种,Spring框架中同时使用了两种动态代理JDKProxy和CGLib,源码中有个创建AOP代理类的方法createAopProxy()中,会判断目标类是否为接口,如果是接口的话,Spring 就会使用 JDK Proxy,去创建代理对象,其他情况就会使用CGLIB动态代理(Code Generation Library 代码生成库),生成一个被代理对象的子类作为代理。
我们在调用getBean()方法的时候返回的其实是代理类的实例,而这个代理类在Spring中使用的是JDKProxy或CgLib实现的,它的核心代码在 DefaultAopProxyFactory#createAopProxy(...) 中,源码如下:
常见面试题?
(1) 说说你对spring的理解?
(2) 使用Spring框架有什么好处呢?
(3) 使用Spring框架有什么好处呢?
(4) 谈一谈你对 IoC 和 DI 的理解。
(5) Spring IoC 有哪些优势?
(6) IoC 的注入方式有哪些?
(7) 谈一谈你对 AOP 的理解。
参考/好文
(1) 书籍 -- SpringBoot实战 -- 汪云飞 编著
(2) 聊一聊Spring中的线程安全性 --
https://juejin.im/post/5a0045ef5188254de169968e
(3)《今天面试了吗》 - Spring
https://juejin.im/post/5e6d993cf265da575b1bd4af
(4) 拉钩课程 -- Java源码剖析
https://kaiwu.lagou.com/course/courseInfo.htm?courseId=59