美文网首页
尝试实现IoC和AOP

尝试实现IoC和AOP

作者: Lnstark | 来源:发表于2020-03-28 23:55 被阅读0次

    尝试以实现一下IoC容器和AOP的方式来学习Spring,以对Spring有更深的理解。
    这只是基于当前对Spring的认识写的,实现的还是很粗糙的,感兴趣的同学可以交流一下。
    IoC大致类图如下:


    IoC类图

    仿照SpringBoot的启动方式,在主类里

    Context ctx = Application.run(App.class);
    

    启动,run方法点进来,

        public static Context run(Class<?> clz) {
            return new Application(clz).run();
        }
    

    先看构造方法

        private Application(Class<?> clz) {
            // 扫描包的路径
            path = clz.getResource("").getFile();
            path = path.replaceAll("%20", " ");// 替换空格
            config = new ConfigurationResolver();
    
            packageName = clz.getPackage().getName();
            this.clz = clz;
    
            context = new WebContext();
            ContextAware.setContext(context);
        }
    
    1. 获取启动类的路径和包名
    2. 加载配置文件,就是读取yml文件。
    3. 初始化上下文context

    上下文context主要写在AbstractContext里,注入的对象就直接放在一个叫beans的HashMap里了。
    这里就一些bean的add和get方法。
    在看run方法:

        public Context run() {
            Scanner.getInstance().scanBeans(path, packageName);
            startServer();
            return context;
        }
    
    1. 扫描并注入对象
    2. 启动服务

    启动服务直接用的是embed tomcat包,主要写在TomcatServer的runService方法里

         public void runService() {
            Tomcat tomcat = new Tomcat();
            tomcat.setPort(port);
            String tmpDirPath = System.getProperty("user.dir") + File.separator + WEBAPP_PATH;
            org.apache.catalina.Context ctxt = tomcat.addContext(contextPath, tmpDirPath);
            Tomcat.addServlet(ctxt, "servlet", new DispatcherServlet());
            ctxt.addServletMappingDecoded("/", "servlet");
            try {
                tomcat.start();
            } catch (LifecycleException e) {
                e.printStackTrace();
            }
            tomcat.getServer().await();
        }
    

    好我们主要看对象的注入,scanBeans方法里:

        public void scanBeans(String basePath, String packageName) {
            scanFiles(basePath, packageName);
            AnalyzerFactory.getAnalyzer(ClassAnalyzer.class).loadClasses(classNames);
        }
    
    1. scanFiles获取包下面所有的类名,放在classNames数组里
    2. 获取类解析器ClassAnalyzer并解析所有类

    loadClass点进去:

    public void loadClasses(List<String> classNames) {
            Class<?> clazz = null;
            // 先加载所有类,再逐个解析类的属性和方法
            for (String className : classNames) {
                try {
                    clazz = loader.loadClass(className);// 默认初始化
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
                if (clazz == null || clazz.isInterface() || clazz.isAnnotation())
                    continue;
                // load class
                analyzeClass(clazz);
            }
    
            for (Map.Entry<Class<?>, List<Object>> entry : clzInstanceMap.entrySet()) {
                Class clz = entry.getKey();
                for (Object o : entry.getValue()) {
                    analyzeFieldMethod(clz, o);// 现在就写了bean注入解析
                }
            }
    
            // 解析controller
            for (Object o : context.getAll()) {
                Class<?> clz = o.getClass();//entry.getKey();
                Controller c = clz.getAnnotation(Controller.class);
                if(c != null)
                    MethodMappingResolver.getInstance().resolveController(clz);// 解析controller方法
            }
    
            // 解析AOP
            AopAnalyzer aopAnalyzer = AnalyzerFactory.getAnalyzer(AopAnalyzer.class);
            aopAnalyzer.analyze();
        }
    

    先过一遍所有的类,把类上带注解的注入进来,然后过一遍方法,把带@Bean的注入进来。
    然后是解析controller和AOP。
    analyzeClass方法:

        public void analyzeClass(Class<?> clazz) {
            Annotation[] classAnnotations = clazz.getAnnotations();
            Object instance = null;
            boolean inject = false;
            String aValue = "";
            for (Annotation a : classAnnotations) {
                if (a instanceof Component) {
                    aValue = ((Component) a).value();
                    inject = true;
                } else if (a instanceof Controller) {
                    aValue = ((Controller) a).value();
                    inject = true;
                }
            }
            if(inject) {
                String name = aValue.equals("") ? firstLetterToLower(clazz.getSimpleName()) : aValue;
                instance = newInstance(clazz);
                clzInstanceMap.add(clazz, instance);
                context.addBean(name, instance);
                log.info("--------------" + name + "injected----------------");
            }
        }
    

    这里其实不应该写判断"a instanceof Controller", 而应该判断a有没有Component注解,待修改。

    github: https://github.com/Ltyro/MySpring

    相关文章

      网友评论

          本文标题:尝试实现IoC和AOP

          本文链接:https://www.haomeiwen.com/subject/fxseuhtx.html