Browse Source

青涩知夏-IOC

青涩知夏 4 years ago
parent
commit
3bc3dfc946

+ 4 - 4
src/main/java/cn/nosum/demo/mvc/action/DemoAction.java

@@ -6,10 +6,10 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import cn.nosum.demo.service.IDemoService;
-import cn.nosum.framework.mvc.annotation.Autowired;
-import cn.nosum.framework.mvc.annotation.Controller;
-import cn.nosum.framework.mvc.annotation.RequestMapping;
-import cn.nosum.framework.mvc.annotation.RequestParam;
+import cn.nosum.framework.annotation.Autowired;
+import cn.nosum.framework.annotation.Controller;
+import cn.nosum.framework.annotation.RequestMapping;
+import cn.nosum.framework.annotation.RequestParam;
 
 
 //虽然,用法一样,但是没有功能

+ 1 - 1
src/main/java/cn/nosum/demo/service/impl/DemoService.java

@@ -1,7 +1,7 @@
 package cn.nosum.demo.service.impl;
 
 import cn.nosum.demo.service.IDemoService;
-import cn.nosum.framework.mvc.annotation.Service;
+import cn.nosum.framework.annotation.Service;
 
 /**
  * 核心业务逻辑

+ 1 - 1
src/main/java/cn/nosum/framework/mvc/annotation/Autowired.java

@@ -1,4 +1,4 @@
-package cn.nosum.framework.mvc.annotation;
+package cn.nosum.framework.annotation;
 
 import java.lang.annotation.*;
 

+ 1 - 1
src/main/java/cn/nosum/framework/mvc/annotation/Controller.java

@@ -1,4 +1,4 @@
-package cn.nosum.framework.mvc.annotation;
+package cn.nosum.framework.annotation;
 
 import java.lang.annotation.*;
 

+ 1 - 1
src/main/java/cn/nosum/framework/mvc/annotation/RequestMapping.java

@@ -1,4 +1,4 @@
-package cn.nosum.framework.mvc.annotation;
+package cn.nosum.framework.annotation;
 
 import java.lang.annotation.*;
 

+ 1 - 1
src/main/java/cn/nosum/framework/mvc/annotation/RequestParam.java

@@ -1,4 +1,4 @@
-package cn.nosum.framework.mvc.annotation;
+package cn.nosum.framework.annotation;
 
 import java.lang.annotation.*;
 

+ 1 - 1
src/main/java/cn/nosum/framework/mvc/annotation/Service.java

@@ -1,4 +1,4 @@
-package cn.nosum.framework.mvc.annotation;
+package cn.nosum.framework.annotation;
 
 import java.lang.annotation.*;
 

+ 22 - 0
src/main/java/cn/nosum/framework/beans/BeanDefinition.java

@@ -0,0 +1,22 @@
+package cn.nosum.framework.beans;
+
+public class BeanDefinition {
+    private String beanClassName;
+    private String factoryBeanName;
+
+    public String getBeanClassName() {
+        return beanClassName;
+    }
+
+    public void setBeanClassName(String beanClassName) {
+        this.beanClassName = beanClassName;
+    }
+
+    public String getFactoryBeanName() {
+        return factoryBeanName;
+    }
+
+    public void setFactoryBeanName(String factoryBeanName) {
+        this.factoryBeanName = factoryBeanName;
+    }
+}

+ 27 - 0
src/main/java/cn/nosum/framework/beans/BeanWrapper.java

@@ -0,0 +1,27 @@
+package cn.nosum.framework.beans;
+
+public class BeanWrapper {
+    private Object wrapperInstance;
+    private Class<?> wrappedClass;
+
+    public BeanWrapper(Object instance) {
+        this.wrappedClass=instance.getClass();
+        this.wrapperInstance=instance;
+    }
+
+    public Object getWrapperInstance() {
+        return wrapperInstance;
+    }
+
+    public void setWrapperInstance(Object wrapperInstance) {
+        this.wrapperInstance = wrapperInstance;
+    }
+
+    public Class<?> getWrappedClass() {
+        return wrappedClass;
+    }
+
+    public void setWrappedClass(Class<?> wrappedClass) {
+        this.wrappedClass = wrappedClass;
+    }
+}

+ 101 - 0
src/main/java/cn/nosum/framework/beans/support/BeanDefinitionReader.java

@@ -0,0 +1,101 @@
+package cn.nosum.framework.beans.support;
+
+import cn.nosum.framework.beans.BeanDefinition;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+public class BeanDefinitionReader {
+    private List<String> registryBeanClasses=new ArrayList<String>();
+    private Properties config=new Properties();
+
+    public BeanDefinitionReader(String... locations){
+        InputStream is=this.getClass().getClassLoader().getResourceAsStream(locations[0].replace("classpath:",""));
+        try {
+            config.load(is);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }finally {
+            if (null!=is){
+                try { is.close(); } catch (IOException e) { e.printStackTrace(); }
+            }
+        }
+        doScanner(config.getProperty("scanPackage"));
+    }
+
+    /**
+     * 扫描
+     */
+    private void doScanner(String scanPackage){
+        URL url=this.getClass().getClassLoader().getResource("/"+scanPackage.replaceAll("\\.","/"));
+        if (url == null){ return; }
+        File classPath=new File(url.getFile());
+        File[] files = classPath.listFiles();
+        if (files == null){return;}
+        for (File file : files) {
+            if (file.isDirectory()){
+                doScanner(scanPackage+"."+file.getName());
+            }else{
+                if (file.getName().endsWith(".class")){
+                    String className=scanPackage+"."+file.getName().replace(".class","");
+                    registryBeanClasses.add(className);
+                }
+            }
+        }
+    }
+
+    /**
+     * 将扫描到的所有配置信息转换为 BeanDefinition 对象,以便于 IOC 操作
+     */
+    public List<BeanDefinition> loadBeanDefinitions(){
+        List<BeanDefinition> result=new ArrayList<BeanDefinition>();
+        try {
+            for (String className : registryBeanClasses) {
+                Class<?> beanClass=Class.forName(className);
+                // 如果是一个接口,则使用实现类
+                if (beanClass.isInterface()){continue;}
+                result.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()),beanClass.getName()));
+                // 如果有多个实现类
+                Class<?>[] interfaces=beanClass.getInterfaces();
+                for (Class<?> i : interfaces) {
+                    result.add(doCreateBeanDefinition(toLowerFirstCase(i.getName()),beanClass.getName()));
+                }
+            }
+        }catch (Exception e){e.printStackTrace();}
+        return result;
+    }
+
+    public BeanDefinition doCreateBeanDefinition(String factoryBeanName,String beanClassName){
+        BeanDefinition beanDefinition=new BeanDefinition();
+        beanDefinition.setBeanClassName(beanClassName);
+        beanDefinition.setFactoryBeanName(factoryBeanName);
+        return beanDefinition;
+    }
+
+    public  String toLowerFirstCase(String simpleName){
+        char[] chars=simpleName.toCharArray();
+        chars[0]+=32;
+        return String.valueOf(chars);
+    }
+
+    public List<String> getRegistryBeanClasses() {
+        return registryBeanClasses;
+    }
+
+    public void setRegistryBeanClasses(List<String> registryBeanClasses) {
+        this.registryBeanClasses = registryBeanClasses;
+    }
+
+    public Properties getConfig() {
+        return config;
+    }
+
+    public void setConfig(Properties config) {
+        this.config = config;
+    }
+}

