GVKun编程网logo

Spring 源码:Spring IoC 容器加载过程(2)(spring容器加载流程)

11

想了解Spring源码:SpringIoC容器加载过程的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于2的相关问题,此外,我们还将为您介绍关于1.spring5源码系列--Spring整体脉

想了解Spring 源码:Spring IoC 容器加载过程的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于2的相关问题,此外,我们还将为您介绍关于1. spring5源码系列 -- Spring整体脉络 IOC加载过程 Bean的生命周期、Ioc容器依赖注入-Spring 源码(2)、Spring Boot教程(三十一)使用Spring-data-jpa(2)、Spring Boot教程(二十三)关于集成 Spring Cache(2)的新知识。

本文目录一览:

Spring 源码:Spring IoC 容器加载过程(2)(spring容器加载流程)

Spring 源码:Spring IoC 容器加载过程(2)(spring容器加载流程)

 Spring 源码版本:4.3.23.RELEASE

一、加载 XML 配置

通过 XML 配置创建 Spring,创建入口是使用 org.springframework.context.support.ClassPathXmlApplicationContext 类,创建容器的代码如下:

 1 package hello;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 public class HelloWorld
 7 {
 8     public static void main(String[] args) {
 9         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
10         System.out.println(context.getBean("hello.Dog", Dog.class).name);
11         System.out.println(context.getBean("hello.Dog#0", Dog.class).name);
12     }
13 }
14 
15 class Dog {
16     String name = "PiPi";
17 }
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
5 
6     <bean class="hello.Dog"/>
7 
8 </beans>

 

1.1 如果 bean 没有配置 id 或 name 属性,那 Spring 会取 class 属性值(也就是全限定类名)加#index(index 为 bean 对象在容器里的序号)作为 name,取类全限定名作为别名 aliases。具体看下面源码:

org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java#parseBeanDefinitionElement

 1     /**
 2      * Parses the supplied {@code <bean>} element. May return {@code null}
 3      * if there were errors during parse. Errors are reported to the
 4      * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
 5      */
 6     public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
 7         String id = ele.getAttribute(ID_ATTRIBUTE);
 8         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
 9 
10         List<String> aliases = new ArrayList<String>();
11         if (StringUtils.hasLength(nameAttr)) {
12             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
13             aliases.addAll(Arrays.asList(nameArr));
14         }
15 
16         String beanName = id;
17         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
18             beanName = aliases.remove(0);
19             if (logger.isDebugEnabled()) {
20                 logger.debug("No XML ''id'' specified - using ''" + beanName +
21                         "'' as bean name and " + aliases + " as aliases");
22             }
23         }
24 
25         if (containingBean == null) {
26             checkNameUniqueness(beanName, aliases, ele);
27         }
28 
29         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
30         if (beanDefinition != null) {
31             if (!StringUtils.hasText(beanName)) {
32                 try {
33                     if (containingBean != null) {
34                         beanName = BeanDefinitionReaderUtils.generateBeanName(
35                                 beanDefinition, this.readerContext.getRegistry(), true);
36                     }
37                     else {
38                         beanName = this.readerContext.generateBeanName(beanDefinition);  //获取到的bean名称为com.example.Hello#0这样的格式,#后面的数字为该类对象在进程中的编号。
39                         // Register an alias for the plain bean class name, if still possible,
40                         // if the generator returned the class name plus a suffix.
41                         // This is expected for Spring 1.2/2.0 backwards compatibility.
42                         String beanClassName = beanDefinition.getBeanClassName(); //获取class属性配置的bean的类名(全限定类名)
43                         if (beanClassName != null &&
44                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
45                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
46                             aliases.add(beanClassName);  //使用全限定类名作为别名
47                         }
48                     }
49                     if (logger.isDebugEnabled()) {
50                         logger.debug("Neither XML ''id'' nor ''name'' specified - " +
51                                 "using generated bean name [" + beanName + "]");
52                     }
53                 }
54                 catch (Exception ex) {
55                     error(ex.getMessage(), ele);
56                     return null;
57                 }
58             }
59             String[] aliasesArray = StringUtils.toStringArray(aliases);
60             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  //创建bean定义对象
61         }
62 
63         return null;
64     }

 

1.2 Bean 的定义加载到一个 ConcurrentHashMap,key 为 bean 名称,value 为 org.springframework.beans.factory.config.BeanDefinition:

org.springframework.beans.factory.support.DefaultListableBeanFactory#beanDefinitionMap

/** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition

 1     //---------------------------------------------------------------------
 2     // Implementation of BeanDefinitionRegistry interface
 3     //---------------------------------------------------------------------
 4 
 5     @Override
 6     public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
 7             throws BeanDefinitionStoreException {
 8 
 9         Assert.hasText(beanName, "Bean name must not be empty");
10         Assert.notNull(beanDefinition, "BeanDefinition must not be null");
11 
12         if (beanDefinition instanceof AbstractBeanDefinition) {
13             try {
14                 ((AbstractBeanDefinition) beanDefinition).validate();
15             }
16             catch (BeanDefinitionValidationException ex) {
17                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
18                         "Validation of bean definition failed", ex);
19             }
20         }
21 
22         BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
23         if (existingDefinition != null) {
24             if (!isAllowBeanDefinitionOverriding()) {
25                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
26                         "Cannot register bean definition [" + beanDefinition + "] for bean ''" + beanName +
27                         "'': There is already [" + existingDefinition + "] bound.");
28             }
29             else if (existingDefinition.getRole() < beanDefinition.getRole()) {
30                 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
31                 if (logger.isWarnEnabled()) {
32                     logger.warn("Overriding user-defined bean definition for bean ''" + beanName +
33                             "'' with a framework-generated bean definition: replacing [" +
34                             existingDefinition + "] with [" + beanDefinition + "]");
35                 }
36             }
37             else if (!beanDefinition.equals(existingDefinition)) {
38                 if (logger.isInfoEnabled()) {
39                     logger.info("Overriding bean definition for bean ''" + beanName +
40                             "'' with a different definition: replacing [" + existingDefinition +
41                             "] with [" + beanDefinition + "]");
42                 }
43             }
44             else {
45                 if (logger.isDebugEnabled()) {
46                     logger.debug("Overriding bean definition for bean ''" + beanName +
47                             "'' with an equivalent definition: replacing [" + existingDefinition +
48                             "] with [" + beanDefinition + "]");
49                 }
50             }
51             this.beanDefinitionMap.put(beanName, beanDefinition);
52         }
53         else {
54             if (hasBeanCreationStarted()) {
55                 // Cannot modify startup-time collection elements anymore (for stable iteration)
56                 synchronized (this.beanDefinitionMap) {
57                     this.beanDefinitionMap.put(beanName, beanDefinition);
58                     List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
59                     updatedDefinitions.addAll(this.beanDefinitionNames);
60                     updatedDefinitions.add(beanName);
61                     this.beanDefinitionNames = updatedDefinitions;
62                     if (this.manualSingletonNames.contains(beanName)) {
63                         Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
64                         updatedSingletons.remove(beanName);
65                         this.manualSingletonNames = updatedSingletons;
66                     }
67                 }
68             }
69             else {
70                 // Still in startup registration phase
71                 this.beanDefinitionMap.put(beanName, beanDefinition);
72                 this.beanDefinitionNames.add(beanName);
73                 this.manualSingletonNames.remove(beanName);
74             }
75             this.frozenBeanDefinitionNames = null;
76         }
77 
78         if (existingDefinition != null || containsSingleton(beanName)) {
79             resetBeanDefinition(beanName);
80         }
81     }

 

1. spring5源码系列 -- Spring整体脉络 IOC加载过程 Bean的生命周期

1. spring5源码系列 -- Spring整体脉络 IOC加载过程 Bean的生命周期

 

目录

1. spring整体脉络

2 描述beanfactory

3. beanfactory和ApplicationContext的区别

4. 简述SpringIoC的加载过程

5. 简述Bean的生命周期

6. Spring中有哪些扩展接口及调用机制

 

一. spring源码整体脉络介绍及源码编译

 1.1. 什么是IOC

ioc是控制反转,这是一种设计理念,用来解决的是层和层之间,类和类之间的耦合问题.

比如,现在有A,B两个类,在A类中引用了B类. 那么如果有一天,B类要被替换掉,我们会怎么办呢?如果B类被引用了100次,我们要替换100次?

现在呢,A是直接调用B,如果我们间接的调用B,将B包装起来,如果以后将B换成C,只需要在包装类里面替换就可以了. 我们不需要修改A类. 这就是控制反转.

 

Spring使用了ioc,Spring.ioc(A,B) 将A和B的引用都存在ioc中,spring会帮我们维护好,完全不用担心.

当我们在A中要使用B的时候,使用B对应的接口,然后使用@Autowired注解

A {
   @Autowired
   private IB b;  
}

什么时候把B换掉了,不痛不痒的,只需要把新的类放到IoC中就可以了.

1.2. Spring源码的整体脉络梳理

Spring IoC是一个容器,在Spring Ioc中维护了许多Bean

那这些bean是如何被注册到IoC中的呢? 换句话说,我们自定义的类,是如何作为一个bean交给IoC容器去管理的呢?

先来回忆,我们在开发spring的时候的步骤: 

第一步: 配置类. 配置类可以使用的方式通常由
      1) xml配置
      2) 注解配置
      3) javaconfig方式配置
第二步: 加载spring上下文
      1) 如果是xml,则new ClasspathXmlApplicationContext("xml");
      2) 如果是注解配置: 则new AnnotationConfigApplicationContext(config.class)

第三步: getBean() 
我们会讲自定义的类,通过xml或者注解的方式注入到ioc容器中.

在这一步,会将xml或注解中指定的类注入到IoC容器中. 

1.2.1 那么,到底是如何将一个类注入到ioc中的呢? 

下面就来梳理一下整个过程. 

第一问: 一个类要生产成一个Bean,最重要最核心的类是什么?

是beanfactory

 

第二问: beanfactory是什么呢?

beanfactory是Spring顶层的核心接口--使用了简单工厂模式. 通常都是根据一个名字生产一个实例,根据传入的唯一的标志来获得bean对象,但具体是穿入参数后创建,还是穿入参数前创建,这个要根据 具体情况而定,根据名字或类型生产不同的bean. 

一句话总结: beanfactory的责任就是生产Bean

来看下面这段代码: 

public static void main( String[] args ) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.getBean("***");
    }

这段代码实现的功能是,读取当前文件所在目录及其子目录中的文件,然后获取指定名称的bean,整个流程如下图所示: 

 

首先,通过ClasspathXmlApplicationContext或者AnnotationConfigApplicationContext去读取配置,然后将其交给beanfactory.

第三. beanfactory调用getBean()方法,将Bean注入到IoC容器中

我们发现,配置的读取,可能是xml方式,也可能是annotation的方式, 不同的方式读取应该使用的是不同的工具. 那么这些工具读取的结果应该是统一的,然后才能交给beanfactory去处理.

因为在beanfactory中是不会对这些异同点进行处理的. beanfactory的作用只有一个,就是个生产Bean

1.2.2 那么,不同的工具读取配置是如何统一的呢?

我们知道,读取配置这一块,应该会有一个不同的实现. 将xml和注解方式读取成统一的东西,放入到beanfactory中. 这个东西是谁呢?就是BeanDeFinition(Bean定义) 

什么意思呢? 如下图:

 

 看绿色框框住的部分. 这个含义是: 通过不同的工具,可能是xmlApplicationContext,可能是annotationApplicationContext工具 读取的配置,最后都会构造成BeanDeFinition对象. 然后将BeanDeFinition传递给beanfactory,beanfactory统一处理BeanDeFinition对象,调用getBean()方法,将其放入IoC容器中.

 

1.2.3 那么又是是如何读取配置统一构造成BeanDeFinition的呢?

我们来举个例子,现在有一个人,比如说我刚买了一个房子,我要装修. 需要一个衣柜,这时候,我会找到一个衣柜店. 然后告诉他我的需求,柜子的颜色,款式格式什么样. 然后衣柜店记录我的需求,这个时候,他不会自己生产,他会通知工厂,让工厂来生产. 工厂按照什么生产呢,衣柜店有一个设计师, 他们的设计师. 会按照我的需求设计出一张图纸. 然后将图纸交给工厂. 工厂按照图纸要求生产Bean. 

整个过程如下图:

 

 

 入口是"我"

1. 我有一个需求,打一个柜子,找到衣柜店

2. 我告诉衣柜店我的需求,款式,然后衣柜店的设计师按照我的要求,设计出一张图纸

3. 衣柜店将图纸给到工厂,工厂按照图纸生产柜子

这是制造衣柜的过程. 其中在画图纸的时候,画一张就给工厂给一张,这样效率太低了. 我们可以画了n张,一起给工厂. 所以,在设计图纸这块是一个容器,存放多张图纸

 

后面,如果我还想定制一个橱柜店. 那么,就告诉设计师我的橱柜的颜色,就可以了. 流程和上面都是一样的. 

 

 

整个这个过程,就类似于我们的bean生产的过程

 

1. 定义了一个带有@Component注解的类,我找到衣柜店,衣柜店就类似于ApplicationContext.

2. 我告诉ApplicationContext我的需求,我要懒加载@Lazy,设置单例模式还是多例模式@Scope. 对应的就是定制柜子的颜色,款式. 然后衣柜店里的设计师BeanDeFinitionRegistry根据我的需求设计出图纸,也就是构造成BeanDeFinition. 不同的BeanDeFinitionRegistry设计出不同的BeanDeFinition,然后将他们都放在容器中.

3. 衣柜店ApplicationContext统一将一摞图纸BeanDeFinitionMap交给工厂,  然后工厂按照要求生产Bean,然后将生成的bean放入到IoC容器中.

 

这是一个带有@Component的类被加载的过程. 

 

衣柜店要要想生意好,那么他要去拉活呀,所以还需要好的销售. 销售要去扫楼盘,去联系,哪些人有装修的需求. 挨个询问. 

可是问了100个人,可能只有10个人有装修的需求. 于是还要有一个接待,这个接待要联系客户,看看哪些是有意向的客户,将其筛选出来. 然后定制家具.

这里多了两类人: 销售和接待. 具体工作如下.

 

销售就相当于我们的BeanDeFinitionReader,他的作用是去扫楼盘,找到潜在客户. 对应的就是BeanDeFinitionReader去读取xml配置或者Annotation注解. 

xml中的配置有很多,注解也有很多,并不都是我们的目标. 于是有了接待

接待要去扫描所有潜在客户. 将有意向的客户扫描出来. 这就类似于我们的BeanDeFinitionScanner,去扫描潜在客户,最后将带有@Component注解的类筛选出来

这就是后面需要定制家具的客户了

BeanDeFinitionReader对应的就去读取配置类,看看有哪些需求需要搞装修.


它本身也是一个抽象类,可以看到他有AnnotationBeanDeFinitionReader和XmlBeanDeFinitionReader


我们配置了配置包,去扫描这个包下所有的类,然后将扫描到的所有的类交给BeanDeFinitionScanner,它会去过滤带有@Component的类. 

在和上面的流程连接起来,就是整个配置文件被加载到IoC的过程了. 

 

1.3. ApplicationContext和factorybean的区别

1. factorybean的功能就是生产bean. 他生产bean是根据BeanDeFinition来生产的. 所以,一次只能生产一个

2. ApplicationContext有两种. 一种是xmlApplicationContext,另一种是annotationApplicationContext,他传入的参数是一个配置文件. 也就是可以加载某个目录下所有带有@Component的类

他们两个都各有使用场景. 使用ApplicationContext的居多.

 

另一个区别: 就是后面会说到的,ApplicationContext有两个扩展接口,可以用来和外部集成. 比如和MyBatis集成.

 

 

 

 

1.4. Bean的生命周期

 

 

如上图,beanfactory拿到BeanDeFinition,直接调用getBean()就生产Bean了么? 

不是的,生产Bean是有一个流程的. 下面我们来看看Bean的生命周期

 

第一步: 实例化. bean实例化的时候从BeanDeFinition中得到Bean的名字,然后通过反射机制,将Bean实例化. 实例化以后,这是还只是个壳子,里面什么都没有.

第二步: 填充属性. 经过初始化以后,bean的壳子就有了,bean里面有哪些属性呢? 在这一步填充


第三步: 初始化. 初始化的时候,会调用initMethod()初始化方法,destory()初始化结束方法

这个时候,类就被构造好了.

第四步: 构造好了的类,会被放到IoC的一个Map中. Map的key是beanName,value是bean实例. 这个Map是一个单例池,也就是我们说的一级缓存


第五步: 我们就可以通过getBean("user"),从单例池中获取雷鸣是user的类了.

 

 在构造bean的过程中,还会有很多细节的问题,比如循环依赖.

 

 

 A类里面调用了B类,所以beanfactory在构造A的时候,会去构造B. 然后在构造B的时候,发现,B还依赖了A. 这样,就是循环依赖. 这是不可以的. 

Spring是如何解决循环依赖的问题的呢? 

设置出口. 比如A在构造的过程中,那么设置一个标记,正在构造中. 然后构造B,B在构造的过程中应用了A,有趣构造A,然后发现A正在构造中,那么,就不会再次构造A了. 

后面还会详细讲解Spring是如何解决循环引用的. 这里我们需要知道的是: Spring使用的是三级缓存来解决循环引用的问题

 其实,bean是存在一级缓存里面,循环引用使用的是三级缓存来解决的. 其实,一、二、三级缓存就是Map。

 

1.5. Spring中的扩展接口

有两个非常重要的扩展接口. beanfactoryPostProcessor(Bean工厂的后置处理器) 和 BeanDeFinitionRegistryPostProcessor

这两个接口是干什么的呢? 

我们在这个图里面,看到了设计师要设计出图纸,然后把图纸交给工厂去生产. 那么设计师设计出来的图纸,有没有可能被修改呢?

当然是可以被修改的. 只要还没有交给工厂,就可以修改.

beanfactoryPostProcessor(Bean工厂的后置处理器)的作用就是修改BeanDeFinition.

1. beanfactoryPostProcessor: 修改BeanDeFinition.

是一个接口,我们的类可以实现这个接口,然后重写里面的方法

public class DefinedPost implements beanfactoryPostProcessor {

    /**
     * 重写Bean工厂的后置处理器
     * @param beanfactory
     * @throws BeansException
     */
    @Override
    public void postProcessbeanfactory(ConfigurableListablebeanfactory beanfactory) throws BeansException {
        // beanfactory 拿到工厂了,就可以获取某一个Bean定义了
        GenericBeanDeFinition car = (GenericBeanDeFinition) beanfactory.getBeanDeFinition("Car");
        // 拿到了car,然后修改了Car的类名为com.example.tulingcourse.Tank. 那么后面在获取的Bean里面,将其转换为Car,就会报错了
        car.setBeanClassName("com.example.tulingcourse.Tank");
    }
}

