Spring源码学习笔记

非 Y 不嫁゛ 提交于 2020-01-14 07:20:55

spring bean实例化简图 

更改allowcircularReference为false可以关闭循环依赖,方式有三种。

1、更改spring源码

2、不要使用带参构造函数

改为

3、拓展spring(具体不知道怎么做,应该是通过BeanPostProcessor接口)

1、Spring IOC

笔记:

1、重要的区别,别搞混了

  • Instantiation 实例化
  • Initialization 初始化

1、在填充bean属性时,会调用一系列的BeanPostProcessor,其中CommonAnnotationBeanPostProcessor处理@Resource注解,AutowiredAnnotationBeanPostProcessor处理@Autowired注解,他们是解决循环依赖的关键。

2、代理是在初始化后调用postprocessor完成的。解决依赖过程中,从二级缓存工厂获取对象的时候,获取到的是原对象的引用,再完成属性注入,再初始化。

3、初始化过程是先处理注解再处理类方法最后再处理注解。所以如果bean同时使用三种初始化方法,@PostConstruct注解的初始化方法先执行(先执行BeanPostProcessor接口,相关BeanPostProcessor接口实现类会处理注解),实现了InitializingBean的afterPropertiesSet()再执行,最后是xml配置的init方法后执行。

4、BeanPostProcessor接口(有方法体的,java8以后就可以了)只有两个方法,

Object postProcessBeforeInitialization(Object bean, String beanName)
postProcessAfterInitialization(Object bean, String beanName)

从名字可以看出,实现该类只能插手初始化的过程,而对实例化过程不能产生影响。

对bean实例化过程产生影响的有BeanPostProcessor接口的子类,比如CommonAnnotationBeanPostProcessor等等

5、若是想把类(不是对象)交给spring管理,可以采用以下方法

  • 使用ApplicationContext类得到DefaultListableBeanFactory,再获取BeanFactory,最后类对应的Beandefinition注入

查看Spring原文档

  • 实现ImportBeanDefinitionRegistrar接口,实现类需要注入到spring 容器

比如有循环依赖如下,类一定要是无参构造器

public class TestInstanceBean1 {
    @Autowired
    private TestInstanceBean2 testInstanceBean2;
    @Value("this is TestInstanceBean")
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void printlnSomething() {
        System.out.println("在TestInstanceBean1中获取testInstanceBean2的名字:"+testInstanceBean2.getName());
        System.out.println("在TestInstanceBean1中获取自己的名字:"+name);
    }
}


public class TestInstanceBean2 {
    @Autowired
    private TestInstanceBean1 testInstanceBean1;
    @Value("this is TestInstanceBean2")
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void printlnSomething() {
        System.out.println("在TestInstanceBean2中获取testInstanceBean1的名字:"+testInstanceBean1.getName());
        System.out.println("在TestInstanceBean2中获取自己的名字:"+name);
    }
}

对于第一种 

//加载TestMain到上下文当中,并且完成spring容器的初始化工作
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
        DefaultListableBeanFactory  beanFactory = (DefaultListableBeanFactory) ac.getBeanFactory();
        BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(TestInstanceBean1.class);
        BeanDefinitionBuilder builder2 = BeanDefinitionBuilder.genericBeanDefinition(TestInstanceBean2.class);
        beanFactory.registerBeanDefinition("testInstanceBean1",builder1.getBeanDefinition());
        beanFactory.registerBeanDefinition("testInstanceBean2",builder2.getBeanDefinition());
        ac.register(TestMain.class);
//完成容器初始化
        ac.refresh();
        TestInstanceBean1 testInstanceBean1= (TestInstanceBean1) ac.getBean("testInstanceBean1");
        testInstanceBean1.printlnSomething();
        TestInstanceBean2 testInstanceBean2= (TestInstanceBean2) ac.getBean("testInstanceBean2");
        testInstanceBean2.printlnSomething();

结果会打印出

在TestInstanceBean1中获取testInstanceBean2的名字:this is TestInstanceBean2
在TestInstanceBean1中获取自己的名字:this is TestInstanceBean
在TestInstanceBean2中获取testInstanceBean1的名字:this is TestInstanceBean
在TestInstanceBean2中获取自己的名字:this is TestInstanceBean2

