Spring源码中getBean的简单流程
作者:互联网
在学习Sring的时候,免不了经常见如下的代码
VirtuousApplicationContext applicationContext = new VirtuousApplicationContext(AppConfig.class);
UserInterFace userInterFace = (UserInterFace) applicationContext.getBean("userService");
这就是Spring给我们造的轮子,于是这次就深入了解了下Spring的bean的加载流程,对BeanDefinition、BeanPostProcessor进行更好的了解。模拟写一下Spring获取Bean的流程
1.如上代码,我们的一个接口交给Spring管理的时候,Spring通过getBean帮我们拿到我们交给他们的对象。
我们仿照Srping 也新建一个ApplicationContext类,在这个类里面有个对象,也就是入参传入的Config的类,于是写一个config的构造函数。
public VirtuousApplicationContext(Class configClass) {
this.configClass = configClass;
}
最开始的第一行代码,我们知道它的功能就是对Spring进行扫描,是否是有交给Spring管理的单列Bean对象,没有就进行创建。 那么接下来的思路就是在这个构造函数中进行对项目代码的扫描操作。通过ComponentScan进行Spring的扫描
if(configClass.isAnnotationPresent(ComponentScan.class)){
ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
String path = componentScanAnnotation.value();
System.out.println("扫描路径:"+path);
path = path.replace(".","/");
ClassLoader classLoader = VirtuousApplicationContext.class.getClassLoader();
URL resource = classLoader.getResource(path);
File file = new File(resource.getFile());
// 找到文件
if(file.isDirectory()){
for(File f: file.listFiles()){
String absolutePath = f.getAbsolutePath();
absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
absolutePath = absolutePath.replace("\\", ".");
try {
Class<?> clazz = classLoader.loadClass(absolutePath);
// 表示一个类是一个Bean
if (clazz.isAnnotationPresent(Component.class)) {
if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
beanPostProcessorList.add(instance);
}
// bean的名字
Component componentAnnotation = clazz.getAnnotation(Component.class);
String beanName = componentAnnotation.value();
if ("".equals(beanName)) {
beanName = Introspector.decapitalize(clazz.getSimpleName());
}
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(clazz);
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
String value = scopeAnnotation.value();
beanDefinition.setScope(value);
} else {
// 单列
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(beanName, beanDefinition);
}
} catch (ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
在扫描过程中,我们的思路是将单列Bean放入一个Map中。第二行代码中,通过getBean获取到我们需要的对象,我们就仿照通过beanName拿到我们交给Spring管理而需要用到的对象。
if(!beanDefinitionMap.containsKey(beanName)){
throw new RuntimeException();
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition.getScope().equals("singleton")){
// 单列
Object singletonBean = singletonObjects.get(beanName);
if(singletonBean == null){
singletonBean = createBean(beanName,beanDefinition);
singletonObjects.put(beanName,singletonBean);
}
return singletonBean;
} else {
// 原型
Object prototypeBean = createBean(beanName,beanDefinition);
return prototypeBean;
}
在这个过程中,如果我们获取到的单列的getBean就返回,如果没有的话,就通过创建Bean,创建成功后也是通过放入Map中。由此引入创建createBean的过程
Class clazz = beanDefinition.getType();
Object instance = null;
try {
instance = clazz.getConstructor().newInstance();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
// 获取bean
field.set(instance, getBean(field.getName()));
}
}
if (instance instanceof BeanNameAware) {
((BeanNameAware)instance).setBeanName(beanName);
}
// BeanPostProcessor
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
}
if (instance instanceof InitializingBean) {
((InitializingBean)instance).afterPropertiesSet();
}
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return instance;
以上就是一个简单粗糙的Spring获取getBean的简单原理。当然,Spring源码底层的实现肯定不是这么简单的代码实现。做下记录,以便继续深入的学习。
标签:Spring,beanName,getBean,clazz,instance,源码,class,beanDefinition 来源: https://blog.csdn.net/qq_35529931/article/details/123036453