第一步: 实现了beanfactoryPostProcessor接口,然后需要重写里面的方法

第二步: 我们发现重写方法直接给我们了beanfactory,bean工厂

第三步: 拿到bean工厂,我们就可以根据名称获取BeanDeFinition,也就是bean定义了. 

第四步: 我们修改了bean定义中的类名为Tank. 

 

这时候会发生什么呢? 从bean工厂中构建的car,取出来以后转换成Car对象,会报错,

public static void main(String[] args) {
    

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
    
        Car car = context.getBean("car",Car.class); // 这里会报错,因为已经被修改
        System.out.println(car.getName());
    }

 

执行流程: 当spring启动的时候,就会去执行AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TulingCourseApplication.class);

然后ApplicationContext回去扫描所有实现了beanfactoryPostProcessor对象的类,然后执行postProcessbeanfactory方法. 

 

beanfactoryPostProcessor被使用到的场景非常多,在集成其他组件的时候,比如集成mybatis

 

2. BeanDeFinitionRegistryPostProcessor 注册BeanDeFinition

这是一个Bean定义注册的后置处理器.BeanDeFinitionRegistryPostProcessor本事是实现了beanfactoryPostProcessor 接口

 

 我们来看个demo

public class DefinedPost implements BeanDeFinitionRegistryPostProcessor {

    /**
     * 重写Bean工厂的后置处理器
     * @param beanfactory
     * @throws BeansException
     */
    @Override
    public void postProcessbeanfactory(ConfigurableListablebeanfactory beanfactory) throws BeansException {
        // beanfactory 拿到工厂了,就可以获取某一个Bean定义了
        GenericBeanDeFinition car = (GenericBeanDeFinition) beanfactory.getBeanDeFinition("Car");
        // 拿到了car,就会报错了
        car.setBeanClassName("com.example.tulingcourse.Tank");
    }

    @Override
    public void postProcessBeanDeFinitionRegistry(BeanDeFinitionRegistry beanDeFinitionRegistry) throws BeansException {

    }
}

一个类实现了BeanDeFinitionRegistryPostProcessor,需要重写postProcessBeanDeFinitionRegistry方法,这个方法直接将BeanDeFinitionRegistry就给我们了. 

然后使用beanDeFinitionRegistry.registerBeanDeFinition(); 就可以添加图纸了

在这里可以注册新的bean,也可以删除注册的bean. 多注册一个,bean工厂就要多构建一个. 

 

总结:

    beanfactoryPostProcessor和BeanDeFinitionRegistryPostProcessor这两个扩展类是很重要的类, 这对于向外部扩展起到了很大的的作用,比如: 集成mybatis

