概述
模拟大致的底层原理,为学习Spring源码做铺垫。
实现的功能:扫描路径、依赖注入、aware回调、初始化前、初始化、初始化后、切面
未实现的功能:构造器推断、循环依赖
重点:BeanDefinition、BeanPostProcessor
学习Spring源码的重点:设计模式、编码规范、设计思想、扩展点
启动类:
md-end-block
public class Yeah
{
public static void main(String[] args)
{
GaxApplicationContext gaxApplicationContext = new GaxApplicationContext(AppConfig.class);
UserInterface userService = (UserInterface) gaxApplicationContext.getBean("userService");
userService.test();
}
}
关键方法:
md-end-block
public class GaxApplicationContext
{
private Class configClass;
private static final String SINGLETON = "singleton";
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
private Map<String, Object> singletonObjects = new HashMap<>();
// Spring源码用的是LinkedList
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
public GaxApplicationContext(Class configClass)
{
this.configClass = configClass;
// 扫描指定路径,找到所有@Component注解的类,封装成beanDefinition保存再Map中
scan(configClass);
// 思考个问题:beanDefinitionMap.keySet()和beanDefinitionMap.entrySet()两种遍历的区别?选用哪个好?
for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet())
{
String beanName = entry.getKey();
BeanDefinition beanDefinition = entry.getValue();
if (SINGLETON.equals(beanDefinition.getScope()))
{
Object bean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, bean);
}
}
}
private Object createBean(String beanName, BeanDefinition beanDefinition)
{
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);
field.set(instance, getBean(field.getName()));
}
}
// aware回调
if (instance instanceof BeanNameAware)
{
((BeanNameAware)instance).setBeanName(beanName);
}
// 初始化前
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 | NoSuchMethodException | IllegalAccessException | InvocationTargetException e)
{
e.printStackTrace();
}
return instance;
}
public Object getBean(String beanName)
{
if (!beanDefinitionMap.containsKey(beanName))
{
throw new NullPointerException();
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (SINGLETON.equals(beanDefinition.getScope()))
{
Object singletonBean = singletonObjects.get(beanName);
if (null == singletonBean)
{
singletonBean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, singletonBean);
}
return singletonBean;
}
else
{
// 原型Bean
Object prototypeBean = createBean(beanName, beanDefinition);
return prototypeBean;
}
}
private void scan(Class configClass)
{
if (configClass.isAnnotationPresent(ComponentScan.class))
{
ComponentScan componentScanAnnotation = (ComponentScan)configClass.getAnnotation(ComponentScan.class);
String path = componentScanAnnotation.value();
// path = com/gax/service
path = path.replace(".", "/");
ClassLoader classLoader = GaxApplicationContext.class.getClassLoader();
URL resource = classLoader.getResource(path);
assert resource != null;
File file = new File(resource.getFile());
if (file.isDirectory())
{
for (File f : Objects.requireNonNull(file.listFiles()))
{
String absolutePath = f.getAbsolutePath();
absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
// 类加载器入参需要的格式:com.gax.service.XXX
absolutePath = absolutePath.replace("\\", ".");
try
{
Class<?> clazz = classLoader.loadClass(absolutePath);
if (clazz.isAnnotationPresent(Component.class))
{
if (BeanPostProcessor.class.isAssignableFrom(clazz))
{
BeanPostProcessor instance = (BeanPostProcessor)clazz.getConstructor().newInstance();
beanPostProcessorList.add(instance);
}
Component componentAnnotation = clazz.getAnnotation(Component.class);
String beanName = componentAnnotation.value();
if ("".equals(beanName))
{
// 默认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
{
// 默认单例Bean
beanDefinition.setScope(SINGLETON);
}
beanDefinitionMap.put(beanName, beanDefinition);
}
}
catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException
| InstantiationException | IllegalAccessException e)
{
e.printStackTrace();
}
}
}
}
}
}
gitee地址:
md-end-block
git clone https://gitee.com/seek6174/spring-seek.git