Spring 就像是我们写代码的一个管家,可能我们在项目中要创建对象,要写单例多例,要加日志,要加事务等等很多功能点。那这些东西如果能有一个现有的框架那就好了,它就是Spring,它不但实现了以上的功能,并且集成容纳各种其他的开源框架。
自己手写Spring的核心就是springbean的生成。
1:通过包扫描 获取到哪些类需要加载到spring容器中,加载到spring中到底是单例还是多例。
2:单例是从单例池(map)中获取,非单例就是每次getBean的时候重新的创建一个新的对象。
3:因为只有包的名称,所以要通过获取包下面的file来获取file的名称以及全路径,从而通过classload把class信息加载到beanDefinition中
核心代码
public ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();public ConcurrentHashMap<String, Object> singleObjects = new ConcurrentHashMap<String, Object>();public AnnotationConfigApplicationContext(Class clazz){//1:通过给的类 获取到需要加载的bean的位置scan(clazz);//2.加载到容器instanceSingleBean();}private void instanceSingleBean(){try {//1:获取beanDefinitionMap 封装的类信息for (String beanName : beanDefinitionMap.keySet()){BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if("singleton".equals(beanDefinition.getScope())){Object bean = doCreateBean(beanDefinition);singleObjects.put(beanName, bean);}}}catch (Exception e){e.printStackTrace();}}private Object doCreateBean(BeanDefinition beanDefinition) throws Exception{Class clazz = beanDefinition.getBeanClass();Object bean = clazz.getDeclaredConstructor().newInstance();Field[] fields = clazz.getDeclaredFields();for (Field field : fields){String beanName = field.getName();if(field.isAnnotationPresent(Autowried.class)){Object fieldBean = getBean(beanName);field.setAccessible(true);field.set(bean, fieldBean);}}return bean;}private void scan(Class clazz) {//1:获取当前类的注解 找到需要扫描的包的路径ComponentScan scan = (ComponentScan)clazz.getAnnotation(ComponentScan.class);String packagePath = scan.value();//获取当前包下的所有的类List<Class> packageClass = genBeanClasses(packagePath);//2:把类封装为BeanDefinition的maptoMap(packageClass);}private void toMap(List<Class> packageClass) {for (Class clazz : packageClass){if(clazz.isAnnotationPresent(Service.class)){//通过当前clazz封装BeanDefinitionBeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setBeanClass(clazz);Service service = (Service) clazz.getAnnotation(Service.class);String beanName = service.value();if(clazz.isAnnotationPresent(Scope.class)){Scope scope = (Scope) clazz.getAnnotation(Scope.class);String scopeValue = scope.value();if("prototype".equals(scopeValue)){beanDefinition.setScope("prototype");}else{beanDefinition.setScope("singleton");}}beanDefinitionMap.put(beanName, beanDefinition);}}}/*** 通过com.mkb.server -> com/mkb/service 再拼接上 类的全路径 得到file文件 通过file文件 获取到文件名 就是 service名称* 然后通过 classLoader.loadClass(className); 获取到class 集合*/private List<Class> genBeanClasses(String packagePath) {List<Class> beanClasses = new ArrayList<Class>();ClassLoader classLoader = AnnotationConfigApplicationContext.class.getClassLoader();packagePath = packagePath.replace(".", "/");URL resource = classLoader.getResource(packagePath);File file = new File(resource.getFile());if (file.isDirectory()) {File[] files = file.listFiles();for (File f : files) {String fileName = f.getAbsolutePath();if (fileName.endsWith(".class")) {String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));className = className.replace("\\", ".");try {Class<?> clazz = classLoader.loadClass(className);beanClasses.add(clazz);} catch (ClassNotFoundException e) {e.printStackTrace();}}}}return beanClasses;}public Object getBean(String beanName) throws Exception{if(!beanDefinitionMap.containsKey(beanName)){throw new Exception();}BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if("singleton".equals(beanDefinition.getScope())){return singleObjects.get(beanName);}else{return doCreateBean(beanDefinition);}}