beanfactoryPostProcessor和BeanDeFinitionRegistryPostProcessor是在ApplicationContext中的两个扩展接口. 这也是ApplicationContext和beanfactory的区别之一,因为有了这两个扩展节点,就可以和外部做集成. 比如Mybatis集成.  比如: 扫描配置类,就是通过 这两个扩展点的方式实现的.

 

这个扩展点的作用:

1. 除了IoC,其他的扩展,比如AOP,和MyBatis集成,都要用到这两个扩展点. 之所以Spring能够有序不乱的和很多外部组件整合,都是这两个扩展点的功能

 

1.6 Bean的扩展点

除了ApplicationContext有扩展点,  在Spring IoC中的bean也有扩展点. BeanPostProcessor(Bean的后置处理器). 如果使用在getBean()之前,那么可以阻止构建Bean,还可以自定义构建Bean.

 

BeanPostProcessor使用的场景有很多. 在Bean实例化之前和之后会被调用.  在填充属性之前和之后也会被调用,初始化之前和之后也会调用. 有些过程不只调用一次. 整个过程一共会调用9次. 在每一个过程都可以扩展Bean.

 

思考: Spring加入AOP是如何实现呢?

集成AOP肯定不会和IoC糅合在一块了. AOP就是通过BeanPostProcessor(Bean后置处理器)整合进来的.

AOP的实现方式有两种: 一种是cglib,另一种是JDK. 

假如说要进行集成,会在那个步骤继承呢? 比如要加日志,使用AOP的方式加. 我们通常是在初始化之后加AOP. 在这里将AOP集成进来.

 

如上图: 当面试的时候面试官问你,Bean的生命周期,我们不能只说实例化-->填充属性-->初始化. 还需要说初始化的时候,还有一些列的aware.

1.7. Spring IOC的加载过程

 

 

对照上图,我们来简述ioc的加载过程 

我们将一个类加载成Bean,不是一步到位的,需要经历一下的过程. 

1. 首先,我们要将类加载成BeanDeFinition(Bean定义)

  加载成bean定义,有以下几个步骤:

  1) 使用BeanDeFinitionReader加载配置类,此时是扫描所有的xml文件或者项目中的注解. 这里面有些使我们的目标类,有些不是

  2) 使用BeanDeFinitionScanner扫描出我们的目标类. 

  3) 使用BeanDeFinitionRegistry注册bean到BeanDeFinitionMap中.

2. 然后,ApplicationContext可以调用beanfactoryPostProcessor修改bean定义,还可以调用BeanDeFinitionRegistryPostProcessor注册bean定义

3. 将BeanDeFinition交给beanfactory处理,beanfactory调用getBean()生成Bean或者调用Bean(getBean()有两个功能). 

4. 成产bean的时候,首先会实例化,然后填充属性(主要是读取@Autowire,@Value等注解). 在初始化Bean,这里会调用initMethod()方法和初始化销毁方法destroy(). 初始化的时候还会调用一堆的Aware,而且在bean生成的过程中 会有很多扩展点,供我们去扩展.

5. 将生产出的Bean放入到Map中,map是一个一级缓存池. 后面,我们可以通过getBean("user")从缓存池中获取bean

 

Ioc容器依赖注入-Spring 源码(2)

Ioc容器依赖注入-Spring 源码(2)

Ioc容器依赖注入-Spring 源码(2)

目录:

Ioc容器beanDeFinition-Spring源码(1)

Ioc容器依赖注入-Spring 源码(2)

Ioc容器BeanPostProcessor-Spring 源码(3)

上篇中组装出了一个beanName:beanDeFinition的ConcurrentHashMap,接下来就是把这些bean像织网一样联系起来。

从Abstractbeanfactory的getBean方法入手:

  @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name,null,false);
    }

    @Override
    public <T> T getBean(String name,Class<T> requiredType) throws BeansException {
        return doGetBean(name,requiredType,false);
    }

    @Override
    public Object getBean(String name,Object... args) throws BeansException {
        return doGetBean(name,args,false);
    }

    public <T> T getBean(String name,Class<T> requiredType,false);
    }

doGetBean方法:

protected <T> T doGetBean(
      final String name,final Class<T> requiredType,final Object[] args,boolean typeCheckOnly)
      throws BeansException {
   //筛选出null,&符号的代表自身
   final String beanName = transformedBeanName(name);
   Object bean;

   // 先获取从单例缓存中获取单例的bean,无需再进行实例化去创建了
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      // 是factorybean情况
      bean = getobjectForBeanInstance(sharedInstance,name,beanName,null);
   }

   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // Check if bean deFinition exists in this factory.
      beanfactory parentbeanfactory = getParentbeanfactory();
      if (parentbeanfactory != null && !containsBeanDeFinition(beanName)) {
         // Not found -> check parent.
         String nametoLookup = originalBeanName(name);
         if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentbeanfactory.getBean(nametoLookup,args);
         }
         else {
            // No args -> delegate to standard getBean method.
            return parentbeanfactory.getBean(nametoLookup,requiredType);
         }
      }

      if (!typeCheckOnly) {
         markBeanAsCreated(beanName);
      }

      try {
         final RootBeanDeFinition mbd = getMergedLocalBeanDeFinition(beanName);
         checkMergedBeanDeFinition(mbd,args);

         // 获取这个bean依赖的对象,进入for循环迭代调用getBean方法,开始织网
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dependsOnBean : dependsOn) {
               if (isDependent(beanName,dependsOnBean)) {
                  throw new BeanCreationException(mbd.getResourceDescription(),"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
               }
               registerDependentBean(dependsOnBean,beanName);
               // 迭代
               getBean(dependsOnBean);
            }
         }

         // 最终创建bean
         // 单例
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName,new ObjectFactory<Object>() {
               @Override
               public Object getobject() throws BeansException {
                  try {
                     return createBean(beanName,mbd,args);
                  }
                  catch (BeansException ex) {
                     // Explicitly remove instance from singleton cache: It might have been put there
                     // eagerly by the creation process,to allow for circular reference resolution.
                     // Also remove any beans that received a temporary reference to the bean.
                     destroySingleton(beanName);
                     throw ex;
                  }
               }
            });
            bean = getobjectForBeanInstance(sharedInstance,mbd);
         }
        // 多例
         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               prototypeInstance = createBean(beanName,args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            bean = getobjectForBeanInstance(prototypeInstance,mbd);
         }
        // 自定义配置的scop
         else {
            String scopeName = mbd.getScope();
            final Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
               throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
               Object scopedInstance = scope.get(beanName,new ObjectFactory<Object>() {
                  @Override
                  public Object getobject() throws BeansException {
                     beforePrototypeCreation(beanName);
                     try {
                        return createBean(beanName,args);
                     }
                     finally {
                        afterPrototypeCreation(beanName);
                     }
                  }
               });
               bean = getobjectForBeanInstance(scopedInstance,mbd);
            }
            catch (IllegalStateException ex) {
               throw new BeanCreationException(beanName,"Scope '" + scopeName + "' is not active for the current thread; consider " +
                     "defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex);
            }
         }
      }
      catch (BeansException ex) {
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }

   // Check if required type matches the type of the actual bean instance.
   if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
      try {
         return getTypeConverter().convertIfNecessary(bean,requiredType);
      }
      catch (TypeMismatchException ex) {
         if (logger.isDebugEnabled()) {
            logger.debug("Failed to convert bean '" + name + "' to required type [" +
                  ClassUtils.getQualifiedname(requiredType) + "]",ex);
         }
         throw new BeanNotOfrequiredTypeException(name,bean.getClass());
      }
   }
   return (T) bean;
}