对于第二种

public class TestBeanFactoryPostProcesser implements ImportBeanDefinitionRegistrar{
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(TestInstanceBean1.class);
        BeanDefinitionBuilder builder2 = BeanDefinitionBuilder.genericBeanDefinition(TestInstanceBean2.class);
        registry.registerBeanDefinition("testInstanceBean1",builder1.getBeanDefinition());
        registry.registerBeanDefinition("testInstanceBean2",builder2.getBeanDefinition());
    }
}

 

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestMain.class);
        TestInstanceBean1 testInstanceBean1= (TestInstanceBean1) ac.getBean("testInstanceBean1");
        testInstanceBean1.printlnSomething();
        TestInstanceBean2 testInstanceBean2= (TestInstanceBean2) ac.getBean("testInstanceBean2");
        testInstanceBean2.printlnSomething();

结果和之前一样,打印出

在TestInstanceBean1中获取testInstanceBean2的名字:this is TestInstanceBean2
在TestInstanceBean1中获取自己的名字:this is TestInstanceBean
在TestInstanceBean2中获取testInstanceBean1的名字:this is TestInstanceBean
在TestInstanceBean2中获取自己的名字:this is TestInstanceBean2

可以看到类里面的注解也会被解析,配置被注入,这是因为BeanDefinition有相应的BeanPostProcessor接口处理了这些注解。这样的手动注入,spring也能够解决循环依赖

6、若是想把对象(不是类)交给spring管理,可以采用以下三种方法

  • @Bean注解,return一个对象
  • 使用ApplicationContext类得到DefaultListableBeanFactory,再获取BeanFactory,最后调用
    registerSingleton(String beanName, Object singletonObject) 
  • 实现FactoryBean接口,重写三个方法(详见Spring文档

1.1BeanFactory和FactoryBean区别

BeanFactory:是访问Spring bean容器的根接口,是浏览spring bean容器情况的底层客户端。(The root interface for accessing a Spring bean container.This is the basic client view of a bean container;)

FactoryBean:BeanFactory生产bean的时候不是直接返回bean的实例,而是调用该bean自身的工厂类生产。BeanFactory存储的是bean自身的工厂,而不是bean实例。

这种模式就是抽象工厂模式,外层工厂放置着内层工厂对象。

1.2循环依赖

循环依赖只存在与单例模式当中,虽然有三级缓存,但对于一个对象来说,它始终只有一个实例。而循环依赖的关键在于对原对象的引用。首先要明白下面的代码。

public class TesCIrcularDependencies {
    private String name;

    public TesCIrcularDependencies(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        System.out.println(name);
    }
}
TesCIrcularDependencies a0 = new TesCIrcularDependencies("原名字");
TesCIrcularDependencies a1=a0;
TesCIrcularDependencies a2=a0;
a1.setName("a1对象更改后的名字");
a0.print();
a1.print();
a2.print();

 打印结果是

a1对象更改后的名字
a1对象更改后的名字
a1对象更改后的名字

比如有A依赖于B,B依赖于A, 解决循环依赖的大致流程为:

 

spring 容器三级缓存作用:

  • singletonObjects:一级缓存,单例池,放置着spring bean的实例(注入完成的bean)(最快);
  • singletonFactories:二级缓存,根据beanName能获取到原对象的引用的工厂。
    (还不是spring bean, 已经构造完成,但还没有注入属性或者初始化)
    解决循环依赖时,当单例池没有beanName对应的spring bean的时候去生产;
  • earlySingletonObjects:三级缓存,因为每次都从singletonFactories生产会比较慢,
    所以将二级缓存的生产结果缓存起来。

 

2、Spring-AOP

1、Cglib和jdk动态代理的区别

2、为什么jdk动态代理必须基于接口 ?

  • 生成的代理类继承了Proxy,由于java是单继承,所以只能实现接口,通过接口实现 
  • 从代理模式的设计来说,充分利用了java的多态特性,也符合基于接口编码的规范
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!