文章目录
- Q1、什么是Spring Bean?和对象有什么区别
- Q2、配置Bean有哪几种方式?
- Q3、Spring支持的Bean有哪几种作用域?
- Q4、单例Bean的优势是什么?
- Q5、Spring的Bean是线程安全的吗?
- Q6、Spring如何处理线程并发问题?
- Q7、Spring实例化Bean有几种方式?
- Q8、什么是Bean的装配(依赖注入)?什么是Bean的自动装配(自动注入)?
- Q9、自动注入有什么限制吗?
- Q10、自动装配的方式有几种?
Q1、什么是Spring Bean?和对象有什么区别
答案:
- Bean也是一个对象,但它是由Spring IoC容器管理的对象
- Bean是一个由Spring IoC容器实例化、组装和管理的对象
举例:
Q2、配置Bean有哪几种方式?
答案:
第一种,使用xml文件配置
:
<bean class="com.llg.UserService" id="userService">
第二种:使用注解
:
前提:需要配置扫描包ComponentScan,否则以下注解无效:
- @Component
而@Component又分为:
- @Controller
- @Service
- @Repository
第三种:@Bean
:
标注于方法,return一个对象,这个对象就会成为一个Bean,和@Component不同,@Component依赖反射来创建实例
//@Bean可以自己来控制Bean实例化的过程@Bean
public DataSource dataSource(){//...// new xxx//设置dataSource对象的各种属性return dataSource;
}
第四种:@Import
:
//@Import只能用在类上
//@Import通过快速导入的方式实现把实例加入spring的IOC容器中
@Import({ 类名.class , 类名.class... })
public class TestDemo {}
//对应的import的bean都将加入到spring容器中
Q3、Spring支持的Bean有哪几种作用域?
PS:
- 作用域的配置可以在xml中使用scope属性
- 也可在使用@Scope注解
答案:
共有5个:
- singleton:单例,在每个Spring IoC容器中只有一个实例(默认)
- prototype:多例,一个bean的定义可以有多个实例
- request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效
- session:在一个htpp Session中,一个ean定义对应于一个实例,该作用域仅限于Web Spring
- application:一个全局的应用共享一个对象
Q4、单例Bean的优势是什么?
答案:
使用单例Bean,则不会每次都创建新的对象,因此在性能上有以下几点的优势:
- 减少了新生成实例的消耗:一来Spring依赖反射来生成bean实例会消耗性能,给对象分配内存也涉及到复杂算法。二来减少服务器内存的消耗
- 生成的对象少了,减少JVM回收
- 可以快速获取到bean,因为单例bean的获取,除了第一次生成之外其余都是在缓存中获取了,所以很快。
Q5、Spring的Bean是线程安全的吗?
答案:
- 单例Bean不是线程安全的,如果类中声明了成员变量,且有对这个变量的读写操作,就会线程不安全
- 但是,如果把成员变量声明在方法中(局部变量—),则单例Bean线程安全
demo演示:
定义一个单例Bean:其成员变量在某方法中有读写操作:
new两个线程,分别调用beanDemo方法:
简单分析下:线程1将username改成welcome:AAA后休眠的过程中,线程2将username改成welcome:QQQ,此时线程休眠结束,返回这个Bean的username属性,则都返回了welcome:QQQ:
如果将username改成beanDemo方法的局部变量,则没有此线程安全问题。
Q6、Spring如何处理线程并发问题?
A1: 将Bean设置为多例
@Bean
@Scope("prototype")
...
A2: 将成员变量放在ThreadLocal(本地线程)中
//修改UserMapper类
public class UserMapper{private ThreadLocal<String> username = new ThreadLocal<>(); //注意类型和之前的变化public String beanDemo(String uname){username.set("welcome:"+uname): //set修改try{Thread.sleep(10); }catch(InterruptedException e){e.printStackTrace();}return username.get(); //get拿值}
}
虽然现在线程1和线程2操作的是同一个UserMapper对象,但username是绑定在各自线程的,是各个线程独有的。
A3: 加同步锁,但这样会影响服务器的吞吐量,相当于把之前的并行改成了串行
Q7、Spring实例化Bean有几种方式?
A1: 构造器方式(反射)
比如使用xml或@Component定义一个Bean,则:
- BeanDefinition.beanClass
- 使用反射的new Instance,底层是在调用构造方法
A2: 静态工厂的方式
即定义Bean的时候配置下factory-method方法,则Spring实例化时会调用factory-method指定的方法去创建Bean,注意静态工厂指定的这个方法必须是静态的。
<bean class="cn.llg.beans.Person" id="person" factory-method="createPerson">
</bean>
A3: 实例工厂的方式(@Bean)
在factory-method的基础上再指定factory-bean,则实例化时,用factory-bean调用factory-method来实例化
<bean class="cn.llg.beans.Person" id="person" factory-bean="personFactory"factory-method="createPerson">
</bean>
别忘了BeanDefinition这个类,它里面就有对应属性存储factory-bean和factory-method
当使用@Bean时,则factoryBeanName就是你的那个配置类,而factoryMethodName就是@Bean注解下面的那个方法的方法名
。
A4: FactoryBean的方式
实现FactoryBean接口,重写getObject方法。
//之前的BeanFactory和FactoryBean区别时的那个FactoryBean
private class Car implements FactoryBean{//...@Overrridepublic Object getObject() throws Exception{return new Tank(); //汽车变坦克}@Overridepublic Class<?> getObjectType(){return Tank.class;}}
总结就是四种,且后面这三种,我们可以自己控制Bean的创建,不再由Spring掌控。
Q8、什么是Bean的装配(依赖注入)?什么是Bean的自动装配(自动注入)?
一个个Bean创建出来,没有自动装配(纯净态Bean)时,如果它的一个属性是另一个对象,则没有自动装配时,这个属性自然为空。之前的这种方式是手动装配:
<bean id="bookService" class="com.llg.service.BookService><property name="bookDao" ref="bookDao" />
</bean>----
PS:对应的Java代码:
public class BookService{//...private BookDao bookDao;//...
}
简单说,自动装配即自动注入,就是Spring去建立Bean与Bean之间的依赖关系,对照上面的代码,自动注入即:
public class BookService{//...@Autowiredprivate BookDao bookDao;//...
}
Q9、自动注入有什么限制吗?
答案:
- 一定要声明set方法
- 覆盖:仍然可以用
<constructor-arg> 和 <property>
配置来定义依赖,且这些配置将覆盖自动注入 - 基本数据类型:不能自动装配简单的属性,如自动数据类型、字符串,但手动注入是可以的,如@Value
- 模糊特性,自动装配不如显式装配精确
<bean id="bookService" class="com.llg.service.BookService><property name="bookDao" ref="bookDao1" />
</bean>//比如上面给bookService的bookDao属性装配,不管BookDao类型的Bean有多少,我就只要id为bookDao1的
Q10、自动装配的方式有几种?
在定义bean的xml中,输入autowired属性,就可以看到有5种:
在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用autowire来配置自动装载模式。在Spring框架xml配置中共有5种自动装配:
no
:即默认不自动装配,需要手动设置ref属性来进行装配BeanbyName
:通过bean的名称进行自动装配,如果有一个bean的name和待装配的bean的property相同(对应代码中的setXXX后面的XXX,而不是直接找属性名
),则自动装配byType
:通过参数的类型来自动装配constructor
:利用构造函数进行装配,看构造函数的形参的类型去找
,找到多个时再按形参名自动装配
public Class CarFactory{private Tank tank;public CarFactory(Tank tank) {this.tank = tank; //按构造函数来自动装配}
}
autodetect
:自动探测,若有构造方法,则按construct的方式,没有,则按byType的方式(在Spring3.0已经弃用)