欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

代码实现还原Spring基本功能,实现IOC,DI,AOP

程序员文章站 2022-10-03 17:16:10
致谢:首先感谢Tom老师,看了Tom老师的视频后,对Spring的实现思路有了更清晰的认识。首先先总结一下实现Spring功能的一个整体思路。实现Spring基本需要经过一下步骤:配置阶段–>初始化阶段–>运行阶段大致流程了解之后我们再细化每个阶段。1、配置阶段:我们需要在web.xml中配置Servlet,init-param,url-pattern,以及新建自定义注解(实现Spring过程中,不需要引入Spring依赖,注解也需要自己自定义)2、初始化阶段:配置阶段完成....

致谢:首先感谢Tom老师,看了Tom老师的视频后,对Spring的实现思路有了更清晰的认识。

首先先总结一下实现Spring功能的一个整体思路。
实现Spring基本需要经过一下步骤:
配置阶段–>初始化阶段–>运行阶段
代码实现还原Spring基本功能,实现IOC,DI,AOP
大致流程了解之后我们再细化每个阶段。
1、配置阶段:
我们需要在web.xml中配置Servlet,init-param,url-pattern,以及新建自定义注解(实现Spring过程中,不需要引入Spring依赖,注解也需要自己自定义)
2、初始化阶段:
配置阶段完成之后,我们需要在初始画阶段做以下处理:

  • 读取配置文件
  • 初始化IOC容器
  • 扫描相关的类
  • 实例化相关的类,并保存到IOC容器中
  • 实现依赖注入
  • 初始化HandlerMapping

3、运行阶段
用户请求后调用doGet/doPost方法,
拿到请求地址,取出requestMapping路径,
拿resquestMapping路径与HandlerMapping匹配,
反射调用method.invoke(),
返回前端

代码实现还原Spring基本功能,实现IOC,DI,AOP
代码区:

配置阶段:

1、配置application.properties

#要扫描的包#
scanPackage=com.nxw.demo

2、配置web.xml

<servlet>
        <servlet-name>MySpring</servlet-name>
        <servlet-class>com.nxw.spring.webmvc.NDispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:application.properties</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>MySpring</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

3、自定义注解

/**
 * Cntroller注解
 * @author Silence
 */

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NController {
    String value() default "";

}

/**
 * 业务逻辑注入注解
 * @author Silence
 */

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NService {
    String value() default "";
}

/**
 * 请求url
 * @author Silence
 */

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NRequestMapping {
    String value() default "";
}

/**
 *  请求参数映射
 * @author Silence
 *
 */

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NRequestParam {
    String value() default "";
    boolean required() default true;
}

/**
 * 自动注入注解
 * @author Silence
 */

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NAutowired {
    String value() default "";
}

初始化阶段:

1、读取配置文件

private void doLoadConfig(String contextConfigLocation) {
        //classpath下找到application.properties配置文件,并且读取出来
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation.replaceAll("classpath:",""));
        try {
            contextConfig.load(is);
        } catch (IOException e) {
            System.err.println("没有找到配置文件");
            e.printStackTrace();

        }finally {
            if(null != is){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2、初始化IOC容器 就是创建一个map

private Map<String,Object> ioc = new HashMap<String, Object>();

3、扫描相关的类

 private void doScanner(String scanPackage) {
        URL url = this.getClass().getClassLoader().getResource("/"+scanPackage.replaceAll(("\\."),"/"));
        File classpath = new File(url.getFile());
        for (File file : classpath.listFiles()) {
            //判断是不是文件夹,如果是递归
            if(file.isDirectory()){
                doScanner(scanPackage + "." + file.getName());
            }else {
                //判断是不是以.class结尾的文件
                if(!file.getName().endsWith(".class")) {continue;}
                //拼接全类名,可以通过Class.forName()
                String className = (scanPackage + "." + file.getName().replace(".class", ""));
                //存入list
                classNames.add(className);
            }
        }
    }

4、实例化相关的类,并且缓存到IOC容器中

 private void doInstance() {
        //扫描刚刚扫描的类
        if(classNames.isEmpty()){return;}
        for (String className : classNames) {
            try {
                Class clazz = Class.forName(className);

                if(clazz.isAnnotationPresent(NController.class)) {
                    String beanName = toLowerFirstCase(clazz.getSimpleName());
                    Object instance = clazz.newInstance();
                    ioc.put(beanName, instance);
                }else if(clazz.isAnnotationPresent(NService.class)){
                    String beanName = toLowerFirstCase(clazz.getSimpleName());
                    //自定义beanName,不同包下相同类名
                    NService service = (NService) clazz.getAnnotation(NService.class);
                    if(!"".equals(service.value())){
                        beanName = service.value();
                    }

                    Object instance = clazz.newInstance();
                    ioc.put(beanName, instance);

                    //如果是接口,用它的实现类赋值
                    for (Class i : clazz.getInterfaces()) {
                        if (ioc.containsKey(i.getName())){
                            throw new Exception("This beanName already exists!");
                        }
                        //匹配接口类型
                        ioc.put(i.getName(),instance);
                    }

                }else{
                    continue;
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

5、完成依赖注入

private void doAutowrited() {
        if(ioc.isEmpty()){return;}
        for (Map.Entry<String, Object> entry : ioc.entrySet()) {
            //把所有的private,public,default,prodected都拿到
            Field fields [] = entry.getValue().getClass().getDeclaredFields();

            for (Field field : fields) {
                if(!field.isAnnotationPresent(NAutowired.class)){
                    continue;
                }
                NAutowired autowired = field.getAnnotation(NAutowired.class);
                String beanName = autowired.value().trim();
                if("".equals(beanName.trim())){
                    beanName = field.getType().getName();
                }

                //暴力访问,可以通过反射拿到所有的private,public,default,prodected
                field.setAccessible(true);

                try {
                    field.set(entry.getValue(),ioc.get(beanName));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
   }

6、初始化HandlerMapping

private void doHandlerMapper() {
        if(ioc.isEmpty()){return;}
        for (Map.Entry<String, Object> entry : ioc.entrySet()) {
            Class<?> clazz = entry.getValue().getClass();

            if(!clazz.isAnnotationPresent(NController.class)){continue;}

            String baseUrl = null;
            if(clazz.isAnnotationPresent(NRequestMapping.class)){
                NRequestMapping requestMapping = clazz.getAnnotation(NRequestMapping.class);
                baseUrl = requestMapping.value();

            }

            for (Method method : clazz.getMethods()) {
                if(!method.isAnnotationPresent(NRequestMapping.class)){continue;}
                NRequestMapping requestMapping = method.getAnnotation(NRequestMapping.class);
                String url = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+","/");
                handleMapping.put(url,method);
                System.out.println("Mapping : " + url + " , "+method);
            }
        }
    }

运行阶段:
doPost()

 //7、调用具体的方法
        String url = req.getRequestURL().toString();
        String contextPath = req.getContextPath();
        String url1 = url.replaceAll("http://localhost:8080","");

        System.out.println("URL : "+url);
        if(!this.handleMapping.containsKey(url1)){
            resp.getWriter().write("404 Not Found!");
            return;
        }

        Map<String,String []> params = req.getParameterMap();
        Method method = this.handleMapping.get(url1);
        String beanName = toLowerFirstCase(method.getDeclaringClass().getSimpleName());
        method.invoke(ioc.get(beanName),new Object[] {req,resp,params.get("name")[0],params.get("addr")[0]});

至此Spring基本功能已经实现。

源码请到 https://download.csdn.net/download/nxw_tsp/12646030 下载

本文地址:https://blog.csdn.net/nxw_tsp/article/details/107483054