文章目录
- Spring Bean
- 一、Bean的种类
- 二、Bean的命名 id属性和name属性
- 三、实例化Bean方式
- 四、Bean的作用域
- 五、Spring Bean生命周期
- 六、Spring框架中的单例Beans是线程安全的么?
- 七、有状态和无状态的对象区别
- 1、基本概念
- 2、Spring中的有状态(Stateful)和无状态(Stateless)
- 3、Servlet是有状态还是无状态的?
Spring Bean
一、Bean的种类
(1)普通Bean
(2)工厂Bean:FactoryBean
- FactoryBean接口提供getObject()方法获得Bean的实例,此Bean实例不是spring容器提供,而是由工厂自己提供;
- Spring的框架内部,AOP相关的功能及事务处理中,很多地方使用到了工厂bean;
- 注意:BeanFactory作用是实例化、定位、配置应用程序中的对象及建立这些对象的依赖。
二、Bean的命名 id属性和name属性
- 一般情况下,装配一个Bean时,通过指定一个id属性作为Bean的名称
- id 属性在IoC容器中必须是唯一的
- id 的命名要满足XML对ID属性命名规范
- 必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号
- 如果Bean的名称中含有特殊字符,就需要使用name属性
例如:
<bean name="#person" class="cn.itcast.bean.Person"/>
因为name属性可以相同,所以后出现Bean会覆盖之前出现的同名的Bean。
三、实例化Bean方式
对于使用Spring框架的开发人员来说,我们主要做的主要有两件事情:①开发Bean;②配置Bean;
而Spring帮我们做的就是根据配置文件来创建Bean实例,并调用Bean实例的方法来完成“依赖注入”,可以把Spring容器理解成一个大型工厂,Bean就是该工厂的产品,工厂(Spirng容器)里能生产出来什么样的产品(Bean),完全取决于我们在配置文件中的配置。
bean 注入与装配的的方式有很多种,主要有四种实例化Bean的方式(Spring依赖注入四种方式)
【1】使用类构造器实例化
①通过index设置参数的位置;②通过type设置参数类型;
/*带参数,方便利用构造器进行注入*/
public CatDaoImpl(String message){
this. message = message;
}
<bean id="CatDaoImpl" class="com.CatDaoImpl">
<constructor-arg value=" message ">
</constructor-arg>
</bean>
【2】set方法注入方法
public class Id {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
<bean id="id" class="com.id ">
<property name="id" value="123">
</property>
</bean>
【3】使用静态工厂方法实例化(简单工厂模式)
静态工厂:用于生成实例对象,所有的方法必须是static
静态工厂顾名思义,就是通过调用静态工厂的方法来获取自己需要的对象,为了让 spring 管理所有对象,我们不能直接通过"工程类.静态方法()"来获取对象,而是依然通过 spring 注入的形式获取:
public class DaoFactory { //静态工厂
public static final FactoryDao getStaticFactoryDaoImpl(){
return new StaticFacotryDaoImpl();
}
}
public class SpringAction {
private FactoryDao staticFactoryDao; //注入对象
//注入对象的 set 方法
public void setStaticFactoryDao(FactoryDao staticFactoryDao) {
this.staticFactoryDao = staticFactoryDao;
}
}
<bean name="springAction" class=" SpringAction" >
<!--使用静态工厂的方法注入对象,对应下面的配置文件-->
<property name="staticFactoryDao" ref="staticFactoryDao"></property>
</bean>
<!--此处获取对象的方式是从工厂类中获取静态方法-->
<bean name="staticFactoryDao" class="DaoFactory"
factory-method="getStaticFactoryDaoImpl"></bean>
//factory-method="getStaticFactoryDaoImpl"指定调用哪个工厂方法
【4】使用实例工厂方法实例化(工厂方法模式)
实例工厂的意思是获取对象实例的方法不是静态的,所以你需要首先 new 工厂类,再调用普通的实例方法:
实例工厂:必须先有工厂实例对象,通过实例对象创建对象。提供所有的方法都是“非静态”的。
public class DaoFactory { //实例工厂
public FactoryDao getFactoryDaoImpl(){
return new FactoryDaoImpl();
}
}
public class SpringAction {
private FactoryDao factoryDao; //注入对象
public void setFactoryDao(FactoryDao factoryDao) {
this.factoryDao = factoryDao;
}
}
<bean name="springAction" class="SpringAction">
<!--使用实例工厂的方法注入对象,对应下面的配置文件-->
<property name="factoryDao" ref="factoryDao"></property>
</bean> <!--此处获取对象的方式是从工厂类中获取实例方法-->
<bean name="daoFactory" class="com.DaoFactory"></bean>
<bean name="factoryDao" factory-bean="daoFactory"
factory-method="getFactoryDaoImpl"></bean>
四、Bean的作用域
Spring容器中的bean可以分为5个范围:
- singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。
- prototype:为每一个bean请求提供一个实例。
- request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
- session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
- global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。
(功课)Portlet是基于Java的Web组件,由Portlet容器管理,并由容器处理请求,生产动态内容。Portlets 是一种Web组件-就像servlets-是专为将合成页面里的内容聚集在一起而设计的
五、Spring Bean生命周期
六、Spring框架中的单例Beans是线程安全的么?
Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。
七、有状态和无状态的对象区别
1、基本概念
(1)有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。
(2)无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象.不能保存数据,是不变类,是线程安全的。
2、Spring中的有状态(Stateful)和无状态(Stateless)
(1)通过上面的分析,相信大家已经对有状态和无状态有了一定的理解。无状态的Bean适合用不变模式,技术就是单例模式,这样可以共享实例,提高性能。有状态的Bean,多线程环境下不安全,那么适合用Prototype原型模式。Prototype: 每次对bean的请求都会创建一个新的bean实例。
(2)默认情况下,从Spring bean工厂所取得的实例为singleton(scope属性为singleton),容器只存在一个共享的bean实例。
(3)理解了两者的关系,那么scope选择的原则就很容易了:有状态的bean都使用prototype作用域,而对无状态的bean则应该使用singleton作用域。
- 如Service层、Dao层用默认singleton就行,虽然Service类也有dao这样的属性,但dao这些类都是没有状态信息的,也就是相当于不变(immutable)类,所以不影响。
- Struts2中的Action因为会有User、BizEntity这样的实例对象,是有状态信息的,在多线程环境下是不安全的,所以Struts2默认的实现是Prototype模式。在Spring中,Struts2的Action中,scope要配成prototype作用域。
- SpringMVC默认是单例模式,Struts2默认的实现是Prototype模式。
3、Servlet是有状态还是无状态的?
Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。
一个Servlet类在Application中只有一个实例存在,也就是有多个线程在使用这个实例,这是单例模式的应用。
无状态的单例是线程安全的,但我们如果在Servlet里用了实例变量,那么就变成有状态了,是非线程安全的。
如下面的用法就是不安全的,因为user、out都是有状态信息的。
/**
* 非线程安全的Servlet。
*/
public class UnSafeServlet HttpServlet{
User user;
PrintWriter out;
public void doGet (HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
//do something...
}
}
Out、Request、Response、Session、Config、Page、PageContext是线程安全的;
Application在整个系统内被使用,所以不是线程安全的.