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的四种方式

  1. 通过xml配置注入bean

    1. <bean id="user" class="com.asong.User">
    2. <property name="name" value="asong"></property>
    3. <property name="age" value="19"></property>
    4. </bean>
  2. 通过配置类和@Bean注解注入bean(@Configuration、@Bean)

    1. @Configuration
    2. public class Config {
    3. //给容器中注册一个bean, 类型为返回值的类型,
    4. @Bean("user") //bean的id
    5. public User user(){
    6. return new Person("asong",19);
    7. }
    8. }

    可以和@Conditional连用,此时为条件注入,需要实现Spring提供的Condition接口

    1. @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)
  1. 通过配置类和@Import注解注入bean,默认id为类全名(包名+类名)

    1. @Configuration
    2. //参数为Bean的class,也可以为ImportSelector和ImportBeanDefinitionRegistrar的实现类class
    3. @Import(value = { User.class,Dog.class})
    4. public class Config {
    5. ...
    6. }

    @Import这里的参数为class数组,可以传入Bean的class,也可以传入ImportSelector和ImportBeanDefinitionRegistrar的实现类class
    接口ImportSelector:Spring提供的一个接口,可以指定传入的Bean,需要实现String[] selectImports方法,返回值为Bean类全名的String数组

    1. public class CustomImportSelector implements ImportSelector{
    2. @Override
    3. public String[] selectImports(AnnotationMetadata importingClassMetadata){
    4. //AnnotationMetadata:当前类的注解信息
    5. //返回值bean的类全名
    6. return new String[]{"com.xx.User","com.xx.Dog"};
    7. }
    8. }

    接口ImportBeanDefinitionRegistrar:Spring提供的一个接口,可以根据需要通过BeanDefinitionRegistry注册器注册Bean ```java public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    / AnnotationMetadata:当前类的注解信息 BeanDefinitionRegistry:BeanDefinition注册类 / @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    1. boolean bean1 = registry.containsBeanDefinition("com.xxx.User");
    2. boolean bean2 = registry.containsBeanDefinition("com.xxx.Dog");
    3. // TODO 如果User和Dog同时存在于我们IOC容器中,那么创建Cat类, 加入到容器
    4. // 对于我们要注册的bean, 需要使用RootBeanDefinition进行封装
    5. if(bean1 && bean2){
    6. RootBeanDefinition beanDefinition = new RootBeanDefinition(Cat.class);
    7. registry.registerBeanDefinition("cat", beanDefinition);
    8. }

    }

}

  1. 4. **实现FactoryBean接口,和@Bean注解一起使用**
  2. ```java
  3. @Configuration
  4. public class Config {
  5. //通过Spring的工厂bean注册
  6. @Bean
  7. public PigFactoryBean pigFactoryBean(){
  8. return new PigFactoryBean();
  9. }
  10. }
  1. public class PigFactoryBean implements FactoryBean<Pig>{
  2. @Override
  3. public Pig getObject() throws Exception {
  4. // TODO Auto-generated method stub
  5. return new Pig();
  6. }
  7. @Override
  8. public Class<?> getObjectType() {
  9. // TODO Auto-generated method stub
  10. return Pig.class;
  11. }
  12. @Override
  13. public boolean isSingleton() {
  14. return true;
  15. }
  16. }

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应用上下文中的一个典型的生命周期过程。
image.png
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 解决方法:


```