目录
5、BeanFactory 和ApplicationContext有什么区别?
12、ApplicationContext 通常的实现是什么?
13、Bean 工厂和 Application contexts 有什么区别?
16、哪种依赖注入方式你建议使用,构造器注入,还是setter方法注入?
26、你可以在 Spring 中注入一个 null 和一个空字符串吗?
27、什么是基于java的spring注解配置?给一些注解的例子
1、如何实现一个IOC容器
1、配置文件配置包扫描路径
2、递归包扫描获取.class文件
3、反射、确定需要交给IOC管理的类
4、对需要注入的类进行依赖注入
配置文件中指定需要扫描的包路径
定义一些注解,分别表示访问控制器,业务服务层,数据持久层,依赖注入注解、获取配置文件注解
从配置文件中获取需要扫描的包路径,获取到当前路径下的文件信息及文件夹的信息,我们将当前路径下所有.class结尾文件放到Set集合进行存放。
遍历这个set集合,获取在类上指定注解上的类,并交给IOC容器,定义一个安全的Map用来储存这些对象
遍历这个IOC容器,获取到每一个类的实例,判断里面有无依赖其他类的实例,然后进行递归注入。
2、spring是什么?
轻量级的开源的j2ee框架,它是一个容器框架,用来装javabean(java对象),中间层框架(万能胶)可以起到一个连接作用,比如说把strus和hibernate结合在一起运用,可以让我们的企业开发更快,更简洁。
spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。
从大小与开销二个方面而言spring都是轻量级的
通过控制反转的技术达到松耦合的目的。
提供了面向切面的丰富支持,允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发
包含并管理应用对象(Bean)的配置和生命周期,这个意义上是一个容器。
将简单的组件配置,组合成为更复杂的应用,这个意义上是一个框架。
3、对AOP的理解
系统是由很多的不同组件组成的,每一个组件各负责一块特定功能。除了实现自身核心功能之外,这些组件还经常承担着额外的职责。例如日志,事务管理和安全这样的核心业务的组件中去。这些系统服务经常被称为横切关注点,因为它们会跨越系统的多个组件。
当我们需要为分散的对象引入公共行为时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合从左到右的关系,例如日志功能。
日志代码往往水平地散布在所有的对象层次中,而与它散布到的对象核心功能毫无关系。
在OOP设计中,它导致大量代码的重复,而不利于各个模块的重用。
AOP:将程序的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。AOP可以对某个对象或者某些对象的功能进行增强,可以在执行某个方法之前额外的做一些事情,在某个方法执行之后额外的做一些事情。
4、谈谈你对IOC的理解
容器概念、控制反转、依赖注入
IOC容器:实际上就是个map(key,value),里面存放的是各种对象(在xml里配置的bean节点,@repository,@Service,@Controller,@component),在项目启动的时候会读取配置文件里面的bean节点,根据全限定类名使用反射创建对象放到map里,扫描到打上注释的类还是通过反射创建对象放到map里。
这个时候map里就有各种对象了,接下来我们在代码里需要用到里面的对象时,再通过DI注入(autowired、resource等注解,xml里bean节点内的ref属性,项目启动时候会读取xml节点ref属性根据id注入,也会扫描这些注解,根据类型或者id注入;id就是对象名)。
控制反转:
没有引入IOC容器之前,对象A依赖对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建对象B。无论是创建还是使用对象B,控制权都在自己手上。
引入IOC容器之后,对象A与对象B之间失去了直接联系,当对象A运行需要对象B的时候,IOC容器会自动创建一个对象B注入到对象A需要的地方。
通过前后的对比,不难看出来;对象A获取依赖对象B的过程,由自动行为变成被动行为,控制权倒转过来了,这就是控制反转这个名词的由来。
全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似于“粘合剂”的作用,把系统中所有的对象粘合起来一起发挥作用,如果没有这个“粘合剂”,对象与对象直接会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来。
依赖注入:
“获取依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理者变为由IOC容器主动注入。依赖注入是实现IOC的方法,就是IOC容器在运行期间,动态地将某些依赖关系注入到对象之中。
5、BeanFactory 和ApplicationContext有什么区别?
Bean 工厂是工厂模式的一个实现, 提供了控制反转功能, 用来把应用的配置和依赖从正真的应用代码中分离。 最常用的 BeanFactory 实现是 XmlBeanFactory 类。
ApplicationContext是BeanFactory子接口
ApplicationContext提供了更完善的功能
1、继承MessageSource,因此支持国际化。
2、统一的资源文件访问方式。
3、提供在监听器中注入bean的事件。
4、同时加载多个配置文件。
5、载入多个(有继承关系)上下文,使得每一个上下文都专注于一个特定层次,比如应用的web层。
BeanFactroy采用的是延时加载形式来注入Bean的,即只有在使用某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的spring的配置问题。如果bean的某个属性没有注入,BeanFactory加载后,直至第一次使用调用getBean方法才会抛出异常。
ApplicationContext,它是在容器启动时,一次性创建所有的Bean。这样,在容器启动时,我们就可以发现spring中配置错误,这样有利于检查所依赖属性是否注入。ApplicationContext启动后预加载所有实例Bean,通过预加载实例bean,确保当你需要的时候,你就不需要等待,因为它们已经创建好了
相对于基本的BeanFactory,ApplicationContext唯一的不足是占用的内存空间。当应用程序配置Bean较多时,启动比较缓慢。
BeanFactory通常以编程的方式来创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。
BeanFactory和ApplicationContext都支持BeanPostProcessor,BeanFactoryPostProcessor的使用,但两个之间的区别就是,BeanFactory需要手动配置,而ApplicationContext则自动注册。
6、描述一下SpringBean的生命周期?
1、解析类得到BeanDefinition
2、如果有多个构造方法,则要推断构造方法
3、确定好构造方法后,进行实例化得到一个对象
4、对对象中的加入@Authowired注解的属性进行属性填充
5、回调Aware方法,比如BeanNameAware,BeanFactoryAware
6、调用BeanPostProcessor的初始化的方法
7、调用初始化方法
8、调用BeanPostProcess的初始化后的方法,在这里会进行AOP
9、如果当前创建的bean是单例的则会把bean放入单例池
10、使用bean
11、spring容器关闭调用DisposableBean中destory()方法
7、解释下spring支持的几种bean的作用域
singleton:默认,每个容器中只有一个bean的实例,单例的模式由Beanfactory自身来维护。该对象的生命周期是与springIOC容器一致的(但在第一次被注入时候才会创建)。
singleton : bean 在每个 Spring ioc 容器中只有一个实例。
prototype: 一个 bean 的定义可以有多个实例。 request: 每次 http 请求都会创建一个 bean, 该作用域仅在基于 web 的 SpringApplicationContext 情形下有效。
session: 在一个 HTTP Session 中, 一个 bean 定义对应一个实例。 该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。
global-session: 在一个全局的 HTTP Session 中, 一个 bean 定义对应一个实例。 该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。 缺省的 Spring bean 的作用域是 Singleton。
8、spring框架中的单例Bean是线程安全的么?
不, Spring 框架中的单例 bean 不是线程安全的。
spring中的bean默认是单例模式的,框架并没有对bean进行多线程的封装处理。
如果Bean是有状态的,那就需要开发人员自己来进行线程安全的保证,最简单的办法就是改变bean的作用域把“Singleton”改为“prototype”这样每次请求bean就相当于是new Bean()这样就可以保证线程的安全了。
有状态就是有数据存储功能
无状态就是不会保存数据 controller,service和dao层本身就不是线程安全的,只是如果调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。
Dao会操作数据库Connection,Connection是带有状态的,比如说数据库事务,spring的事务管理器使用Threadlocal为不同线程维护了一套独立的Connection副本,保证线程之间不会相互影响(spring是如何保证事务获取同一个Connection的)
不要在bean中声明任何有状态的实例变量或类常量,如果必须如此,那么就使用ThreadLocal把变量变为线程私有的,如果bean的实例变量或类变量需要多个线程之间共享,那么就只能使用synchronized,lock,CAS等这些线程同步的方法了。
9、使用spring框架的好处是什么?
轻量:spring是轻量的,基本的版本大约2MB
控制反转:spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或者查找依赖的对象们。
面向切面的编程(AOP): Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
容器:spring包含并管理应用中对象的生命周期和配置。
MVC框架:Spring的WEB框架是个精心设计的框架,是web框架的一个很好的替代品。
事务管理:Spring提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)
异常处理:spring提供了方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked异常
10、Spring 由哪些模块组成?
Core module
Bean module
Context module
Expression Language module
JDBC module
ORM module
OXM module
Java Messaging Service(JMS) module
Transaction module
Web module
Web-Servlet module
Web-Struts module
Web-Portlet module
11、核心容器(应用上下文)模块
这是基本的spring模块,提供spring框架的基本功能,BeanFactory是任何以spring为基础的应用的核心。spring框架建立在此模块之上,它使spring成为一个容器。
12、ApplicationContext 通常的实现是什么?
FileSystemXmlApplicationContext : 此容器从一个 XML 文件中加载 beans的定义, XML Bean 配置文件的全路径名必须提供给它的构造函数。
ClassPathXmlApplicationContext: 此容器也从一个 XML 文件中加载 beans的定义, 这里, 你需要正确设置 classpath 因为这个容器将在 classpath 里找bean 配置。
WebXmlApplicationContext: 此容器加载一个 XML 文件, 此文件定义了一个WEB 应用的所有 bean。
13、Bean 工厂和 Application contexts 有什么区别?
Application contexts 提供一种方法处理文本消息, 一个通常的做法是加载文件资源( 比如镜像) , 它们可以向注册为监听器的 bean 发布事件。 另外, 在容器或容器内的 对 象 上 执 行 的 那 些 不 得 不 由 bean 工 厂 以 程 序 化 方 式 处 理 的 操 作 , 可 以 在Application contexts 中 以 声 明 的 方 式 处 理 。 Application contexts 实 现 了MessageSource 接口, 该接口的实现以可插拔的方式提供获取本地化消息的方法。
14、一个Spring的应用看起来像什么?
一个定义了一些功能的接口
这实现包括属性,它的Setter,getter方法和函数等
spring AOP
Spring的XML配置文件
使用以上功能的客户端程序
15、有哪些不同类型的IOC(依赖注入)方式?
构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个其他类的依赖。
Setter 方法注入:Setter方法注入是容器通过调用无参数或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。
16、哪种依赖注入方式你建议使用,构造器注入,还是setter方法注入?
你两种依赖方式都可以使用,构造器注入和setter方法注入。最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。
17、什么是spring beans?
Spring beans 是那些形成spring应用的主干的java对象。它们被spring IOC容器初始化,装配,和管理。这些beans通过容器中的元数据创建。比如,以XML文件中<bean/>的形式定义。
spring框架定义的beans都是单件beans。在bean tag中有个属性"singleton",如果它被赋予TRUE,bean就是单件,否则就是一个prototype bean。默认是TRUE,所以所有弟子spring框架中的beans缺省都是单件。
18、一个spring bean定义 包含什么?
一个springbean的定义包含容器必知的所有元数据,包括如何创建一个bean,它的生命周期详情以及它的依赖。
19、如何给spring容器提供配置元数据?
这里有三种重要的方法给spring容器提供配置元数据
xml配置文件
基于注解配置
基于java配置
20、什么是spring的内部bean?
当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,为了定义 inner bean,在spring的基于xml的配置元数据中,可以在<property/>或<constructor-arg/>元素内使用<bean/>元素,内部bean通常是匿名的,他们的Scope一般是prototype。
21、在spring中如何注入一个java集合?
spring 提供以下几种集合的配置元素
<list> 类型用于注入一列值,允许有相同的值 <set>类型用于注入一组值,不允许有相同的值
<map> 类型用于注入一组键值对,键和值都可以为任意类型。
<props>类型用于注入一组键值对,键和值都只能为string类型
22、什么是bean装配?
装配,或bean装配是指在spring容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,如何通过依赖注入来把它们装配到一起。
23、什么是bean的自动装配?
Spring 容 器 能 够 自 动 装 配 相 互 合 作 的 bean , 这 意 味 着 容 器 不 需 要<constructor-arg>和<property>配置, 能通过 Bean 工厂自动处理 bean 之间的协作。
24、解释不同方式的自动装配
有五种自动装配的方式, 可以用来指导 Spring 容器用自动装配方式来进行依赖注入no: 默认的方式是不进行自动装配, 通过显式设置 ref 属性来进行装配。 byName: 通过参数名 自动装配, Spring 容器在配置文件中发现 bean 的 autowire属性被设置成 byname, 之后容器试图匹配、 装配和该 bean 的属性具有相同名字的bean。 byType: 通过参数类型自动装配, Spring 容器在配置文件中发现 bean 的 autowire属性被设置成 byType, 之后容器试图匹配、 装配和该 bean 的属性具有相同类型的 bean。 如果有多个 bean 符合条件, 则抛出错误。 constructor: 这个方式类似于 byType, 但是要提供给构造器参数, 如果没有确定的带参数的构造器参数类型, 将会抛出异常。 autodetect: 首先尝试使用 constructor 来自动装配, 如果无法工作, 则使用 byType方式。
25、自动装配有哪些局限性?
自动装配的局限性是:
重写:你仍需用<constructor-arg>和<property>配置来定义依赖,意味着总要重写自动装配。
基本数据类型:你不能自动装配简单的属性,如基本数据类型,string字符串、和类。模糊特性:自动装配不如显式装配精确,建议使用显式装配。
26、你可以在 Spring 中注入一个 null 和一个空字符串吗?
可以。
27、什么是基于java的spring注解配置?给一些注解的例子
基于java的配置,允许在少量的java注解的帮助下,进行你的大部分spring配置而非通过XML文件。
以@Configuration 注解为例, 它用来标记类可以当做一个 bean 的定义, 被 SpringIOC 容器使用。 另一个例子是@Bean 注解, 它表示此方法将要返回一个对象, 作为一个 bean 注册进 Spring 应用上下文。
28、spring框架中单例Bean是线程安全的么?
spring中的bean默认是单例模式的,框架并没有对bean进行多线程的封装处理。
如果Bean是有状态的,那就需要开发人员自己来进行安全保证,最简单的办法就是改变bean的作用域把“Singleton”改为“prototype”这样每次请求Bean就相当于是new Bean() 这样就可以保证线程安全了。
有状态就是数据存储功能
无状态就是不保存数据,controller、service和dao层本身并不是线程安全的,只是如果调用里面的方法,并且多线程调用一个实例方法,会在内存中复制一个变量,这是自己线程的工作内存,是安全的。
Dao会操作数据库Connection,Connection是带有状态的,比如说数据库事务,spring的事务管理器使用ThreadLocal为不同的线程维护已一套独立的Connection副本,保证线程之间不会相互影响(spring是如何保证事务获取同一个Connection的。)
不要在bean中声明有状态的实例变量或者类变量,如果必須如此,那么就使用ThreadLocal把变量变为私有的,如果bean的实例变量或者类需要多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现同步线程的方法了。
29、Spring框架中用到了哪些设计模式?
# 简单工厂:由一个工厂类根据传入的参数,动态决定应该创建哪个产品类。
# spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否在传入参数后创建还是传入参数前创建这个根据具体情况来定。
# 工厂方法:实现 FactoryBean接口的bean是一类叫做factory的bean。其特点是,spring会在使用getBean()调用获得bean时,会自动调用该bean的getObject()方法,所以返回的不是factory这个bean,而是这个bean.getObject()方法的返回值。
# 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
# spring对单例的实现,spring中的单例模式完成了后半句话,即提供了全局访问点BeanFactory,但没有从构造器级别去控制单例,这是因为spring管理的是任意的java对象。
# 适配器模式:spring定义了一个适配接口,使得每一种controller有一种对应的适配器实现类,让适配器代替controller执行相应的方法,这样在扩展controller时,只需要添加一个适配器类就完成了springmvc的扩展了。
# 装饰器模式:动态地给一个对象添加额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
# spring中用到的包装类模式在类名上有两种表现;一种是类名含有wrapper,另一种类名中含有Decorator。
# 动态代理:切面在应用的时刻被织入,一般情况下,在织入切面时,AOP容器会为目标对象创建动态的创建一个代理对象,springaop就是以这种方式织入切面的。
# 观察者模式
# spring的事件驱动模型使用观察者模式,spring中observer模式常用的地方是listener的实现
# 策略者模式
# spring框架的访问Resource接口,该接口提供了更强的资源访问能力,spring框架本身使用了Resource接口来访问底层资源。