精华内容
下载资源
问答
  • 一、spring单例与多例定义 单例:一个类只能产生一个对象(对应到spring中,注入的对象永远是同一个) 多例:一个类能产生多个对象(对应到spring中,注入的对象永远是新的) @Scope("prototype") @Scope("singleton...
  • 主要介绍了浅谈Spring单例Bean与单例模式的区别,具有一定借鉴价值,需要的朋友可以参考下
  • Spring单例是指一个Spring Bean容器(ApplicationContext)中仅有一个实例。同时同一个容器中类型相同但是名称不同也会是不同实例。 单例池 底层是CurrentHashMap,是实现SpringBean单例的手段。 ...

    单例模式

    单例模式是指在一个jvm进程(运行的Java程序)中仅有一个实例。

    Spring单例Bean

    Spring单例是指一个Spring Bean容器(ApplicationContext)中仅有一个实例。同时同一个容器中类型相同但是名称不同也会是不同实例。
    在这里插入图片描述

    单例池

    底层是CurrentHashMap,key为beanName,value为bean,它是实现SpringBean单例的手段。

    展开全文
  • Spring单例初始化流程

    2021-04-06 22:08:19
    Spring单例对象的初始化主要分为三步。 createBeanInstance:实例化,其实就是 调用对象的构造方法实例化对象。 populateBean:填充属性,这一步主要是多bean的依赖属性进行填充。 initializeBean:调用spring ...

    概述

    Spring的单例对象的初始化主要分为三步。
    在这里插入图片描述

    1. createBeanInstance:实例化,其实就是 调用对象的构造方法实例化对象。
    2. populateBean:填充属性,这一步主要是多bean的依赖属性进行填充。
    3. initializeBean:调用spring xml中的init() 方法,或者@PostConstruct注解的init()方法。

    三级缓存

    对于单例来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存。

    哪三级缓存

    /** Cache of singleton objects: bean name --> bean instance */
    // 一级缓存,完全初始化好的单例放入其中,从上下文获取的单例就是从这里获取
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
    /** Cache of singleton factories: bean name --> ObjectFactory */
    // 三级缓存,存放实例化的对象,还没有对其进行属性填充
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
    /** Cache of early singleton objects: bean name --> bean instance */
    // 二级缓存,提前暴光的单例对象的Cache(用于检测循环引用,与singletonFactories互斥,就是要么在singletonFactories中要么在earlySingletonObjects中),
    // 也只是实例化,但还没有填充属性
    private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
    

    从缓存中获取bean

    在获取bean的时候,首先是根据beanName从缓存中获取bean,如果获取不到就通过单列工厂创建,具体的流程可以看单列初始化流程图。
    缓存中获取bean的逻辑是先从singletonObjects(一级缓存)获取,如果获取不到去earlySingletonObjects(二级缓存)获取,还是获取不到就从singletonFactories(三级缓存)获取。
    源码如下:

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
                Map var4 = this.singletonObjects;
                synchronized(this.singletonObjects) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null && allowEarlyReference) {
                        ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
            return singletonObject != NULL_OBJECT ? singletonObject : null;
        }
    

    注释

    1. isSingletonCurrentlyInCreation()判断当前单例bean是否正在创建中,
      也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象,
      或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。)
    2. allowEarlyReference 是否允许从singletonFactories中通过getObject拿到对象。

    单例初始流程

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 单例多例需要搞明白这些问题: 1. 什么是单例多例; 2. 如何产生单例多例; 3. 为什么要用单例多例 4. 什么时候用单例,什么时候用多例; 1. 什么是单例、多例: 所谓单例就是所有的请求都用一个对象来处理,...

    单例多例需要搞明白这些问题:

         1. 什么是单例多例;

         2. 如何产生单例多例;

         3. 为什么要用单例多例

         4. 什么时候用单例,什么时候用多例;

     

    1. 什么是单例、多例:

         所谓单例就是所有的请求都用一个对象来处理,比如我们常用的service和dao层的对象通常都是单例的,而多例则指每个请求用一个新的对象来处理,比如action;

     

         单例模式和多例模式说明:

         1. 单例模式和多例模式属于对象模式。

         2. 单例模式的对象在整个系统中只有一份,多例模式可以有多个实例。

         3. 它们都不对外提供构造方法,即构造方法都为私有。

     

    2. 如何产生单例、多例:

        在通用的SSH中,单例在spring中是默认的,如果要产生多例,则在配置文件的bean中添加scope="prototype";

     

    3. 为什么用单例、多例:

        之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;

       之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;

        用单例和多例的标准只有一个:

        当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例;

     

    4. 何时用单例?何时用多例?

        对于struts2来说,action必须用多例,因为action本身含有请求参数的值,即可改变的状态;

        而对于STRUTS1来说,action则可用单例,因为请求参数的值是放在actionForm中,而非action中的;

        另外要说一下,并不是说service或dao一定是单例,标准同第3点所讲的,就曾见过有的service中也包含了可改变的状态,同时执行方法也依赖该状态,但一样用的单例,这样就会出现隐藏的BUG,而并发的BUG通常很难重现和查找;

     

          spring生成对象默认是单例的。通过scope属性可以更改为多例

     

    <bean id="user" class="modle.User" scope="prototype">  </bean>

     

    现在又这么一种情况.

     

    User类调用一个service, 这个service又调用一个tool。

    有时我们希望User是多例的,service是单例的,而tool又是多例的。

    很自然地想法是配置文件这些写

    <bean id="user" class="modle.User" scope="prototype">   

         <property name="service" ref="userservice"></property> 

    </bean>   

    <bean id="userservice" class="service.userService" >   

         <property name="tool" ref="tool"></property> 

    </bean>   

    <bean id="tool" class="service.ToolImpl" scope="prototype">

    </bean>

    但是这种写法是错误的! 不能使用spring的自动注入!

     

    由于service是单例的,所以这种方法的结果是:User多例,service和tool都是单例。(为什么?)

     

    官网文档:

    4.5.3 Singleton beans with prototype-bean dependencies

     

    When you use singleton-scoped beans with dependencies on prototype beans, be aware that dependencies are resolved at instantiation time. Thus if you dependency-inject a prototype-scoped bean into a singleton-scoped bean, a new prototype bean is instantiated and then dependency-injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to the singleton-scoped bean.

     

    However, suppose you want the singleton-scoped bean to acquire a new instance of the prototype-scoped bean repeatedly at runtime. You cannot dependency-inject a prototype-scoped bean into your singleton bean, because that injection occurs only once, when the Spring container is instantiating the singleton bean and resolving and injecting its dependencies. If you need a new instance of a prototype bean at runtime more than once, see Section 4.4.6, “Method injection”

     

    正确的写法是,是每次调用tool时都生成一个新的tool对象。但是我们又不能手动new一个,要借助BeanFactory

     

    public class User {

     

      private userService service;

      private int age;

      private Date date;

      private String name;

     

    UserService 通过实现 BeanFactoryAware 接口来获得factory

    由于不使用spring的自动注入,set方法要去掉!

    public class userService implements BeanFactoryAware{   

      private Tool tool;

      private BeanFactory factory;
      public void service(){
        this.tool = (Tool)factory.getBean("tool");
        System.out.println(this+":service");
        tool.work();
      }
      public Tool getTool() {
            return tool;
      }

    // public void setTool(Tool tool) {//        

    // this.tool = (Tool)factory.getBean("tool");// } 

    public void setBeanFactory(BeanFactory f) throws BeansException {

        factory = f;
      }
     
    }

    配置文件,不能再使用注入。因此要把tool对象的注入去掉!

    <bean id="user" class="modle.User" scope="prototype">   

         <property name="service" ref="userservice"></property> 

    </bean>   

    <bean id="userservice" class="service.userService" > 

    </bean>   

    <bean id="tool" class="service.ToolImpl" scope="prototype">

    </bean>

    public interface Tool { 

         public void work();

    }

     

    public class ToolImpl implements Tool{

      public void work() {
        System.out.println(this+":Tool Work");

      }

    }

    测试类:

    public class Test {
      public static void main(String[] args) {
        ClassPathResource res = new ClassPathResource("applicationContext.xml");
        XmlBeanFactory factory = new XmlBeanFactory(res);
        User user = (User)factory.getBean("user");
        User user2 =  (User)factory.getBean("user");
            System.out.println(user);
        user.getService().service();
        System.out.println();
        System.out.println(user2);
        user2.getService().service();
      }
    }

    Output:

     

     

    modle.User@42552c
    service.userService@19e15c:service
    service.ToolImpl@11a75a2:Tool Work
    

    modle.User@210b5b
    service.userService@19e15c:service
    service.ToolImpl@170888e:Tool Work

    展开全文
  • spring单例模式与线程安全问题

    千次阅读 2019-08-19 20:05:01
    三、spring单例模式下,资源是否是线程安全的,跟是不是单例没关系,主要看资源是否存在共享情况,如果存在共享情况,在需要解决线程安全问题,例如 SimpleDateFormat 1、synchronize 2、变成局部变量,每次在...

    一、局部变量,不存在线程安全问题,因为每个请求都是一个线程请求,局部变量都在线程内不共享

    public int sayHello(int count) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count++;
            return count;
        }

    二、全局变量,存在线程安全问题,全局变量是共享数据

    private int count = 0;
        
        public int sayHello() {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count++;
            return count;
        }

    三、spring单例模式下,资源是否是线程安全的,跟是不是单例没关系,主要看资源是否存在共享情况,如果存在共享情况,在需要解决线程安全问题,例如 SimpleDateFormat

    1、synchronize

    2、变成局部变量,每次在方法中new SimpleDateFormat(); (不推荐)

    3、ThreadLocal<SimpleDateFormat>

    //使用ThreadLocal代替原来的new SimpleDateFormat
        private static final ThreadLocal<SimpleDateFormat> dateFormatter = new ThreadLocal<SimpleDateFormat>(){
            @Override
            protected SimpleDateFormat initialValue() {
                return  new SimpleDateFormat("yyyy-MM-dd");
            }
        };
    
    
        @Override
        public String today(String POGroup) {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            return dateFormatter.get().format(new DateTime().withZone(DateTimeZone.forID(this.timeZoneMapping.get(POGroup))).toLocalDateTime().toDate());
        }

     

    展开全文
  • Spring单例bean线程不安全问题学习研究问题引入问题的回答如何解决?背景知识Spring 的 bean 作用域(scope)类型原型Bean与单例Bean理论依据实验过程多线程模型ThreadLocal@Scope("prototype")@Scope("request")...
  • spring单例bean的创建流程简化创建流程图流程说明详细创建流程图 简化创建流程图 流程说明 1 当spring容器在启动的时候或者启动完成后显示调用getBean方法时来获取bean实例的时候,都会调用这个doGetBean方法 ...
  • spring 单例 并发访问

    2019-04-30 14:01:00
     1、spring框架controller和service默认都是单例的,那么多并发bio时,是如何实现线程安全的? 线程与栈:  A、每当启用一个线程时,JVM就为他分配一个Java栈,栈是以帧为单位保存当前线程的运行状态。某个...
  • 为什么spring单例模式可以支持多线程并发访问? 1、spring单例模式是指,在内存中只实例化一个类的对象 2、类的变量有线程安全的问题,就是有get和set方法的类成员属性。执行单例对象的方法不会有线程安全的问题 ...
  • Spring容器会将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持 在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出 ...
  • 2.Spring单例模式

    2019-01-24 15:24:59
    Spring单例模式 单例模式:是指在一个JVM进程中仅有一个实例,只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例(Spring默认为单例模式)。 多例模式:对这个bean的每次请求都会创建一个新的...
  • spring单例模式指的是在内存中只实例化一个类的对象。确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 当多个用户同时请求一个接口服务的时候,容器会给每一个请求分配一个线程,这时候多个线程...
  • spring单例模式

    千次阅读 2017-08-17 17:54:16
    关于spring单例还是多例1.spring作为控制层默认采用的是单例模式,即在一个conctroller实例化一次之后,就不在实例化了. 2.当然,spring也是支持多例的,使用 @scope(“prototype”) 注解来实现多例.使用多例会是程序...
  • 一、Spring单例模式与线程安全 Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方。 单例模式的意思就是只有一个实例。单例模式确保某一个类只有...
  • spring单例改多例

    千次阅读 2018-05-24 15:23:30
    spring默认是单例模式(就每个请求都是用的同一对象,对于dao层肯定是棒棒的),但是有的时候,我们需要每个请求都产生一个新的对象,就如做微信小程序,用scoket、不可能一直都用一个来接收的,因为需要分配房间,...
  • Spring单例Bean与单例模式的区别

    万次阅读 2017-07-08 19:37:29
    Spring单例Bean与单例模式的区别在于它们关联的环境不一样,单例模式是指在一个JVM进程中仅有一个实例,而Spring单例是指一个Spring Bean容器(ApplicationContext)中仅有一个实例。首先看单例模式,在一个JVM进程中...
  • Spring 中的 bean 为什么默认单例 单例bean与原型bean的区别 如果一个bean被声明为单例的时候,在处理多次请求的时候在Spring容器里只实例化出一个bean,后续的请求都公用这个对象,这个对象会保存在一个map里面。 ...
  • Spring单例和多例

    千次阅读 2019-01-15 15:24:54
    - spring中默认是单例还是多例? - 什么时候使用单例?什么时候使用多例? - springMVC的的controller是单例还是多例?(为什么是单例?) - … spring默认当然是单例,我想说的是第二条,什么时候使用单例?什么时候使用多例?...
  • Spring 的 bean默认是单例的,在高并发下,如果在 Spring单例 bean 中设置成员变量,则会发生并发问题。最近在进行开发时,错误的在单例的bean中使用了成员变量,导致多个线程大并发访问时,出现赋值错误及日志...
  • spring生成对象默认是单例的。通过scope属性可以更改为多例。 &lt;bean id="user" class="modle.User" scope="prototype"&gt; &lt;/bean&gt; 现在有这么一种情况. ...
  •  2:spring单例模式的安全问题是使用ThreadLocal解决的 单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。 当多用户同时请求...
  • spring单例模式和多例模式,首先单例模式是什么呢? 单例模式:不管获取对象几次,每次getBean都是同一个实例。 单例模式又分为懒汉模式和饿汉模式。 饿汉模式:在加载对象时候,对象就会创建实例,为所有...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 106,412
精华内容 42,564
关键字:

spring单例

spring 订阅