Spring相关概念

1、依赖注入

重新学习Spring的时候发现对核心思想的理解有些淡忘,所以进行相关记录。
依赖注入本质的目的就是为了松耦合,松耦合一方面是为了减少维护成本(也更利于代码的扩展),另一方面也为代码的测试提供了很大的遍历。依赖注入的重要表现就在于不用在依赖方去实例化被依赖的类,这样同时意味着我们可以有更多的实现类去编写被依赖类,而不用担心依赖类的维护成本。

2、容器

容器是Spring的核心,但是Spring容器并不是只有一个,Spring自带多个容器,可以分为两类,bean工厂和应用上下文。上下文可以理解为Spring容器的抽象化表达,例如我们常见的ApplicationContext本质上说就是一个维护Bean定义以及对象之间协作关系的高级接口。

3、IOC

所谓IOC,是一种叫控制反转的编程思想,网上有很通俗易懂的总结,我就不胡乱阐述了。总之一句话,我的应用程序里不用再过问对象的创建和管理对象之间的依赖关系了,都让IOC容器给代劳吧,也就是说,我把对象创建、管理的控制权都交给Spring容器,这是一种控制权的反转,所以Spring容器才能称为IOC容器。不过这里要厘清一点:并不是说只有Spring的容器才叫IOC容器,基于IOC容器的框架还有很多,并不是Spring特有的。
例如:然后通过应用上下文将配置加载到IOC容器,让Spring替我们管理对象,待我们需要使用对象的时候,再从容器中获取bean就ok了

public class Test {
    public static void main(String[] args) {
        //加载项目中的spring配置文件到容器
//        ApplicationContext context = new ClassPathXmlApplicationContext("resouces/applicationContext.xml");
        //加载系统盘中的配置文件到容器
        ApplicationContext context = new FileSystemXmlApplicationContext("E:/Spring/applicationContext.xml");
        //从容器中获取对象实例
        Man man = context.getBean(Man.class);
        man.driveCar();
    }
}

4、bean的生命周期

参照Spring实战一书中的bean的生命周期叙述(网上也可以查到很多),总结下来就是,在我们通过Spring上下文获取一个bean的时候,

  • Spring首先对bean进行实例化(new一个),然后将bean相关的值和引用注入进去;
  • 再然后如果这各bean实现了一些接口(如 BeanNameAware(与bean在容器中的名字有关) 、 BeanFactoryAware等,基本都是用于bean在使用前进行一些修改、填充、完善的接口);
  • 然后bean准备就绪,可以被应用程序使用了,将一直驻留在应用上下文中,直到该应用上下文被销毁。
  • 如果bean实现了销毁时的一些接口,那么bean销毁的时候会执行相关方法。

5、springmvc下的单例和多例

Spring单例和多例

在ssm框架中 service层、dao层、controller层都是默认使用单例模式,只会产生唯一 一个对象。

单例模式下会共享普通成员变量和静态成员变量,多例模式下普通成员变量不共享,静态成员共享.

controller虽然是单例,但不会造成线程阻塞;
为什么局部变量不会受多线程影响?
1、对于那些会以多线程运行的单例类,例如Web应用中的Servlet,每个方法中对局部变量的操作都是在线程自己独立的内存区域内完成的,所以是线程安全的
2、局部变量不会受多线程影响
3、成员变量会受到多线程影响
4、对于成员变量的操作,可以使用ThreadLocal来保证线程安全

JVM是如何实现线程的独立内存空间?
Java中的栈
1、每当启用一个线程时,JVM就为他分配一个Java栈,栈是以帧为单位保存当前线程的运行状态。某个线程正在执行的方法称为当前方法,当前方法使用的栈帧称为当前帧,当前方法所属的类称为当前类,当前类的常量池称为当前常量池。当线程执行一个方法时,它会跟踪当前常量池。
2、每当线程调用一个Java方法时,JVM就会在该线程对应的栈中压入一个帧,这个帧自然就成了当前帧。当执行这个方法时,它使用这个帧来存储参数、局部变量、中间运算结果等等。
3、Java栈上的所有数据都是私有的。任何线程都不能访问另一个线程的栈数据。所以我们不用考虑多线程情况下栈数据访问同步的情况。

spring是否使用了threadlocal?
ThreadLocal是JDK提供的为解决线程安全的一种解决办法
spring自己肯定用到了ThreadLocal
深入学习得知:
无论service是单例的还是多例的,注入到controller中的只有一个实例,这是在容器启动的时候就已经注入的,所以并发的访问controller,如果controller是多例,会生成多个controller实例,但是指向的service都是容器启动时注入的那一个。但是service注入到不同的controller中时,如果service是多例的,那么不同的controller中的service实例不同。
所以在controller或者service中定义成员变量的时候一定要小心,如果想要共享信息,最好写成配置信息的。
ps:status2默认是多实例的,因为spring是针对方法的访问,而status2更多的是针对类,所以在status中有很多成员属性,为了线程安全默认是多例的。

有状态和无状态的bean

  • 有状态会话bean :每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。

  • 无状态会话bean :bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean 的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean 并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。
    其中bean作用域中的singleton是无状态的作用域,prototype是有状态的作用域…bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法。但对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype
    bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被prototype作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。)

Spring中bean的作用域

Spring IOC容器创建一个Bean实例时,可以为Bean指定实例的作用域,作用域包括singleton(单例模式)、prototype(原型模式)、request(HTTP请求)、session(会话)、global-session(全局会话)。

在这里插入图片描述

(1)当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

(2)当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:

<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/> 

或者

<bean id="account" class="com.foo.DefaultAccount" singleton="false"/> 

(3)当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:


<bean id="loginAction" class="cn".csdn.LoginAction" scope="request"/>
 

针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。

(4)当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:


<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。

(5)当一个bean的作用域为Global Session,表示在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:


<bean id="user" class="com.foo.Preferences "scope="globalSession"/>

global session作用域类似于标准的HTTP Session作用域,不过仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。

Spring与并发

Spring处理并发主要靠ThreadLocal,详情可以参考以下地址
https://blog.csdn.net/coding_1994/article/details/81155765

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值