无论单例还是多例模式的scop都是调用AbstractAutowireCapablebeanfactory的createBean方法->doCreateBean方法来创建bean:

protected Object createBean(String beanName,RootBeanDeFinition mbd,Object[] args) throws BeanCreationException {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating instance of bean '" + beanName + "'");
   }
   RootBeanDeFinition mbdToUse = mbd;

   // Make sure bean class is actually resolved at this point,and
   // clone the bean deFinition in case of a dynamically resolved Class
   // which cannot be stored in the shared merged bean deFinition.
   Class<?> resolvedClass = resolveBeanClass(mbd,beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDeFinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }

   // Prepare method overrides.
   try {
      mbdToUse.prepareMethodoverrides();
   }
   catch (BeanDeFinitionValidationException ex) {
      throw new BeanDeFinitionStoreException(mbdToUse.getResourceDescription(),"Validation of method overrides Failed",ex);
   }

   try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      Object bean = resolveBeforeInstantiation(beanName,mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(),"BeanPostProcessor before instantiation of bean Failed",ex);
   }

   Object beanInstance = doCreateBean(beanName,mbdToUse,args);
   if (logger.isDebugEnabled()) {
      logger.debug("Finished creating instance of bean '" + beanName + "'");
   }
   return beanInstance;
}
protected Object doCreateBean(final String beanName,final RootBeanDeFinition mbd,final Object[] args) {
        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factorybeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName,args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

        // Allow post-processors to modify the merged bean deFinition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                applyMergedBeanDeFinitionPostProcessors(mbd,beanType,beanName);
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like beanfactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName,new ObjectFactory<Object>() {
                @Override
                public Object getobject() throws BeansException {
                    return getEarlyBeanReference(beanName,bean);
                }
            });
        }

        // Initialize the bean instance.
        Object exposedobject = bean;
        try {
            populateBean(beanName,instanceWrapper);
            if (exposedobject != null) {
                exposedobject = initializeBean(beanName,exposedobject,mbd);
            }
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(mbd.getResourceDescription(),"Initialization of bean Failed",ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName,false);
            if (earlySingletonReference != null) {
                if (exposedobject == bean) {
                    exposedobject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference,but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off,for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            registerdisposableBeanIfNecessary(beanName,bean,mbd);
        }
        catch (BeanDeFinitionValidationException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(),"Invalid destruction signature",ex);
        }

        return exposedobject;
    }

以上的单例部分交由DefaultSingletonBeanRegistry管理,采用Registry of Singleton 模式,我在单例的文章里也补充了

可以想象:网由点和线组成

1,createBeanInstance(beanName,args)生成包装了bean的对象,就是生成好点。

protected BeanWrapper createBeanInstance(String beanName,Object[] args) {
        // Make sure bean class is actually resolved at this point.
        Class<?> beanClass = resolveBeanClass(mbd,beanName);

        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(),"Bean class isn't public,and non-public access not allowed: " + beanClass.getName());
        }
    // 工厂方法创建bean
        if (mbd.getFactoryMethodName() != null)  {
            return instantiateUsingFactoryMethod(beanName,args);
        }

        // Shortcut when re-creating the same bean...
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorargumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorargumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                return autowireConstructor(beanName,null);
            }
            else {
                return instantiateBean(beanName,mbd);
            }
        }

        // 使用构造函数创建bean
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass,beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDeFinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasconstructorargumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName,ctors,args);
        }

        // 使用默认的构造函数创建bean
        return instantiateBean(beanName,mbd);
    }
    // 使用默认的构造函数创建bean
    protected BeanWrapper instantiateBean(final String beanName,final RootBeanDeFinition mbd) {
        try {
            Object beanInstance;
            final beanfactory parent = this;
            if (System.getSecurityManager() != null) {
                beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    @Override
                    public Object run() {
                      //
                        return getInstantiationStrategy().instantiate(mbd,parent);
                    }
                },getAccessControlContext());
            }
            else {
                beanInstance = getInstantiationStrategy().instantiate(mbd,parent);
            }
            BeanWrapper bw = new BeanWrapperImpl(beanInstance);
            initBeanWrapper(bw);
            return bw;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(),"Instantiation of bean Failed",ex);
        }
    }

SimpleInstantiationStrategy的instantiate(RootBeanDeFinition bd,String beanName,beanfactory owner)方法:

public Object instantiate(RootBeanDeFinition bd,beanfactory owner) {
   // 如果没有override method 就走构造函数 否则走cglib
   if (bd.getmethodOverrides().isEmpty()) {
      Constructor<?> constructorToUse;
      synchronized (bd.constructorargumentLock) {
         constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
         if (constructorToUse == null) {
            final Class<?> clazz = bd.getBeanClass();
            if (clazz.isInterface()) {
               throw new BeanInstantiationException(clazz,"Specified class is an interface");
            }
            try {
               if (System.getSecurityManager() != null) {
                  constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
                     @Override
                     public Constructor<?> run() throws Exception {
                        return clazz.getDeclaredConstructor((Class[]) null);
                     }
                  });
               }
               else {
                  constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
               }
               bd.resolvedConstructorOrFactoryMethod = constructorToUse;
            }
            catch (Exception ex) {
               throw new BeanInstantiationException(clazz,"No default constructor found",ex);
            }
         }
      }
      // BeanUtils 方法
      return BeanUtils.instantiateClass(constructorToUse);
   }
   else {
      // Must generate cglib subclass.
      return instantiateWithMethodInjection(bd,owner);
   }
}

以上已经把ioc容器管理的bean创建的过程都走完了,接下来就是把这些bean之间的关系建立起来,有了点,再做一下线,就可以变成网了。

2,populateBean(beanName,instanceWrapper);方法来做好线的事。

