- 1.什么是Spring beans
- 2.一个 Spring Bean 定义包含什么?
- 3.如何给Spring 容器提供配置元数据?Spring有几种配置方式
- 4.Spring配置文件包含了哪些信息
- 5.Spring注入bean的四种方式
- 6.你怎样定义类的作用域?
- 7.解释Spring支持的几种bean的作用域
- 8.Spring框架中的单例bean是线程安全的吗?
- 9.Spring如何处理线程并发问题?
- 10.解释Spring框架中bean的生命周期
- 11.哪些是重要的bean生命周期方法? 你能重载它们吗?
- 12.什么是Spring的内部bean?
- 13.在 Spring中如何注入一个java集合?
- 14.什么是bean装配?
- 15.什么是bean的自动装配?
- 16.bean自动装配的方式
- 17.使用@Autowired注解自动装配的过程是怎样的?
- 18.自动装配有哪些局限性?
- 19.你可以在Spring中注入一个null 和一个空字符串吗?
1.什么是Spring beans
Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以 XML文件中 的形式定义。
2.一个 Spring Bean 定义包含什么?
一个Spring Bean 的定义包含容器必知的所有配置元数据,包括如何创建一个 bean,它的生命周期详情及它的依赖。
3.如何给Spring 容器提供配置元数据?Spring有几种配置方式
这里有三种重要的方法给Spring 容器提供配置元数据。
- XML配置文件。
- 基于注解的配置。
- 基于java的配置。
4.Spring配置文件包含了哪些信息
Spring配置文件是个XML文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用5.Spring注入bean的四种方式
通过xml配置注入bean
<bean id="user" class="com.asong.User"><property name="name" value="asong"></property><property name="age" value="19"></property></bean>
通过配置类和@Bean注解注入bean(@Configuration、@Bean)
@Configurationpublic class Config {//给容器中注册一个bean, 类型为返回值的类型,@Bean("user") //bean的idpublic User user(){return new Person("asong",19);}}
可以和@Conditional连用,此时为条件注入,需要实现Spring提供的Condition接口
@Conditional({xxx.class,xx.class})
@Scope可以设置单例或多例,Spring默认为单例,参数可设置为以下四种 ```java
- prototype:多实例: IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象, 而是每次获取的时候才会调用方法创建对象
- singleton:单实例(默认):IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿(大Map.get)的同一个bean
- request: 主要针对web应用, 递交一次请求创建一个实例
- session:同一个session创建一个实例 ``` @Lazy注解可以设置Bean懒加载,即使用时加载(Spring默认ioc容器创建时加载Bean)
通过配置类和@Import注解注入bean,默认id为类全名(包名+类名)
@Configuration//参数为Bean的class,也可以为ImportSelector和ImportBeanDefinitionRegistrar的实现类class@Import(value = { User.class,Dog.class})public class Config {...}
@Import这里的参数为class数组,可以传入Bean的class,也可以传入ImportSelector和ImportBeanDefinitionRegistrar的实现类class
接口ImportSelector:Spring提供的一个接口,可以指定传入的Bean,需要实现String[] selectImports方法,返回值为Bean类全名的String数组public class CustomImportSelector implements ImportSelector{@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata){//AnnotationMetadata:当前类的注解信息//返回值bean的类全名return new String[]{"com.xx.User","com.xx.Dog"};}}
接口ImportBeanDefinitionRegistrar:Spring提供的一个接口,可以根据需要通过BeanDefinitionRegistry注册器注册Bean ```java public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/ AnnotationMetadata:当前类的注解信息 BeanDefinitionRegistry:BeanDefinition注册类 / @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean bean1 = registry.containsBeanDefinition("com.xxx.User");boolean bean2 = registry.containsBeanDefinition("com.xxx.Dog");// TODO 如果User和Dog同时存在于我们IOC容器中,那么创建Cat类, 加入到容器// 对于我们要注册的bean, 需要使用RootBeanDefinition进行封装if(bean1 && bean2){RootBeanDefinition beanDefinition = new RootBeanDefinition(Cat.class);registry.registerBeanDefinition("cat", beanDefinition);}
}
}
4. **实现FactoryBean接口,和@Bean注解一起使用**```java@Configurationpublic class Config {//通过Spring的工厂bean注册@Beanpublic PigFactoryBean pigFactoryBean(){return new PigFactoryBean();}}
public class PigFactoryBean implements FactoryBean<Pig>{@Overridepublic Pig getObject() throws Exception {// TODO Auto-generated method stubreturn new Pig();}@Overridepublic Class<?> getObjectType() {// TODO Auto-generated method stubreturn Pig.class;}@Overridepublic boolean isSingleton() {return true;}}
6.你怎样定义类的作用域?
当定义一个在Spring里,我们还能给这个bean声明一个作用域。它可以通过 bean 定义中的scope属性来定义。如,当Spring要在需要的时候每次生产一个新的bean实例,bean的scope属性被指定为prototype。另一方面,一个bean 每次使用的时候必须返回同一个实例,这个bean的scope属性必须设为singleton。
7.解释Spring支持的几种bean的作用域
Spring框架支持以下五种bean的作用域
- 1.singleton : bean在每个Spring ioc 容器中只有一个实例。
- 2.prototype:一个bean的定义可以有多个实例。
- 3.request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
- 4.session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效.
- 5.global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
注意: 缺省的Spring bean的作用域是Singleton。使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销。
8.Spring框架中的单例bean是线程安全的吗?
不是,Spring框架中的单例bean不是线程安全的。
spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。
实际上大部分时候 spring bean 无状态的(比如 dao 类),所有某种程度上来 说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域, 把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。
- 有状态就是有数据存储功能。
- 无状态就是不会保存数据。
9.Spring如何处理线程并发问题?
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中, 绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。 ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。 同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。 ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。10.解释Spring框架中bean的生命周期
传统Java应用中,bean的生命周期很简单。使用Java关键字new进行对象实例化之后就可以使用了,一旦bean不再被使用,Java会自动进行垃圾回收。
下图展示了bean装载到Spring应用上下文中的一个典型的生命周期过程。
bean在Spring容器中从创建到销毁经历了若干阶段,每一阶段都可以针对 Spring如何管理bean进行个性化定制。
Spring的初始化主要分为以下流程:
- Spring对bean进行实例化;
- Spring将值和bean的引用注入到bean对应的属性中;
- 如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;
- 如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方 法,将BeanFactory容器实例传入;
- 如果bean实现了ApplicationContextAware接口,Spring将调用 setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的post- ProcessBeforeInitialization()方法;
- 如果bean实现了InitializingBean接口,Spring将调用它们的after- PropertiesSet()方法。
- 如果bean使用initmethod声明了初始化方法, 该方法也会被调用;
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的post- ProcessAfterInitialization()方法;
此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
- 如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。
- 同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。
现在你已经了解了如何创建和加载一个Spring容器。但是一个空的容器并没有太大的价值,在你把东西放进去之前,它里面什么都没有。为了从Spring的 DI(依赖注入)中受益,我们必须将应用对象装配进Spring容器中。
11.哪些是重要的bean生命周期方法? 你能重载它们吗?
有两个重要的bean生命周期方法:
- 第一个是setup , 它是在容器加载bean的时候被调用
- 第二个方法是 teardown 它是在容器卸载类的时候被调用。
bean标签有两个比较重要的注解:@PostConstruct和@PreDestroy注解,用他们可以自己定制初始化和注销的方法。
12.什么是Spring的内部bean?
内部bean:一个bean仅被作用作另一个bean的属性。就是说,一个bean是另外一个bean的属性。内部bean通常是匿名的,他们的Scope一般是prototype。
13.在 Spring中如何注入一个java集合?
Spring提供以下几种集合的配置元素:
- 类型用于注入一列值,允许有相同的值。
- 类型用于注入一组值,不允许有相同的值。
- 类型用于注入一组键值对,键和值都只能为String类型。
14.什么是bean装配?
bean装配就是Spring容器把bean组装到一起
15.什么是bean的自动装配?
传统spring项目中,使用xml配置方式如果想要bean进行注入,需要手动编写xml文件。每创建一个类就需要编写一个xml文件注入spring容器。Spring提供了自动装配的操作,可以通过向Bean Factory中注入的方式自动搞定bean之间的依赖关系。自动装配可以设置在每个bean上,可以设置在特定的bean上。
16.bean自动装配的方式
使用autowire来配置自动装配模式。在xml配置中有五种自动装配。
- no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行 装配bean。
- byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
- byType:通过参数的数据类型进行自动装配。
- constructor:利用构造函数进行装配,并且构造函数的参数通过 byType进行装配。
autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。
17.使用@Autowired注解自动装配的过程是怎样的?
在启动spring IoC时,容器自动装载了一个 AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到 @Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的 bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
- 如果查询的结果不止一个,那么@Autowired会根据名称来查找;
如果上述查找的结果为空,那么会抛出异常。解决方法时,使用 required=false。
18.自动装配有哪些局限性?
重写:你仍需用和配置来定义依赖,意味着总要重写自动装配。
- 基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串和类。
- 模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。
19.你可以在Spring中注入一个null 和一个空字符串吗?
可以。可以放到对象当中,进行注入,使用注解的话,可以直接设置为null或者空串,使用xml也是一样,如下: ```xml 解决方法:
