在Spring框架中,主要是要IOC容器和AOP切面两块,然而从IOC容器中如何获取bean也对我们而言也是可以来学习解析的。
在工作中,一次通过从IOC容器中获取通过继承FactoryBean接口的类,发现在对注入后的类名添加&与不添加&的区别很大,在添加&的情况下,获取的是当前继承FactoryBean接口的类;在不添加&的情况下,获取的是当前继承FactoryBean接口的类中通过getObject()返回的类对象。
因此引起了我对getBean的源码探讨,看看Spring框架中究竟是如何来获取继承FactoryBean接口的类的bean。
由于工作中的代码太过繁琐,同时也涉及到一些非必要的东西(呵呵,大家应该懂得),所以我通过简单的示例来通过继承FactoryBean接口完成IOC的注入,然后在后面的源码解读中来理解getBean方法(本篇文章主要是讲解getBean方法,由于getBean依赖通过继承FactoryBean接口完成IOC的注入的bean来获取,所以就在这部分来简单示例)。
1、pojo类
作为后面注入到IOC容器,需要通过getBean获取的对象
package com.cyw.demo.bean;
public class Girl {
}
2、基于FactoryBean接口继承的类
通过继承FactoryBean接口,实现getObject()获取Girl的对象。
package com.cyw.demo.config;
import org.springframework.beans.factory.FactoryBean;
import com.cyw.demo.bean.Girl;
public class DemoFactoryBean implements FactoryBean<Girl> {
public Girl getObject() throws Exception {
return new Girl();
}
public Class> getObjectType() {
return Girl.class;
}
}
3、配置类
通过配置来注入DemoFactoryBean类。
package com.cyw.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DemoConfig {
@Bean
public DemoFactoryBean demoFactoryBean() {
return new DemoFactoryBean();
}
}
4、测试类
package maven_spring;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cyw.demo.config.DemoConfig;
public class DemoTest {
@Test
public void test() {
ApplicationContext app = new AnnotationConfigApplicationContext(DemoConfig.class);
Object bean1 = app.getBean("demoFactoryBean");
System.out.println(bean1);
Object bean2 = app.getBean("&demoFactoryBean");
System.out.println(bean2);
}
}
通过只是test()方法,输出bean1和bean2变量的值。
发现bean1是Gril的实例对象,bean2是DemoFactoryBean的实例对象。
现在应该是激动人心的时刻了,因为研究完getBean()的源码,就能很清楚的认识到上述示例中为什么在有没有添加&,输出的两个对象是不同了。
1、先上时序图
源码是基于5.0.6.RELEASE版本,大家可以随自己的意愿来选择
2、解析时序图
1)client为我们访问IOC容器,获取Bean
public class DemoTest {
@Test
public void test() {
ApplicationContext app = new AnnotationConfigApplicationContext(DemoConfig.class);
Object bean1 = app.getBean("demoFactoryBean");
System.out.println(bean1);
Object bean2 = app.getBean("&demoFactoryBean");
System.out.println(bean2);
}
}
2)通过getBean来进入调用的类AbstractBeanFactory.class
此处的源码只基于Object bean2 = app.getBean(“&demoFactoryBean”);来讲解,如果大家有兴趣,可以研究下Object bean1 = app.getBean(“demoFactoryBean”);
现在继续进入正题:
在AbstractBeanFactory.class类中getBean方法
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
3)doGetBean(name, null, null, false);方法
调用 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
4)进入AbstractAutowireCapableBeanFactory.class
@Override
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
String currentlyCreatedBean = this.currentlyCreatedBean.get();
if (currentlyCreatedBean != null) {
registerDependentBean(beanName, currentlyCreatedBean);
}
return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
}
5)调会AbstractBeanFactory.class的getObjectForBeanInstance方法
主要看这段代码 判断当前类是否继承FactoryBean或者beanName是否有&前缀
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
6)isFactoryDereference在BeanFactoryUtils.class类中,判断当前beanName是否有&前缀
public static boolean isFactoryDereference(@Nullable String name) {
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
通过上述代码的调用后会返回true,这样就会直接返回当前的beanInstance(在第5步)
关于Object bean1 = app.getBean(“demoFactoryBean”);这段对应的源码,是在上述的基础上继续深入即可。