文章目录

  • 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的作用域

springboot bean设置默认值 spring默认bean名称_Spring


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生命周期

springboot bean设置默认值 spring默认bean名称_线程安全_02

springboot bean设置默认值 spring默认bean名称_作用域_03

六、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在整个系统内被使用,所以不是线程安全的.