千水金年

Spring Bean

2017-02-09

本文 spring复习笔记

bean

init-method

  • 该方法是由spring容器执行
  • 在构造函数之后执行
  • 如果在构造函数之后,在调用方法之前要做一些工作,可以在init方法中完成

destroy-method

  • 如果该bean是单例(默认就是singlton),则在spring容器关闭或者销毁的时候,执行该方法
  • 如果该bean是多例(scope=”prototype”),则spring容器不负责销毁
  • 说明:要想让spring容器控制bean的生命周期,那么该bean必须是单例 如果该bean是多例,该bean中还有资源,关闭资源的操作由程序员完成

scope

singleton 默认

  • 单例
  • 属性是共享的
  • 一般情况下,把数据存放在方法中的变量中

对于Spring中实现Singleton模式,是以IOC容器为单位,换句话说,一个JVM可能有多个IOC容器,而Java中实现Singleton而言,只有一个JVM。所以说,Spring中实现的Singleton模式与Java中的Singleton设计模式有点不同。 此外,spring singleton的含义是在一个spring 上下文中保持单态。 所以singleton模式中,singleton的class在整个JVM中只有一个instance,Spring的Bean,你可以一个class配置多个Bean,这个class就有了多个instance。这个singleton是指在spring容器中,这个Bean是单实例的,是线程共享的。所以要求这些类都是线程安全的。也就是说,不能出现修改Bean属性的方法,当然除了设值得那些setter。只要满足线程安全,这些bean都可以用singleton。而且我们在绝大多数使用上,也是这样用的,包括dao,service。

Beanfactory是Spring初始以静态方式载入的,Spring的单例IOC是基于容器级的,所以这你都不用担心与考虑.

–应用中对象有两种,行为对象和数据对象,行为对象都要求是线程安全的!也就是允许单例的, 不管是dao 还是 service 对象,都是行为对象,行为对象不应该引用非线程安全的对象做成员量,同时在应用外部的资源(如文件,数据库连接,session)时,要先保证对这些东西的访问是做了并发控制的!

对于spring来讲,都是保证对同一sesionfactory bean是单例的,也就是所谓 sessionfactory 范围的.

–这是一个真实的案例,我们在项目中使用Spring和ACEGI,我之所以选择ACEGI,除了它对权限的良好控制外,

我还看好它的SecurityContextHolder,通过代码来看:

Authentication auth = SecurityContextHolder.getContext().getAuthentication();

我可以很容易在系统任意一层得到用户的信息,而不用把用户信息在参数里传来传去,(这也是struts的缺点之一)

但是我在每一次要得到用户信息的时候都写上面的一段代码,未免有些麻烦,所以我在BaseService, BaseDao里都提供了如下方法:

/**   
 * get current login user info   
 * @return UserInfo   
 */    
protected UserInfo getUserInfo()     
{     
    return getUserContext().getUserInfo();     
}     
    
/**   
 * get current login user context   
 * @return UserContext   
 */    
protected UserContext getUserContext()     
{     
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();     
    return (UserContext) auth.getPrincipal();     
}     

这样在其他的Service和Dao类里可以通过

super.getUserContext(), super.getUserInfo()     

来得到用户的信息,这也为问题的产生提供了温床。请看如下代码:

public class SomeServece extends BaseService implements SomeInterFace       
{     
    private UserInfo user = super.getUserInfo();     
         
    public someMethod()     
    {     
       int userID = this.user.getUserID();     
       String userName = this.user.getUserName();     
       //bla bla do something user userID and userNaem     
    }     
}         

这段代码在单元测试的时候不会用任何问题,但是在多用户测试的情况下,你会发现任何调用SomeService里someMethod()方法的userID和userName都是同一个人,也就是第一个登陆的人的信息。 其根本原因是Spring的Bean在默认情况下是Singleton的,Bean SomeServece的实例只会生成一份,也就是所SomeServece实例的user对象只会被初始化一次,就是第一次登陆人的信息,以后不会变了。所以BaseService想为开发提供方便,却给开发带来了风险.

正确的用法应该是这样的

public class SomeServece extends BaseService implements SomeInterFace       
{        
    public someMethod()     
    {     
       int userID = super.getUserInfo().getUserID();     
       String userName = super.getUserInfo().getUserName();     
       //bla bla do something user userID and userNaem     
    }  
}  

prototype

  • 多例
  • 当一个bean是多例模式的情况下,lazy-init为false或者default无效

lazy-init

ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的singleton bean。通常情况下这是件好事,因为这样在配置中的任何错误就会即刻被发现(否则的话可能要花几个小时甚至几天)。 通过在元素上使用’default-lazy-init’属性、元素上使用’lazy-init’

lazy-init true 在context.getBean的时候才要创建对象

  • 优点 如果该bean中有大数据存在,则什么时候context.getBean,什么时候创建对象 可以防止数据过早的停留在内存中,做到了懒加载
  • 缺点 如果spring配置文件中,该bean的配置有错误,那么在tomcat容器启动的时候,发现不了

lazy-init false 在启动spring容器的时候创建对象

  • 优点 如果在启动tomcat时要启动spring容器, 那么如果spring容器会错误,这个时候tomcat容器不会正常启动
  • 缺点 如果存在大量的数据,会过早的停留在内存中
<beans />                <bean />            immediately  
<beans />                <bean lazy-init="true" />   lazy      
<beans />                <bean lazy-init="false"/>   immediately           
<beans default-lazy-init="true"/>  <bean />          lazy  
<beans default-lazy-init="true"/>  <bean lazy-init="true" />     lazy  
<beans default-lazy-init="true"/>  <bean lazy-init="false" />    immediately  
<beans default-lazy-init="false"/>  <bean />             immediately  
<beans default-lazy-init="false"/>  <bean lazy-init="true" />    lazy  
<beans default-lazy-init="false"/>  <bean lazy-init="false" />   immediately  

Comments