模拟大致的底层原理,为学习Spring源码做铺垫。
实现的功能:扫描路径、依赖注入、aware回调、初始化前、初始化、初始化后、切面
未实现的功能:构造器推断、循环依赖
重点:BeanDefinition、BeanPostProcessor
学习Spring源码的重点:设计模式、编码规范、设计思想、扩展点
启动类:
- public class Yeah
- {
- public static void main(String[] args)
- {
- GaxApplicationContext gaxApplicationContext = new GaxApplicationContext(AppConfig.class);
- UserInterface userService = (UserInterface) gaxApplicationContext.getBean("userService");
- userService.test();
- }
- }
关键方法:
- public class GaxApplicationContext
- {
- private Class configClass;
-
- private static final String SINGLETON = "singleton";
-
- private Map
beanDefinitionMap = new HashMap<>(); -
- private Map
singletonObjects = new HashMap<>(); -
- // Spring源码用的是LinkedList
- private List
beanPostProcessorList = new ArrayList<>(); -
- public GaxApplicationContext(Class configClass)
- {
- this.configClass = configClass;
-
- // 扫描指定路径,找到所有@Component注解的类,封装成beanDefinition保存再Map中
- scan(configClass);
-
- // 思考个问题:beanDefinitionMap.keySet()和beanDefinitionMap.entrySet()两种遍历的区别?选用哪个好?
- for (Map.Entry
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地址:
git clone https://gitee.com/seek6174/spring-seek.git