前言
通过手写模拟Spring源码了解Spring底层源码启动原理与工作工程。第一部分为通过@ComponetScan扫描相应的包获取Bean实例。这里未设置@Scope,默认都是单例。
一、目录结构
二、相关部分代码
1.Spring启动类
public class Test { public static void main(String args[]){ try { ApplicationContext applicationContext=new ApplicationContext(AppConfig.class); Userservice bean = (Userservice)applicationContext.getBean("userservice"); bean.test(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
2.AppConfig类和ComponentScan注解
1. @ComponentScan("com.example.service") 2. public class AppConfig { 3. }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ComponentScan { String value() default ""; }
3.
BeanDefinition类
public class BeanDefinition { private Class clazz; public BeanDefinition(Class clazz) { this.clazz = clazz; } public BeanDefinition() { } public Class getClazz() { return clazz; } public void setClazz(Class clazz) { this.clazz = clazz; } }
4.ApplicationContext类
获取配置类的注解扫描路径,通过类加载器获取该路径下的资源,然后遍历资源下的各个文件,判断当前类是不是一个Bean实例,将BeanName和BeanDefinition对象存储到Map集合中。然后遍历该Map集合,添加到单例池中。
public ApplicationContext(Class configClass) throws ClassNotFoundException { this.configClass = configClass; ComponentScan annotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class); String value = annotation.value(); System.out.println(value); value=value.replace('.','/'); // 类加载器应用 ClassLoader classLoader=ApplicationContext.class.getClassLoader(); // 获取类加载器下当前目录下的资源 URL resource = classLoader.getResource(value); File file=new File(resource.getFile()); if(file.isDirectory()){ File[] files=file.listFiles(); for(File f:files){ // 获取当前资源下的class文件 String absolutePath = f.getAbsolutePath(); if(absolutePath.endsWith(".class")){ String className=absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class")); className=className.replace("\\","."); Class<?> loadClass = classLoader.loadClass(className); if(loadClass.isAnnotationPresent(Componet.class)){ Componet declaredAnnotation = loadClass.getDeclaredAnnotation(Componet.class); String value1 = declaredAnnotation.value(); BeanDefinition beanDefinition=new BeanDefinition(); beanDefinition.setClazz(loadClass); beanDefinitionHashMap.put(value1,beanDefinition); } } } } for(String beanName:beanDefinitionHashMap.keySet()){ BeanDefinition beanDefinition=beanDefinitionHashMap.get(beanName); Object bean = createBean(beanDefinition); hashMap.put(beanName,bean); } }
createBean方法
public Object createBean(BeanDefinition beanDefinition){ Class clazz=beanDefinition.getClazz(); try { Object o = clazz.getDeclaredConstructor().newInstance(); return o; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } return null; }
getBean方法
public Object getBean(String beanName){ if(beanDefinitionHashMap.containsKey(beanName)){ BeanDefinition beanDefinition = beanDefinitionHashMap.get(beanName); Object o = hashMap.get(beanName); return o; } else { throw new NullPointerException(); } }
总结
通过简单手写Spring源码,有了更深的理解。