Spring源碼學習筆記

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的多態特性,也符合基於接口編碼的規範
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章