protected void populateBean(String beanName,BeanWrapper bw) {
    // 需要注入的值
        PropertyValues pvs = mbd.getPropertyValues();

        if (bw == null) {
            if (!pvs.isEmpty()) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(),"Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used,for example,// to support styles of field injection.
        boolean continueWithPropertyPopulation = true;

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(),beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }

        if (mbd.getResolvedAutowireMode() == RootBeanDeFinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDeFinition.AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

            // Add property values based on autowire by name if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDeFinition.AUTOWIRE_BY_NAME) {
                autowireByName(beanName,bw,newPvs);
            }

            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDeFinition.AUTOWIRE_BY_TYPE) {
                autowireByType(beanName,newPvs);
            }

            pvs = newPvs;
        }

        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDeFinition.DEPENDENCY_CHECK_NONE);

        if (hasInstAwareBpps || needsDepCheck) {
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw,mbd.allowCaching);
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcesspropertyValues(pvs,filteredPds,bw.getWrappedInstance(),beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName,pvs);
            }
        }
    // 注入操作
        applyPropertyValues(beanName,pvs);
    }
    
    protected void applyPropertyValues(String beanName,BeanDeFinition mbd,BeanWrapper bw,PropertyValues pvs) {
        if (pvs == null || pvs.isEmpty()) {
            return;
        }

        MutablePropertyValues mpvs = null;
        List<PropertyValue> original;

        if (System.getSecurityManager() != null) {
            if (bw instanceof BeanWrapperImpl) {
                ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
            }
        }

        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            if (mpvs.isConverted()) {
                // Shortcut: use the pre-converted values as-is.
                try {
                    bw.setPropertyValues(mpvs);
                    return;
                }
                catch (BeansException ex) {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(),"Error setting property values",ex);
                }
            }
            original = mpvs.getPropertyValueList();
        }
        else {
            original = Arrays.asList(pvs.getPropertyValues());
        }

        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        //处理类
        BeanDeFinitionValueResolver valueResolver = new BeanDeFinitionValueResolver(this,converter);

        // Create a deep copy,resolving any references for values.
        List<PropertyValue> deepcopy = new ArrayList<PropertyValue>(original.size());
        boolean resolveNecessary = false;
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                deepcopy.add(pv);
            }
            else {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                // 
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv,originalValue);
                Object convertedValue = resolvedValue;
                boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isnestedOrIndexedProperty(propertyName);
                if (convertible) {
                    convertedValue = convertForProperty(resolvedValue,propertyName,converter);
                }
                // Possibly store converted value in merged bean deFinition,// in order to avoid re-conversion for every created bean instance.
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepcopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepcopy.add(pv);
                }
                else {
                    resolveNecessary = true;
                    deepcopy.add(new PropertyValue(pv,convertedValue));
                }
            }
        }
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // Set our (possibly massaged) deep copy.
        try {
            bw.setPropertyValues(new MutablePropertyValues(deepcopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(),ex);
        }
    }

什么类型都会调用到TypeConverterDelegate.convertIfNecessary来获得注入的bean

public <T> T convertIfNecessary(String propertyName,Object oldValue,Object newValue,Class<T> requiredType,TypeDescriptor typeDescriptor) throws IllegalArgumentException {

   // Custom editor for this type?
   propertyeditor editor = this.propertyeditorRegistry.findCustomEditor(requiredType,propertyName);

   ConversionFailedException conversionAttemptEx = null;

   // No custom editor but custom ConversionService specified?
   ConversionService conversionService = this.propertyeditorRegistry.getConversionService();
   if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
      TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
      if (conversionService.canConvert(sourceTypeDesc,typeDescriptor)) {
         try {
            return (T) conversionService.convert(newValue,sourceTypeDesc,typeDescriptor);
         }
         catch (ConversionFailedException ex) {
            // fallback to default conversion logic below
            conversionAttemptEx = ex;
         }
      }
   }

   Object convertedValue = newValue;

   // Value not of required type?
   if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType,convertedValue))) {
      if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {
         TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();
         if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {
            convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
         }
      }
      if (editor == null) {
         editor = findDefaultEditor(requiredType);
      }
      convertedValue = doConvertValue(oldValue,convertedValue,editor);
   }

   boolean standardConversion = false;

   if (requiredType != null) {
      // Try to apply some standard type conversion rules if appropriate.

      if (convertedValue != null) {
         if (Object.class == requiredType) {
            return (T) convertedValue;
         }
         else if (requiredType.isArray()) {
            // Array required -> apply appropriate conversion of elements.
            if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
               convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
            }
            return (T) convertToTypedArray(convertedValue,requiredType.getComponentType());
         }
         else if (convertedValue instanceof Collection) {
            // Convert elements to target type,if determined.
            convertedValue = convertToTypedCollection(
                  (Collection<?>) convertedValue,typeDescriptor);
            standardConversion = true;
         }
         else if (convertedValue instanceof Map) {
            // Convert keys and values to respective target type,if determined.
            convertedValue = convertToTypedMap(
                  (Map<?,?>) convertedValue,typeDescriptor);
            standardConversion = true;
         }
         if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
            convertedValue = Array.get(convertedValue,0);
            standardConversion = true;
         }
         if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
            // We can stringify any primitive value...
            return (T) convertedValue.toString();
         }
         else if (convertedValue instanceof String && !requiredType.isinstance(convertedValue)) {
            if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
               try {
                  Constructor<T> strCtor = requiredType.getConstructor(String.class);
                  return BeanUtils.instantiateClass(strCtor,convertedValue);
               }
               catch (NoSuchMethodException ex) {
                  // proceed with field lookup
                  if (logger.isTraceEnabled()) {
                     logger.trace("No String constructor found on type [" + requiredType.getName() + "]",ex);
                  }
               }
               catch (Exception ex) {
                  if (logger.isDebugEnabled()) {
                     logger.debug("Construction via String Failed for type [" + requiredType.getName() + "]",ex);
                  }
               }
            }
            String trimmedValue = ((String) convertedValue).trim();
            if (requiredType.isEnum() && "".equals(trimmedValue)) {
               // It's an empty enum identifier: reset the enum value to null.
               return null;
            }
            convertedValue = attemptToConvertStringToEnum(requiredType,trimmedValue,convertedValue);
            standardConversion = true;
         }
         else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
            convertedValue = NumberUtils.convertNumberToTargetClass(
                  (Number) convertedValue,(Class<Number>) requiredType);
            standardConversion = true;
         }
      }
      else {
         // convertedValue == null
         if (javaUtilOptionalEmpty != null && requiredType.equals(javaUtilOptionalEmpty.getClass())) {
            convertedValue = javaUtilOptionalEmpty;
         }
      }

      if (!ClassUtils.isAssignableValue(requiredType,convertedValue)) {
         if (conversionAttemptEx != null) {
            // Original exception from former ConversionService call above...
            throw conversionAttemptEx;
         }
         else if (conversionService != null) {
            // ConversionService not tried before,probably custom editor found
            // but editor Couldn't produce the required type...
            TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
            if (conversionService.canConvert(sourceTypeDesc,typeDescriptor)) {
               return (T) conversionService.convert(newValue,typeDescriptor);
            }
         }

         // Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
         StringBuilder msg = new StringBuilder();
         msg.append("Cannot convert value of type [").append(ClassUtils.getDescriptiveType(newValue));
         msg.append("] to required type [").append(ClassUtils.getQualifiedname(requiredType)).append("]");
         if (propertyName != null) {
            msg.append(" for property '").append(propertyName).append("'");
         }
         if (editor != null) {
            msg.append(": propertyeditor [").append(editor.getClass().getName()).append(
                  "] returned inappropriate value of type [").append(
                  ClassUtils.getDescriptiveType(convertedValue)).append("]");
            throw new IllegalArgumentException(msg.toString());
         }
         else {
            msg.append(": no matching editors or conversion strategy found");
            throw new IllegalStateException(msg.toString());
         }
      }
   }

   if (conversionAttemptEx != null) {
      if (editor == null && !standardConversion && requiredType != null && Object.class != requiredType) {
         throw conversionAttemptEx;
      }
      logger.debug("Original ConversionService attempt Failed - ignored since " +
            "propertyeditor based conversion eventually succeeded",conversionAttemptEx);
   }

   return (T) convertedValue;
}

放入bean的操作是BeanWrapperImpl的基类上的setPropertyValue实现

