1.Spring
Spring 框架现在是 Java 后端框架家族里面最强大的一个,其拥有 IOC 和 AOP 两大利器,大大简化了软件开发复杂性。并且,Spring 现在能与所有主流开发框架集成,可谓是一个万能框架,Spring 让 JAVA 开发变得更多简单。
面试真题:
(1)什么是控制反转(IOC)?什么是依赖注入?
(2)请解释下Spring中的IOC?
(3)将Spring配置到你的应用中共有几种方法?
(4)怎样用注解的方式配置Spring?
(5)描述Spring Bean的生命周期?
(6)描述Spring中各种Bean的范围?
(7)什么是Spring的嵌入beans?
(8)Spring框架中的单例bean是否是线程安全的?
(9)请举例说明如何用Spring注入一个Java的集合类?
(10)请举例说明如何在Spring的Bean中注入一个java.util.Properties?
(11)请解释Spring的Bean的自动生成原理?
(12)请辨析自动生成Bean之间模块的区别?
(13)如何开启基于基于注解的自动写入?
(14)请举例说明@Required注解?
(15)请举例说明@Autowired注解?
(16)请举例说明@Qualifier注解?
(17)请说明构造器注入和setter方法注入之间的区别?
(18)Spring框架中不同类型event有什么区别?
(19)FileSystemResource和ClassPathResource有何区别?
(20)请列举Spring框架中用了哪些设计模式?
(1)什么是控制反转(IOC)?什么是依赖注入?
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
●谁依赖于谁:当然是应用程序依赖于IoC容器;
●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
(2)将Spring依赖注入的三种实现方式?
●构造器注入
●Setter方法注入
●接口注入
(3)将Spring配置到你的应用中共有几种方法?
●基于xml的配置
●基于注解的配置
●基于java的配置
(4)怎样用注解的方式配置Spring?
使用注解的方式使我们无需在XML中配置一个Bean引用,更加简单和方便。
注解配置默认情况下在Spring中是关闭的,我们需要在配置文件中使用<context:annotation-config/>
激活它。
@Required
注解应用于bean属性的setter方法@Autowired
注解可以应用到bean属性的setter方法,非setter方法,构造函数和属性@Qualifier
,通过指定确切的将被引用的bean,@Autowired
和@Qualifier
注解可以用来删除混乱- JSR-250 Annotations,Spring支持JSR-250的基础的注解,其中包括了
@Resource
,@PostContruct
和@PreDestory
注解
@Required注解
@Required
注解应用于bean属性的setter方法,它表示受影响的bean属性在配置时必须放在XML配置文件中,否则容器就会抛出一个BeanInitializationException
异常。
@Required
注解用于注解属性的setter方法,如果一个属性的setter方法被@Required
注解,则表示在XML配置中,该属性一定要注入值,否则会报异常。
setter方法中的@Autowired
当Spring遇到一个在setter方法中使用的@Autowired
注解,它会通过byType
的方法自动为该属性注入值。
属性中的@Autowired
注解
我们可以直接在属性上运用@Autowired
注解,这样我们可以无需为该属性写setter方法,Spring会自动为该属性注入值。
构造方法中的@Autowired
注解
默认情况下,@Autowired
注解意味着依赖是必须的,它类似于@Required
注释,然而,你可以使用@Autowired
的(required=false)
选项关闭默认行为。
@Qualifier
注解
当我们创建多个具有相同类型的bean时,并且想要用一个属性只为它们其中的一个进行装配,在这种情况下,我们可以结合使用@Qualifier
和@Autowired
注解通过指定哪一个真正的bean将会被装配来消除混乱。
@Resource
注解
我们可以在字段中或者setter方法中使用@Resource
注解,它使用一个name
属性,该属性以一个bean名称的形式被注入,也就是说,它遵循byName
形式的自动装配。
@Resource
与@Autowired
注解的用法很类似,它们的区别如下:
@Autowired
注解为Spring提供的注解,只按照byType
方式注入,默认情况下,它要求依赖对象必须存在,如果允许为null
,可以设置它的required
属性为false
,如果我们想按照byName
方式来装配,可以结合@Qualifier
注解一起使用;@Resource
为J2EE提供的注解,它有两个重要的属性:name
和type
。而默认情况下,@Resource
注解按照byName
的方式来装配。@Resource
的装配顺序是这样的:
- 如果同时指定了
name
和type
,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。 - 如果指定了
name
,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。 - 如果指定了
type
,则从上下文中找到类型匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。 - 如果既没有指定
name
,又没有指定type
,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
- 如果同时指定了
(5)怎样基于java配置的方式配置Spring?
- Spring对Java配置的支持是由
@Configuration
注解和@Bean
注解来实现的。由@Bean
注解的方法将会实例化、配置和初始化一个新对象,这个对象将由Spring的IoC容器来管理。@Bean声明所起到的作用与<bean/>
元素类似。被@Configuration
所注解的类则表示这个类的主要目的是作为bean定义的资源。被@Configuration
声明的类可以通过在同一个类的内部调用@Bean
方法来设置嵌入bean的依赖关系。
(8)Spring框架中的单例bean是否是线程安全的?
这取决于你的bean是否是有状态的;如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。
默认情况下Spring的bean都是单例的,所以就一般业务开发中bean都是无状态的(比如DAO层),所以是线程安全的。
但你的bean是有状态的话(比如你要在bean中存储某些数据),就需要将bean的scope改成prototype,让每次请求都相当于重新new一个bean,这样就是线程安全的了。
Spring作用域(scope)的配置区别:
- 非线程安全:Singleton(默认): Spring容器只存在一个共享的bean实例。对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。
- 线程安全: Prototype: 每次对bean的请求都会创建一个新的bean实例。对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。
使用实例:
- DAO层的实现类推荐设置scope="singleton",这些类没有状态,只需用singleton只需维护一个实例,可提高性能。
- Struts2的action类推荐设置scope="prototype",action显然是有状态的,需要每次创建一个新的实例,保证线程安全。
拓展:
有状态对象(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。
无状态对象(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean 的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean 并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。
27. 解释Spring框架中bean的生命周期。
- Spring容器 从XML 文件中读取bean的定义,并实例化bean。
- Spring根据bean的定义填充所有的属性。
- 如果bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanName方法。
- 如果Bean 实现了 BeanFactoryAware 接口, Spring传递beanfactory 给setBeanFactory 方法。
-
如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们。
- 如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。
- 如果有BeanPostProcessors 和bean 关联,这些bean的postProcessAfterInitialization() 方法将被调用。
- 如果bean实现了 DisposableBean,它将调用destroy()方法。