spring框架总结
1. Spring是什么?及其特点。
Spring框架是一个开源的轻量级容器框架。主要有三大特点:
(1) 容器。Spring框架是一个容器,能够管理项目中的所有对象。
(2) IOC(控制反转)。Spring将创建对象的方式反转了,从程序员自己创建反转给了程序。
DI(依赖注入) 需要有IOC环境,在Spring创建Bean对象时,动态的将依赖对象注入到Bean对象中去。依赖注入和控制反转最大的好处就是解耦合。
(3) AOP(面向切面)。面向切面编程,简而言之,就是将纵向重复的代码横向抽取出来,主要体现在为容器中管理的对象生成动态代理对象。
2. applicationContext & BeanFactory区
BeanFactory
BeanFactory是一个接口,用来实例化、配置和管理Bean对象,里面有一个getBean()方法获取Bean对象。
使用BeanFactory(拿到Bean对象) 三种方法:
方式一:根据id拿,可以确定
方式二:也是根据id和Class实例,可以确定(不需要强转)
方式三:根据类型,现在有两个类型相等,无法确定(报错)
//第一步:拿到资源配置文件 Resource resource = new ClassPathResource("applicationContext.xml"); //第二步:拿到核心对象 BeanFactory BeanFactory factory = new XmlBeanFactory(resource); //通过BeanFactory获取Bean对象的三种方式: //第一种:通过xml文件中配置的id获取对象 Object bean1 = factory.getBean("ud"); ((UserDaoImpl)bean1).add(); //第二种:通过xml文件中配置的id及类的字节码对象 获取对象 UserDaoImpl bean2 = factory.getBean("ud",UserDaoImpl.class); bean2.add(); //第三种:通过类的字节码对象 获取对象. UserDaoImpl bean3 = factory.getBean(UserDaoImpl.class); bean3.add(); //依赖注入(DI)/控制反转(IOC) //三种方式拿到的Bena对象在内存中的地址都相同 System.out.println(bean1==bean2 && bean2==bean3);//true
以上三种方式是spring框架底层拿对象的方式,我们不会去用这些方式去直接获取bean对象
获取spring核心对象的首选方式:
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过该对象的getBean()获取具体的bean对象
UserDaoImpl bean4 = ac.getBean("ud",UserDaoImpl.class);
UserDaoImpl bean5 = ac.getBean("ud",UserDaoImpl.class);
System.out.println(bean4 == bean5); //true
区别:
1. ApplicationContext是BeanFactory的子类,拥有更多的功能与方法。比如:提供了文本信息解析工具,包括I18N(国际化)的支持;提供了载入文件资源的通用方法;提供了发送事件的功能。
2. ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。
而BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。
3. BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
扩展:我们在使用ApplicationContext的时候,可以通过配置让它也变成与BeanFactory一样的懒加载:
配置一:让所有Bean都变成懒加载
<beans xmlns="http://www.springframework.org/schema/beans"
....
default-lazy-init="true">
<bean ></bean>
</beans>
配置二:让其中一个Bean变成懒加载
<bean ></bean>
3. 请解释Spring Bean的生命周期?
先简单了解:
生命周期属性(了解)———初始化和销毁
(1)配置一个方法作为生命周期初始化方法,spring会在对象创建之后立刻调用 init-method
(2)配置一个方法作为生命周期的销毁方法,spring容器在关闭并销毁所有容器中的对象之前调用destory-method
<bean init-method=“init” destory-method=“destory”></bean> 对应注解为@PostConstruct
<bean name=“hello” class=“完整类名”></bean> 对应注解为@PreDestory
Spring中Bean的管理是其最基本的功能,根据下面的图来了解Spring中Bean的生命周期:
解说:
(1)BeanFactoryPostProcessor的postProcessorBeanFactory()方法:若某个IoC容器内添加了实现了BeanFactoryPostProcessor接口的实现类Bean,那么在该容器中实例化任何其他Bean之前可以回调该Bean中的postPrcessorBeanFactory()方法来对Bean的配置元数据进行更改,比如从XML配置文件中获取到的配置信息。
(2)Bean的实例化:对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
(3)Bean属性注入:实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
(4)BeanNameAware的setBeanName()方法:如果某个Bean实现了BeanNameAware接口,那么Spring将会将Bean实例的ID传递给setBeanName()方法,在Bean类中新增一个beanName字段,并实现setBeanName()方法。
(5)BeanFactoryAware的setBeanFactory()方法:如果某个Bean实现了BeanFactoryAware接口,那么Spring将会将创建Bean的BeanFactory传递给setBeanFactory()方法,在Bean类中新增了一个beanFactory字段用来保存BeanFactory的值,并实现setBeanFactory()方法。
(6)ApplicationContextAware的setApplicationContext()方法:如果某个Bean实现了ApplicationContextAware接口,那么Spring将会将该Bean所在的上下文环境ApplicationContext传递给setApplicationContext()方法,在Bean类中新增一个ApplicationContext字段用来保存ApplicationContext的值,并实现setApplicationContext()方法。
(7)BeanPostProcessor预初始化方法:如果某个IoC容器中增加的实现BeanPostProcessor接口的实现类Bean,那么在该容器中实例化Bean之后,执行初始化之前会调用BeanPostProcessor中的postProcessBeforeInitialization()方法执行预初始化处理。
(8)InitializingBean的afterPropertiesSet()方法:如果Bean实现了InitializingBean接口,那么Bean在实例化完成后将会执行接口中的afterPropertiesSet()方法来进行初始化。
(9)自定义的inti-method指定的方法:如果配置文件中使用init-method属性指定了初始化方法,那么Bean在实例化完成后将会调用该属性指定的初始化方法进行Bean的初始化。
(10)BeanPostProcessor初始化后方法:如果某个IoC容器中增加的实现BeanPostProcessor接口的实现类Bean,那么在该容器中实例化Bean之后并且完成初始化调用后执行该接口中的postProcessorAfterInitialization()方法进行初始化后处理。
(11)使用Bean:此时有关Bean的所有准备工作均已完成,Bean可以被程序使用了,它们将会一直驻留在应用上下文中,直到该上下文环境被销毁。
(12)DisposableBean的destory()方法:如果Bean实现了DisposableBean接口,Spring将会在Bean实例销毁之前调用该接口的destory()方法,来完成一些销毁之前的处理工作。
(13)自定义的destory-method指定的方法:如果在配置文件中使用destory-method指定了销毁方法,那么在Bean实例销毁之前会调用该指定的方法完成一些销毁之前的处理工作。
4. 解释Spring支持的几种bean的作用域。
Spring容器中的bean可以分为5个范围: scope属性
(1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。
(2)prototype:多例原型: 被标识为多例的对象,每次在获得才会被创建,每次创建都是新的对象.
(3)request:Web环境下,对象与request生命周期一致 .
(4)session:Web环境下,对象与session生命周期一致.
(5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。
总结:绝大多数情况下,使用单例singleton(默认值),但是在与struts整合时候,务必要用prototype多例,因为struts2在每次请求都会创建一个新的Action,若为单例,在多请求情况下,每个请求找找spring拿的都是同一个action。
5. Spring框架中的单例Beans是线程安全的么?
Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。
6、Spring如何处理线程并发问题?
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
7. 注解将对象注册到Spring容器当中,有几种注解方式?它们有什么区别吗?
4种。配置在类上方的注解分别是:@Component() 普通的注解:用于三层外的bean的配置. @Service() 业务层 . @Controller() web层中使用 . @Respository()//持久层.
Spring框架最早出现的只有@Component()注解,但如果所有的对象都使用同一个注解,很难区分对象究竟属于哪一层架构。基于此,Spring又推出了@Service()、@Controller()、@Respository()三种注解,用于区分对象属于哪一层架构。但4种注解方式从功能上来说没有任何区别。
8. 如何用注解的方式来完成属性注入?
1. 在需要使用注解进行的时候,需要在配置文件中进行 开启注解扫描的配置
<!--开启注解的扫描 扫描com.gs下所有的包-->
<context:component-scan base-package="com.gs" />
<!-- 开启Spring的注解的扫描:@Controller @Service @Repository @Component等 。默认存在-->
<context:annotation-config />
2. 按类型分可以分为值类型注入和引用类型注入。
值类型注入可以通过@Value()注解来完成,该注解既可以声明在属性上,也可以声明在方法上,建议声明在方法上,但是更多的人会声明在属性上,因为更方便。
引用类型注入可以通过三种注解方式来完成:
配置在属性上的注解
@Resource javax包下的一个注解,功能更加强大点
@Autowired
@Qualifier 属性注入时通知spring容器注入何种类型的对象(告诉spring容器对象的id(name))注意:在使用注解的方式下 及 一个接口下有多个实现类的时候 结合@Autowird一起使用
9. Spring框架中,什么注解可以用来指定对象的作用范围? 和怎么导入其他spring配置文件
答:@Scope(scopeName=”singleton”)。
模块化配置,即分模块配置(导入其他spring配置文件)
<beans>
<import resource = “spring配置文件的全路径名” />
</beans>
10、Spring的自动装配。
Spring中bean有三种装配机制,分别是:1. 在xml中显示配置、 2. 在java中显示配置, 3. 隐式的bean发现机制和自动装配。
set注入和构造注入有时在做配置时比较麻烦。所以框架为了提高开发效率,提供自动装配功能,简化配置。
Spring自动化装配可以借助@Autowired属性实现,以下是自动装配@Autowired属性的六个值的简要介绍:
(1)no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。
(2)byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
(3)byType:通过参数的数据类型进行自动装配。
缺点:如果存在多个相同类型的bean对象,会出错。
如果属性为单一类型的数据,那么查找到多个关联对象会发生错误。
如果属性为数组或集合(泛型)类型,那么查找到多个关联对象不会发生异常。
(4)constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
(5)autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。
(6)default :表示默认采用上一级标签的自动装配的取值。如果存在多个配置文件的话,那么每一个配置文件的自动装配方式都是独立的。
11.spring中 有哪些依赖注入方式?
1. 使用属性的setter方法注入 . (可用于注入bean、字面量、集合;如果是新项目,建议使用Spring注解,因为一堆一堆的xml不好维护,同时功能也不如注解强大。)
属性注入要求Bean提供一个默认的无参的构造函数(否则使用属性注入时将抛出异常),并为需要注入的属性提供对应的Setter方法。Spring先调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用Setter方法注入属性值。
看下简单的例子:
Car类 :定义了3个属性,并分别提供了对应的Setter方法。
属性注入要求Bean提供一个默认的构造函数,并为需要注入的属性提供对应的Setter方法。
Spring先调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用Setter方法注入属性值。
package com.spring.model; public class Car { private int maxSpeed; private String brand; private double price; public int getMaxSpeed() { return maxSpeed; } //一定要写被注入对象的set方法 public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public void run(){ System.out.println("brand:"+brand+",maxSpeed:"+maxSpeed+",price:"+price); } }
在Spring配置文件中对Car进行属性注入:
<!-- 属性注入 --> <bean > <property name="maxSpeed" value="200"></property> <property name="brand" value="红旗CA72"></property> <property name="price" value="200000.00"></property> </bean>