protected void setPropertyValue(PropertyTokenHolder tokens,PropertyValue pv) throws BeansException {
        String propertyName = tokens.canonicalName;
        String actualName = tokens.actualName;

        if (tokens.keys != null) {
            // Apply indexes and map keys: fetch value for all keys but the last one.
            PropertyTokenHolder getterTokens = new PropertyTokenHolder();
            getterTokens.canonicalName = tokens.canonicalName;
            getterTokens.actualName = tokens.actualName;
            getterTokens.keys = new String[tokens.keys.length - 1];
            System.arraycopy(tokens.keys,0,getterTokens.keys,tokens.keys.length - 1);
            Object propValue;
            try {
                propValue = getPropertyValue(getterTokens);
            }
            catch (NotReadablePropertyException ex) {
                throw new NotWritablePropertyException(getRootClass(),this.nestedpath + propertyName,"Cannot access indexed value in property referenced " +
                                "in indexed property path '" + propertyName + "'",ex);
            }
            // Set value for last key.
            String key = tokens.keys[tokens.keys.length - 1];
            if (propValue == null) {
                // null map value case
                if (isautogrownestedpaths()) {
                    // Todo: cleanup,this is pretty hacky
                    int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
                    getterTokens.canonicalName = tokens.canonicalName.substring(0,lastKeyIndex);
                    propValue = setDefaultValue(getterTokens);
                }
                else {
                    throw new NullValueInnestedpathException(getRootClass(),"Cannot access indexed value in property referenced " +
                                    "in indexed property path '" + propertyName + "': returned null");
                }
            }
            if (propValue.getClass().isArray()) {
                PropertyHandler ph = getLocalPropertyHandler(actualName);
                Class<?> requiredType = propValue.getClass().getComponentType();
                int arrayIndex = Integer.parseInt(key);
                Object oldValue = null;
                try {
                    if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
                        oldValue = Array.get(propValue,arrayIndex);
                    }
                    Object convertedValue = convertIfNecessary(propertyName,oldValue,pv.getValue(),ph.nested(tokens.keys.length));
                    int length = Array.getLength(propValue);
                    if (arrayIndex >= length && arrayIndex < this.autogrowCollectionLimit) {
                        Class<?> componentType = propValue.getClass().getComponentType();
                        Object newArray = Array.newInstance(componentType,arrayIndex + 1);
                        System.arraycopy(propValue,newArray,0,length);
                        setPropertyValue(actualName,newArray);
                        propValue = getPropertyValue(actualName);
                    }
                    Array.set(propValue,arrayIndex,convertedValue);
                }
                catch (indexoutofboundsexception ex) {
                    throw new InvalidPropertyException(getRootClass(),"Invalid array index in property path '" + propertyName + "'",ex);
                }
            }
            else if (propValue instanceof List) {
                PropertyHandler ph = getPropertyHandler(actualName);
                Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
                List<Object> list = (List<Object>) propValue;
                int index = Integer.parseInt(key);
                Object oldValue = null;
                if (isExtractOldValueForEditor() && index < list.size()) {
                    oldValue = list.get(index);
                }
                Object convertedValue = convertIfNecessary(propertyName,ph.nested(tokens.keys.length));
                int size = list.size();
                if (index >= size && index < this.autogrowCollectionLimit) {
                    for (int i = size; i < index; i++) {
                        try {
                            list.add(null);
                        }
                        catch (NullPointerException ex) {
                            throw new InvalidPropertyException(getRootClass(),"Cannot set element with index " + index + " in List of size " +
                                            size + ",accessed using property path '" + propertyName +
                                            "': List does not support filling up gaps with null elements");
                        }
                    }
                    list.add(convertedValue);
                }
                else {
                    try {
                        list.set(index,convertedValue);
                    }
                    catch (indexoutofboundsexception ex) {
                        throw new InvalidPropertyException(getRootClass(),"Invalid list index in property path '" + propertyName + "'",ex);
                    }
                }
            }
            else if (propValue instanceof Map) {
                PropertyHandler ph = getLocalPropertyHandler(actualName);
                Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
                Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
                Map<Object,Object> map = (Map<Object,Object>) propValue;
                // IMPORTANT: Do not pass full property name in here - property editors
                // must not kick in for map keys but rather only for map values.
                TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
                Object convertedMapKey = convertIfNecessary(null,null,key,mapKeyType,typeDescriptor);
                Object oldValue = null;
                if (isExtractOldValueForEditor()) {
                    oldValue = map.get(convertedMapKey);
                }
                // Pass full property name and old value in here,since we want full
                // conversion ability for map values.
                Object convertedMapValue = convertIfNecessary(propertyName,mapValueType,ph.nested(tokens.keys.length));
                map.put(convertedMapKey,convertedMapValue);
            }
            else {
                throw new InvalidPropertyException(getRootClass(),"Property referenced in indexed property path '" + propertyName +
                                "' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
            }
        }

        else {
            PropertyHandler ph = getLocalPropertyHandler(actualName);
            if (ph == null || !ph.isWritable()) {
                if (pv.isOptional()) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Ignoring optional value for property '" + actualName +
                                "' - property not found on bean class [" + getRootClass().getName() + "]");
                    }
                    return;
                }
                else {
                    throw createNotWritablePropertyException(propertyName);
                }
            }
            Object oldValue = null;
            try {
                Object originalValue = pv.getValue();
                Object valuetoApply = originalValue;
                if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
                    if (pv.isConverted()) {
                        valuetoApply = pv.getConvertedValue();
                    }
                    else {
                        if (isExtractOldValueForEditor() && ph.isReadable()) {
                            try {
                                oldValue = ph.getValue();
                            }
                            catch (Exception ex) {
                                if (ex instanceof PrivilegedActionException) {
                                    ex = ((PrivilegedActionException) ex).getException();
                                }
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Could not read prevIoUs value of property '" +
                                            this.nestedpath + propertyName + "'",ex);
                                }
                            }
                        }
                        valuetoApply = convertForProperty(
                                propertyName,originalValue,ph.toTypeDescriptor());
                    }
                    pv.getoriginalPropertyValue().conversionNecessary = (valuetoApply != originalValue);
                }
                ph.setValue(object,valuetoApply);
            }
            catch (TypeMismatchException ex) {
                throw ex;
            }
            catch (InvocationTargetException ex) {
                PropertyChangeEvent propertyChangeEvent =
                        new PropertyChangeEvent(this.rootObject,pv.getValue());
                if (ex.getTargetException() instanceof ClassCastException) {
                    throw new TypeMismatchException(propertyChangeEvent,ph.getPropertyType(),ex.getTargetException());
                }
                else {
                    Throwable cause = ex.getTargetException();
                    if (cause instanceof UndeclaredThrowableException) {
                        // May happen e.g. with Groovy-generated methods
                        cause = cause.getCause();
                    }
                    throw new MethodInvocationException(propertyChangeEvent,cause);
                }
            }
            catch (Exception ex) {
                PropertyChangeEvent pce =
                        new PropertyChangeEvent(this.rootObject,pv.getValue());
                throw new MethodInvocationException(pce,ex);
            }
        }
    }
    // 使用反射机制,执行注入set方法注入bean
    public void setValue(final Object object,Object valuetoApply) throws Exception {
            final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
                    ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
                    this.pd.getWriteMethod());
            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        @Override
                        public Object run() {
                            writeMethod.setAccessible(true);
                            return null;
                        }
                    });
                }
                else {
                    writeMethod.setAccessible(true);
                }
            }
            final Object value = valuetoApply;
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        @Override
                        public Object run() throws Exception {
                            writeMethod.invoke(object,value);
                            return null;
                        }
                    },acc);
                }
                catch (PrivilegedActionException ex) {
                    throw ex.getException();
                }
            }
            else {
                writeMethod.invoke(getWrappedInstance(),value);
            }
        }

