想了解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容器加载流程)
- 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 源码版本: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. 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容器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)
创建实体
创建一个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)
开启缓存技术
在程序的入口中加入@ 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)的相关知识,请在本站进行查询。
本文标签: