Spring中的Bean相关问题
请谈谈Spring中的单例Bean的线程安全问题?
大部分时候我们并没有在系统中使用多线程,所以很少有人关注这个问题,单例bean存在线程安全问题,主要是因为当多个线程操作同一个对象时,对这个对象的非静态成员变量的写操作会存在线程安全问题.
有两种常见的解决办法:
1.在bean对象中尽量避免定义可变的成员变量(不太现实)
2.在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中(推荐的一种方式)
Spring如何处理线程并发问题?
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为Singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题.
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题.同步机制采用了"时间换空间"的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队,而ThreadLocal采用了"空间换时间"的方式,ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突,因为每一个线程都有自己的变量副本,从而也就没有必要对该变量进行同步了,ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal.
Spring中的Bean的作用域有哪些?
1.singleton:唯一bean实例,Spring中的bean默认都是单例的.
2.prototype:每次请求都会创建一个新的bean实例.
3.request:每一次HTTP请求都会产生一个新的bean,该bean只在当前HTTP request内有效.
4.session:每一次HTTP请求都会产生一个新的bean,该bean只在当前HTTP session内有效.
5.global-session:全局session作用域.
什么是Spring的Bean的装配?
bean的装配是指在Spring容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,通过依赖注入把它们装配到一起.
什么是Spring Bean的自动装配?都有哪些自动装配方式?
Spring容器能够自动装配相互合作的bean,这意味着容器不需要<constructor-arg>和<propert>配置,能通过Bean工厂自动处理bean之间的协作;
有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入
1.no:默认的方式是不进行自动装配,通过显示设置ref属性来进行装配.
2.byName:通过参数名自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byName,之后容器试图匹配,装配和该bean的属性具有相同名字的bean.
3.byType:通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配,装配和该bean的属性具有相同类型的bean,如果有多个bean符合条件,则抛出错误.
4.constructor:这个方式类似于byType,但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常.
5.autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式.
自动装配的局限性:
1.重写:你仍需要使用<constructor-arg>和<property>配置来定义依赖,意味着总要重写自动装配.
2.基本数据类型:你不能自动装配简单的属性,如:基本数据类型,String类型,和 类.
3.模糊特性:自动装配不如显式装配精确,如果有可能尽量使用显式装配.
基于注解的方式:
使用@Autowired注解来自动装配指定的Bean,在使用@Autowired注解之前需要在Spring配置文件中进行配置:<context:annotation-config />。在启动Spring IOC时,容器自动装载了一个 AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowired,@Resource或@Inject时,就会在IOC容器中自动查找需要的Bean,并装配给该对象的属性,在使用@Autowired时,首先在容器中查询对应类型的bean:
如果查询结果刚好有一个,就将该Bean装配给@Autowired指定的数据;
如果查询结果不止一个,那么@Autowired会根据名称来查找;
如果上述查找结果为空,那么会抛出异常,解决方法是:使用required = false;
@Autowired可用于:构造函数,成员变量,setter方法.
注:@Autowired和@Resource之间的区别
(1):@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
(2):@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
如果想在某个Bean生成并装配完毕后执行自己的逻辑,可以用什么方式实现?
有时,我们需要在启动bean时初始化bean的属性,例如读取properties文件,对属性进行赋值,启动容器时让某个method方法执行等,这时需要在进行配置,让bean在注入时启动相应的方法.
共有以下几种方法:
1.如果是通过xml配置文件进行Bean的生成,我们可以在配置Bean的时候,使用init-method="executionMethod"属性,这样在当前Bean实例化完成后,就会自动执行指定的executionMethod,executionMethod为定义在Bean中的一个方法.
1 <bean id="initializingBean" class="全类名" init-method="executionMethod"></bean>
2.可以让Bean实现InitializationBean接口,并重写其afterPropertiesSet()方法.
3.给需要调用的方法加上@PostConstruct注解,即在构造方法之后调用.比如:
1 @PostConstruct 2 private void initMethod1(){ .....}
请谈一下Spring基于xml注入bean的几种方式?
1.set方法注入
2.构造器注入,(1)通过index设置参数的位置,(2)通过type设置参数类型.
3.静态工厂注入
4.实例工厂
(3和4这两种方式可以合并成一种:利用反射注入,通过反射的到这个属性的filed对象,通过这个对象的set方法进行注入,@Autowired注解采用的就是这种方式)
详细解释可以参考这里:点击进入
请说说BeanFactory和ApplicationContext的区别?
BeanFactory和ApplicationContext是Spring两大核心接口,都可以当做Spring容器,其中ApplicationContext是BeanFactory的子接口.
1.BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载,实例化,控制bean的生命周期,维护bean之间的依赖关系,ApplicationContext接口作为BeanFactory接口的派生,除了提供BeanFactory所有的功能外,还提供了更完整的框架功能,例如:
(1):继承MessageSource,因此支持国际化。
(2):统一的资源文件访问方式。
(3):提供在监听器中注册bean的事件。
(4):同时加载多个配置文件。
(5):载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
2.BeanFactory采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化.这样我们就不容易发现一些存在的Spring配置问题,例如:如果Bean的某一个属性没有注入,BeanFactory加载后,直至第一次使用,调用getBean方法才会抛出异常.
ApplicationContext采用的是在容器启动时,一次性创建了所有的Bean,这样,在容器启动时,我们就可以发现Spring中存在的配置问题,这样有利于检查所依赖属性是否注入,ApplicationContext启动后预加载所有的单例Bean,通过预载入单实例Bean,确保当你使用的时候,就不用等待了,因为它们已经被创建好了.
相对于BeanFactory,ApplicationContext唯一的不足是占用内存空间,当应用程序配置的Bean较多时,程序启动较慢.
3.BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader.
4.BeanFactory和ApplicationContext都支持BeanPostProcessor,BeanFactoryPostProcessor的使用,但两者的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册.