+ 140 - 0
src/main/java/cn/nosum/framework/context/ApplicationContext.java

@@ -0,0 +1,140 @@
+package cn.nosum.framework.context;
+
+import cn.nosum.framework.annotation.Autowired;
+import cn.nosum.framework.annotation.Controller;
+import cn.nosum.framework.annotation.Service;
+import cn.nosum.framework.beans.BeanDefinition;
+import cn.nosum.framework.beans.BeanWrapper;
+import cn.nosum.framework.beans.support.BeanDefinitionReader;
+
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class ApplicationContext {
+    protected final Map<String, BeanDefinition> beanDefinitionMap=new ConcurrentHashMap<String, BeanDefinition>();
+    private String[] configLocations;
+    private BeanDefinitionReader reader;
+
+    private Map<String,Object> factoryBeanObjectCache=new ConcurrentHashMap<String, Object>();
+    private Map<String, BeanWrapper> factoryBeanInstanceCache=new ConcurrentHashMap<String, BeanWrapper>();
+
+    public ApplicationContext(String... configLocations){
+        this.configLocations=configLocations;
+        try {
+            // 定位
+            reader=new BeanDefinitionReader(this.configLocations);
+            // 加载配置文件,扫描相关的类,包装为 BeanDefinition
+            List<BeanDefinition>beanDefinitions=reader.loadBeanDefinitions();
+            // 注册,将配置信息放到容器中
+            doRegistryBeanDefinition(beanDefinitions);
+            // 依赖注入
+            doAutowired();
+        }catch (Exception e){e.printStackTrace();}
+    }
+
+    private void doRegistryBeanDefinition(List<BeanDefinition> beanDefinitions) throws Exception {
+        for (BeanDefinition beanDefinition : beanDefinitions) {
+            if (this.beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())){
+                throw new Exception("The Bean " + beanDefinition.getFactoryBeanName() + "is exists!!");
+            }
+            this.beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition);
+            this.beanDefinitionMap.put(beanDefinition.getBeanClassName(),beanDefinition);
+        }
+    }
+
+    private void doAutowired() {
+        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : this.beanDefinitionMap.entrySet()) {
+            String beanName=beanDefinitionEntry.getKey();
+            try {
+                getBean(beanName);
+            }catch (Exception e){e.printStackTrace();}
+        }
+    }
+
+    private Object getBean(Class<?> beanClass) {
+        return getBean(beanClass.getName());
+    }
+
+    private Object getBean(String beanName) {
+        // 读取配置信息
+        BeanDefinition beanDefinition=this.beanDefinitionMap.get(beanName);
+        // 将对象封装到 BeanDefinitionWrapper 中
+        BeanWrapper beanWrapper=new BeanWrapper(instantiateBean(beanDefinition));
+        // 缓存
+        this.factoryBeanInstanceCache.put(beanName,beanWrapper);
+        // 依赖注入
+        populateBean(beanName,beanDefinition,beanWrapper);
+        return this.factoryBeanInstanceCache.get(beanName).getWrapperInstance();
+    }
+
+    private void populateBean(String beanName, BeanDefinition beanDefinition, BeanWrapper beanWrapper) {
+        //可能涉及到循环依赖?
+        //A{ B b}
+        //B{ A b}
+        //用两个缓存,循环两次
+        //1、把第一次读取结果为空的BeanDefinition存到第一个缓存
+        //2、等第一次循环之后,第二次循环再检查第一次的缓存,再进行赋值
+        Object instance = beanWrapper.getWrapperInstance();
+        Class<?> clazz = beanWrapper.getWrappedClass();
+        //在Spring中@Component
+        if(!(clazz.isAnnotationPresent(Controller.class) || clazz.isAnnotationPresent(Service.class))){
+            return;
+        }
+        //把所有的包括private/protected/default/public 修饰字段都取出来
+        for (Field field : clazz.getDeclaredFields()) {
+            if(!field.isAnnotationPresent(Autowired.class)){ continue; }
+            Autowired autowired = field.getAnnotation(Autowired.class);
+            //如果用户没有自定义的beanName,就默认根据类型注入
+            String autowiredBeanName = autowired.value().trim();
+            if("".equals(autowiredBeanName)){
+                //field.getType().getName() 获取字段的类型
+                autowiredBeanName = field.getType().getName();
+            }
+            //暴力访问
+            field.setAccessible(true);
+            try {
+                if(this.factoryBeanInstanceCache.get(autowiredBeanName) == null){
+                    continue;
+                }
+                field.set(instance,this.factoryBeanInstanceCache.get(autowiredBeanName).getWrapperInstance());
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+                continue;
+            }
+        }
+
+    }
+
+    private Object instantiateBean(BeanDefinition beanDefinition) {
+        // 取得实例化对象的类名
+        String className=beanDefinition.getBeanClassName();
+        Object instance=null;
+        try{
+            if (this.factoryBeanObjectCache.containsKey(className)){
+                instance=this.factoryBeanObjectCache.get(className);
+            }else{
+                Class<?> clazz=Class.forName(className);
+                instance=clazz.getDeclaredConstructor().newInstance();
+                this.factoryBeanObjectCache.put(className,instance);
+                this.factoryBeanObjectCache.put(beanDefinition.getFactoryBeanName(),instance);
+            }
+        }catch (Exception e){e.printStackTrace();}
+        return instance;
+    }
+
+    public String[] getBeanDefinitionNames(){
+        return this.beanDefinitionMap.keySet().toArray(new String[getBeanDefinitionCount()]);
+    }
+
+    public int getBeanDefinitionCount(){
+        return this.beanDefinitionMap.size();
+    }
+
+   public Properties getConfig(){
+        return this.reader.getConfig();
+   }
+
+}