----------------------

永远爱汀汀

Spring Boot教程(三十一)使用Spring-data-jpa(2)

Spring Boot教程(三十一)使用Spring-data-jpa(2)

创建实体

创建一个User实体,包含id(主键)、name(姓名)、age(年龄)属性,通过ORM框架其会被映射到数据库表中,由于配置了hibernate.hbm2ddl.auto,在应用启动的时候框架会自动去数据库中创建对应的表。

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private Integer age;

    // 省略构造函数

    // 省略getter和setter

}

创建数据访问接口

下面针对User实体创建对应的Repository接口实现对该实体的数据访问,如下代码:

public interface UserRepository extends JpaRepository<User, Long> {

    User findByName(String name);

    User findByNameAndAge(String name, Integer age);

    @Query("from User u where u.name=:name")
    User findUser(@Param("name") String name);

}

在Spring-data-jpa中,只需要编写类似上面这样的接口就可实现数据访问。不再像我们以往编写了接口时候还需要自己编写接口实现类,直接减少了我们的文件清单。

下面对上面的UserRepository做一些解释,该接口继承自JpaRepository,通过查看JpaRepository接口的API文档,可以看到该接口本身已经实现了创建(save)、更新(save)、删除(delete)、查询(findAll、findOne)等基本操作的函数,因此对于这些基础操作的数据访问就不需要开发者再自己定义。

 

在我们实际开发中,JpaRepository接口定义的接口往往还不够或者性能不够优化,我们需要进一步实现更复杂一些的查询或操作。由于本文重点在spring boot中整合spring-data-jpa,在这里先抛砖引玉简单介绍一下spring-data-jpa中让我们兴奋的功能,后续再单独开篇讲一下spring-data-jpa中的常见使用。

在上例中,我们可以看到下面两个函数:

  • User findByName(String name)
  • User findByNameAndAge(String name, Integer age)

它们分别实现了按name查询User实体和按name和age查询User实体,可以看到我们这里没有任何类SQL语句就完成了两个条件查询方法。这就是Spring-data-jpa的一大特性:通过解析方法名创建查询

除了通过解析方法名来创建查询外,它也提供通过使用@Query 注解来创建查询,您只需要编写JPQL语句,并通过类似“:name”来映射@Param指定的参数,就像例子中的第三个findUser函数一样。

 

Spring-data-jpa的能力远不止本文提到的这些,由于本文主要以整合介绍为主,对于Spring-data-jpa的使用只是介绍了常见的使用方式。诸如@Modifying操作、分页排序、原生SQL支持以及与Spring MVC的结合使用等等内容就不在本文中详细展开,这里先挖个坑,后续再补文章填坑,如您对这些感兴趣可以关注我博客或简书,同样欢迎大家留言交流想法。

单元测试

在完成了上面的数据访问接口之后,按照惯例就是编写对应的单元测试来验证编写的内容是否正确。这里就不多做介绍,主要通过数据操作和查询来反复验证操作的正确性。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTests {

	@Autowired
	private UserRepository userRepository;

	@Test
	public void test() throws Exception {

		// 创建10条记录
		userRepository.save(new User("AAA", 10));
		userRepository.save(new User("BBB", 20));
		userRepository.save(new User("CCC", 30));
		userRepository.save(new User("DDD", 40));
		userRepository.save(new User("EEE", 50));
		userRepository.save(new User("FFF", 60));
		userRepository.save(new User("GGG", 70));
		userRepository.save(new User("HHH", 80));
		userRepository.save(new User("III", 90));
		userRepository.save(new User("JJJ", 100));

		// 测试findAll, 查询所有记录
		Assert.assertEquals(10, userRepository.findAll().size());

		// 测试findByName, 查询姓名为FFF的User
		Assert.assertEquals(60, userRepository.findByName("FFF").getAge().longValue());

		// 测试findUser, 查询姓名为FFF的User
		Assert.assertEquals(60, userRepository.findUser("FFF").getAge().longValue());

		// 测试findByNameAndAge, 查询姓名为FFF并且年龄为60的User
		Assert.assertEquals("FFF", userRepository.findByNameAndAge("FFF", 60).getName());

		// 测试删除姓名为AAA的User
		userRepository.delete(userRepository.findByName("AAA"));

		// 测试findAll, 查询所有记录, 验证上面的删除是否成功
		Assert.assertEquals(9, userRepository.findAll().size());

	}


}

源码来源

Spring Boot教程(二十三)关于集成 Spring Cache(2)

Spring Boot教程(二十三)关于集成 Spring Cache(2)

开启缓存技术

在程序的入口中加入@ EnableCaching开启缓存技术:

@SpringBootApplication
@EnableCaching
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

在需要缓存的地方加入@Cacheable注解,比如在getByIsbn()方法上加入@Cacheable(“books”),这个方法就开启了缓存策略,当缓存有这个数据的时候,会直接返回数据,不会等待去查询数据库。

@Component
public class SimpleBookRepository implements BookRepository {

    @Override
    @Cacheable("books")
    public Book getByIsbn(String isbn) {
        simulateSlowService();
        return new Book(isbn, "Some book");
    }

    // Don''t do this at home
    private void simulateSlowService() {
        try {
            long time = 3000L;
            Thread.sleep(time);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }

}

这时再启动程序,你会发现程序打印:

isbn-1234 –>Book{isbn=’isbn-1234’, title=’Some book’} 
2017-04-23 18:17:09.479 INFO 8054 — [ main] forezp.AppRunner : isbn-4567 –>Book{isbn=’isbn-4567’, title=’Some book’} 
2017-04-23 18:17:09.480 INFO 8054 — [ main] forezp.AppRunner : isbn-1234 –>Book{isbn=’isbn-1234’, title=’Some book’} 
2017-04-23 18:17:09.480 INFO 8054 — [ main] forezp.AppRunner : isbn-4567 –>Book{isbn=’isbn-4567’, title=’Some book’} 
2017-04-23 18:17:09.481 INFO 8054 — [ main] forezp.AppRunner : isbn-1234 –>Book{isbn=’isbn-1234’, title=’Some book’} 
2017-04-23 18:17:09.481 INFO 8054 — [ main] forezp.AppRunner : isbn-1234 –>Book{isbn=’isbn-1234’, title=’Some book’}

只有打印前面2个数据,程序等了3s,之后的数据瞬间打印在控制台上了,这说明缓存起了作用。

源码来源

今天的关于Spring 源码:Spring IoC 容器加载过程2的分享已经结束,谢谢您的关注,如果想了解更多关于1. spring5源码系列 -- Spring整体脉络 IOC加载过程 Bean的生命周期、Ioc容器依赖注入-Spring 源码(2)、Spring Boot教程(三十一)使用Spring-data-jpa(2)、Spring Boot教程(二十三)关于集成 Spring Cache(2)的相关知识,请在本站进行查询。

本文标签: