1. Spring框架优点?
(1).方便解耦,简化开发
通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
(2).AOP(面向切面)编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
(3).声明式事务的支持
在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
(4).方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
(5).方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
(6).降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。
(7).Java 源码是经典学习范例
Spring的源码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。Spring框架源码无疑是Java技术的最佳实践范例。如果想在短时间内迅速提高自己的Java技术水平和应用开发水平,学习和研究Spring源码将会使你收到意想不到的效果。
2. 谈谈你对spring IOC和DI的理解,它们有什么区别?
IoC, Inversion of Control, 控制反转
首先想说说IoC(Inversion of Control,控制反转)。这是Spring的核心,贯穿始终。所谓IoC,对于Spring框架来说,就是由Spring来负责控制对象的生命周期和对象间的关系。这是什么意思呢,举个简单的例子,我们是如何找女朋友的?常见的情况是,我们到处去看看找到自己喜欢的,然后打听她们的兴趣爱好、qq号、电话号………,想办法认识她们,投其所好送其所要……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序开发也是如此,在一个对象中,如果要使用另外的对象,就必须得到它(自己new一个),使用完之后还要将对象销毁,对象始终会和其他的接口或类耦合起来。
那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个要求的列表,告诉它我想找个什么样的女朋友,然后婚介就会按照我们的要求,提供一个女孩,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在Spring容器中登记,告诉Spring你是个什么东西,你需要什么东西,然后Spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 Spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被Spring控制,所以这叫控制反转。
DI(依赖注入)
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉Spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,Spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,Spring就是通过反射来实现注入的。
总结:
IOC是一种叫做“控制反转”的设计思想。
a、较浅的层次——从名字上解析
“控制”就是指对 对象的创建、维护、销毁等生命周期的控制,这个过程一般是由我们的程序去主动控制的,如使用new关键字去创建一个对象(创建),在使用过程中保持引用(维护),在失去全部引用后由GC去回收对象(销毁)。
“反转”就是指对 对象的创建、维护、销毁等生命周期的控制由程序控制改为由IOC容器控制,需要某个对象时就直接通过名字去IOC容器中获取。
b、更深的层次——提到DI,依赖注入,是IOC的一种重要实现
一个对象的创建往往会涉及到其他对象的创建,比如一个对象A的成员变量持有着另一个对象B的引用,这就是依赖,A依赖于B。IOC机制既然负责了对象的创建,那么这个依赖关系也就必须由IOC容器负责起来。负责的方式就是DI——依赖注入,通过将依赖关系写入配置文件,然后在创建有依赖关系的对象时,由IOC容器注入依赖的对象,如在创建A时,检查到有依赖关系,IOC容器就把A依赖的对象B创建后注入到A中(组装,通过反射机制实现),然后把A返回给对象请求者,完成工作。
c、IOC的意义何在?
IOC并没有实现更多的功能,但它的存在使我们不需要很多代码、不需要考虑对象间复杂的耦合关系就能从IOC容器中获取合适的对象,而且提供了对 对象的可靠的管理,极大地降低了开发的复杂性。
3. Spring配置bean实例化有哪些方式?
3.1通过无参构造
xml文件中配置:
需要被Spring来管理的类:
3.2通过有参构造:
xml配置文件:
需要被Spring来管理的类:
3.3通过静态工厂
静态工厂对象
xml配置文件
3.4通过实例(非静态)工厂
工厂对象:
xml配置文件:
4. 请介绍一下Spring框架中bean的生命周期和作用域
在Spring中,简单地讲,bean就是由IoC容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。
默认情况下, 同一个<bean>只会创建一个对象.,即Spring默认的作用域是singleton
作用域:
bean的生命周期:
Spring中bean的实例化过程(不好意思,我盗图了):
与上图类似,bean的生命周期流程图:
bean实例生命周期的执行过程如下:
0、Spring对bean进行实例化,默认bean是单例;
1、Spring对bean进行依赖注入(DI);
2、如果bean实现了BeanNameAware接口,spring将bean的id传给setBeanName()方法;
3、如果bean实现了BeanFactoryAware接口,spring将调用setBeanFactory方法,将BeanFactory实例传进来;
4、如果bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用上下文的引用传入到bean中;
5、如果bean实现了BeanPostProcessor接口,它的postProcessBeforeInitialization方法将被调用;
6、如果bean实现了InitializingBean接口,spring将调用它的afterPropertiesSet接口方法,类似的如果bean使用了init-method属性声明了初始化方法,该方法也会被调用;
7、如果bean实现了BeanPostProcessor接口,它的postProcessAfterInitialization接口方法将被调用;
8、此时bean已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁;
9、若bean实现了DisposableBean接口,spring将调用它的distroy()接口方法。同样的,如果bean使用了destroy-method属性声明了销毁方法,则该方法被调用;
总结:
其实很多时候我们并不会真的去实现上面说描述的那些接口,那么下面我们就除去那些接口
单例模式(singleton),默认情况下
当scope=”singleton”,即默认情况下,会在启动容器时(即实例化容器时)时实例化(创建)。但我们可以指定bean节点的lazy-init=”true”,懒加载,来延迟初始化bean,这时候,只有在第一次获取bean时才会初始化bean,即第一次请求该bean时才初始化。如下配置:
<bean id="serviceImpl" class="com.chenpeng.service.ServiceImpl" lazy-init="true"/>
<bean>标签详解:
<bean>用于管理对象(创建对象)
1. id
当前bean的唯一标识, 尽量遵循规范: 字母, 数字, 下划线
2. class
用于描述类型的全限定路径
3. factory-bean
用于引用要使用的实例工厂对象
4. factory-method
用于指定要使用的工厂中的方法名
5. name
用于定义别名(外号, 昵称), 支持特殊符号(不要出现#$)
别名可以通过: 空格, 逗号, 分号进行分隔
6. init-method
初始化方法, 在创建对象后, 使用对象(getBean)前, spring自动调用的方法
7. destroy-method
销毁时自动调用的方法.
8. parent
用于描述继承关系, 常用于简化配置
9. abstract
用于描述抽象的bean. 表示这个bean标签不能通过getBean得到对象, 通常要配合parent使用
可选值:
true: 当前bean为抽象bean
false:默认值, 当前bean为非抽象bean
10. lazy-init
延迟初始化. 默认情况下, Spring在容器被加载时就创建对象. 延迟初始化表示在容器被加载时, Spring不创建该对象, 而是在getBean获取对象时才去创建. 可选值:
true:
false:默认值
11. scope
作用域, 用于表示对象的创建个数和使用范围.可选值:
singleton: 默认值, 表示只创建一个对象
prototype: 容器加载时不创建对象, getBean的时候创建对象, 表示每次获取对象都重新创建一个新的对象
request: 需要配合spring-web.jar包使用, 表示一次客户端请求中, 对象是单例的.
session: 需要配合spring-web.jar包使用, 表示一次会话中, 对象是单例的.
global session: 需要配合spring-web.jar, spring-webmvc-portlet.jar包使用, 表示在同一个globalsession中, 对象是单例的
application: 需要配合spring-web.jar包使用, 表示整个应用程序中, 对象是单例的.
5. Bean注入属性有哪几种方式?
1.Set注入
类中:
xml配置文件中:
2.构造器注入(这种方式的注入是指带有参数的构造函数注入)
类中:
xml配置文件:
3.静态工厂的方法注入( 静态工厂: 不需要创建工厂对象, 直接通过工厂类, 调用静态方法就可以得到目标对象)
类中
/**
* 静态工厂: 不需要创建工厂对象, 直接通过工厂类, 调用静态方法就可以得到目标对象
*
* @author chenpeng
*
*/
public class UserStaticFactory {
public static User getInstance() {
System.out.println("静态工厂获取对象");
return new User();
}
}
xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置使用静态工厂创建User对象 -->
<bean id="user"
class="com.chenpeng.factory.UserStaticFactory"
factory-method="getInstance" />
</beans>
4.实例工厂的方法注入
类:
/**
* 实例工厂
* 必须先创建工厂对象, 然后通过工厂对象调用方法得到目标对象
*
* @author chenpeng
*
*/
public class UserInstanceFactory {
public UserInstanceFactory() {
System.out.println("实例工厂对象创建");
}
public User getInstance(String name) {
System.out.println("实例工厂获取对象...");
return new User(name);
}
}
xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置工厂对象 -->
<bean id="factory" class="com.chenpeng.factory.UserInstanceFactory"></bean>
<!-- 配置使用工厂创建User对象 -->
<bean id="user" factory-bean="factory" factory-method="getInstance">
<constructor-arg name="name" value="李四" />
</bean>
</beans>
总结:
Spring IOC注入方式用得最多的是(1)(2)种
6. @Autowired和@Resource之间的区别
@Resource和@Autowired都是做bean的注入时使用,
其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。
@AutoWired: 是spring提供的注解, 默认先按类型进行注入, 如果找到则注入, 找不到再按照名称进行注入; 如果找到多个匹配的类型, 抛出异常.
@Resource: 是javax.annotation包中提供的注解, 默认先按照名称注入, 名称一致则注入, 如果没有同名的, 再按照类型注入.