+ 4 - 4
src/main/java/cn/nosum/framework/mvc/v1/servlet/DispatcherServlet.java

@@ -1,9 +1,9 @@
 package cn.nosum.framework.mvc.v1.servlet;
 
-import cn.nosum.framework.mvc.annotation.Autowired;
-import cn.nosum.framework.mvc.annotation.Controller;
-import cn.nosum.framework.mvc.annotation.RequestMapping;
-import cn.nosum.framework.mvc.annotation.Service;
+import cn.nosum.framework.annotation.Autowired;
+import cn.nosum.framework.annotation.Controller;
+import cn.nosum.framework.annotation.RequestMapping;
+import cn.nosum.framework.annotation.Service;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;

+ 1 - 1
src/main/java/cn/nosum/framework/mvc/v2/servlet/DispatcherServlet.java

@@ -1,6 +1,6 @@
 package cn.nosum.framework.mvc.v2.servlet;
 
-import cn.nosum.framework.mvc.annotation.*;
+import cn.nosum.framework.annotation.*;
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;

+ 1 - 2
src/main/java/cn/nosum/framework/mvc/v3/servlet/GPDispatcherServlet.java

@@ -1,7 +1,6 @@
 package cn.nosum.framework.mvc.v3.servlet;
 
-import cn.nosum.framework.mvc.annotation.*;
-import cn.nosum.framework.mvc.annotation.*;
+import cn.nosum.framework.annotation.*;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;