自己实现SpringMVC 底层机制[二]

简介: 自己实现SpringMVC 底层机制[二]

自己实现SpringMVC 底层机制[二]


实现任务阶段3- 从web.xml 动态获取myspringmvc.xml


前面我们加载myspringmvc.xml 是硬编码, 现在做活, 从web.xml 动态获取,


分图析示意


9ca347d50f06434bae0f30f2662713b6.png

MyDispatcherServlet 在创建并初始化MyWebApplicationContext,动态的从web.xml 中获取到配置文件.


代码实现


修改my-springmvc\src\main\java\com\myspringmvc\context\MyWebApplicationContext.java

public class MyWebApplicationContext {
    //定义属性classFullPathList, 保存扫描包/子包的类的全路径
    private List<String> classFullPathList =
            new ArrayList<>();
    //定义属性ioc, 存放反射生成的Bean对象 /Controller/Service
    public ConcurrentHashMap<String, Object> ioc =
            new ConcurrentHashMap<>();
    //无参构造器
    public MyWebApplicationContext() {
    }
    private String configLocation;//属性,表示spring容器配置文件
    public MyWebApplicationContext(String configLocation) {
        this.configLocation = configLocation;
    }
    //编写方法,完成自己的spring容器的初始化
    public void init() {
        //这里是写的固定的spring容器配置文件=>做活
        //String basePackage = XMLParser.getBasePackage("myspringmvc.xml");
        String basePackage =
                XMLParser.getBasePackage(configLocation.split(":")[1]);
        //这时basePackage => com.controller,com.service
        String[] basePackages = basePackage.split(",");
        //判断包是否为空
        if (basePackages.length > 0) {
            //遍历basePackages, 进行扫描
            for (String pack : basePackages) {
                scanPackage(pack);//扫描包保存路径放在集合,便于后面进行反射到容器
            }
        }
        System.out.println("扫描后的= classFullPathList=" + classFullPathList);//测试得到的路径集合是否正确
        //将扫描到的类, 反射到ico容器
        executeInstance();
        System.out.println("扫描后的 ioc容器= " + ioc);
    }
}


修改my-springmvc\src\main\java\com\myspringmvc\servlet\MyDispatcherServlet.java

@Override
    public void init(ServletConfig servletConfig) throws ServletException {
        //获取到web.xml中的 contextConfigLocation
        /*
         <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:myspringmvc.xml</param-value>
        </init-param>
         */
        String configLocation =
                servletConfig.getInitParameter("contextConfigLocation");
        //创建自己的spring容器
        myWebApplicationContext =
                new MyWebApplicationContext(configLocation);
        myWebApplicationContext.init();//完成容器初始化
        //调用 initHandlerMapping , 完成url和控制器方法的映射
        initHandlerMapping();
        //输出handlerList
        System.out.println("handlerList初始化的结果= " + handlerList);
    }

完成测试(启动tomcat 方式, 修改后,redeploye 即可生效)。


实现任务阶段4- 完成自定义@Service 注解功能。


功能说明: 如果给某个类加上@Service, 则可以将其注入到我们的Spring 容器


分析示意图


cfe35e6ea6dc4eb39a8256ef1d06d437.png

给Service 类标注@Service, 可以将对象注入到Spring 容器中。

可以通过接口名支持多级类名来获取到Service Bean。

如下

//扫描后的ioc
ioc={monsterService=com.service.impl.MonsterServiceImpl@6323a1c1,
orderController=com.controller.OrderController@4c96ec4f,
monsterController=com.controller.MonsterController@81664b3}


代码实现


创建my-springmvc\src\main\java\com\entity\Monster.java

public class Monster {
    private Integer id;
    private String name;
    private String skill;
    private Integer age;
    public Monster(Integer id, String name, String skill, Integer age) {
        this.id = id;
        this.name = name;
        this.skill = skill;
        this.age = age;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSkill() {
        return skill;
    }
    public void setSkill(String skill) {
        this.skill = skill;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Monster{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", skill='" + skill + '\'' +
                ", age=" + age +
                '}';
    }
}


创建my-springmvc\src\main\java\com\myspringmvc\annotation\Service.java

// Service 注解,用于标识一个Service对象,并注入到spring容器
@Target(ElementType.TYPE)//该注解只能声明在一个类前
@Retention(RetentionPolicy.RUNTIME)//不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
@Documented//  java 在生成文档,显示注解
public @interface Service {
    String value() default "";
}


创建my-springmvc\src\main\java\com\service\MonsterService.java

public interface MonsterService{
    //增加方法-返回monster列表
    public List<Monster> listMonster();
}


创建my-springmvc\src\main\java\com\service\impl\MonsterServiceImpl.java

@Service
public class MonsterServiceImpl implements MonsterService {
    @Override
    public List<Monster> listMonster() {
        //这里模拟数据->DB
        List<Monster> monsters =  new ArrayList<>();
        monsters.add(new Monster(100, "牛魔王", "芭蕉扇", 400));
        monsters.add(new Monster(200, "老猫妖怪", "抓老鼠", 200));
        return monsters;
    }
}


修改my-springmvc\src\main\resources\myspringmvc.xml

<?xml version="1.0" encoding="utf-8" ?>
<beans>
    <!--指定要扫描的基本包以及子包的java类-->
    <component-scan base-package="com.controller,com.service"></component-scan>
</beans>


修改my-springmvc\src\main\java\com\myspringmvc\context\MyWebApplicationContext.java

 //编写方法,将扫描到的类, 在满足条件的情况下,反射到ioc容器
//实例化扫描到的类->创建对象->放入到IOC 容器[ConcurrentHashMap]
    public void executeInstance() {
        //判断是否扫描到类
        if (classFullPathList.size() == 0) {//说明没有扫描到类
            return;
        }
        try {
            //遍历classFullPathList,进行反射
            for (String classFullPath : classFullPathList) {
                Class<?> clazz = Class.forName(classFullPath);
                //说明当前这个类有@Controller
                if (clazz.isAnnotationPresent(Controller.class)) {
                    //得到类名首字母小写
                    String beanName = clazz.getSimpleName().substring(0, 1).toLowerCase() +
                            clazz.getSimpleName().substring(1);
                    ioc.put(beanName, clazz.newInstance());
                } //如果有其它的注解,可以扩展 , 来处理@Service
                else if (clazz.isAnnotationPresent(Service.class)) {//如果类有@Serivce注解
                    //先获取到Service的value值=> 就是注入时的beanName
                    Service serviceAnnotation =
                            clazz.getAnnotation(Service.class);
                    String beanName = serviceAnnotation.value();
                    if ("".equals(beanName)) {//说明没有指定value, 我们就使用默认的机制注入Service
                        //可以通过接口名/类名[首字母小写]来注入ioc容器
                        //1.得到所有接口的名称=>反射
                        Class<?>[] interfaces = clazz.getInterfaces();
                        Object instance = clazz.newInstance();
                        //2. 遍历接口,然后通过多个接口名来注入
                        for (Class<?> anInterface : interfaces) {
                            //接口名->首字母小写
                            String beanName2 = anInterface.getSimpleName().substring(0, 1).toLowerCase() +
                                    anInterface.getSimpleName().substring(1);
                            ioc.put(beanName2, instance);
                        }
                    } else {//如果有指定名称,就使用该名称注入即可
                        ioc.put(beanName, clazz.newInstance());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


完成测试(启动Tomcat, 自动加载MyDispatcherServlet, 完成IOC 容器的注入)。


扫描后的ioc= {monsterService=com.service.impl.MonsterServiceImpl@6323a1c1,
orderController=com.controller.OrderController@4c96ec4f,
monsterController=com.controller.MonsterController@81664b3}


相关文章
|
6月前
|
设计模式 前端开发 Java
【深入浅出Spring原理及实战】「夯实基础系列」360全方位渗透和探究SpringMVC的核心原理和运作机制(总体框架原理篇)
【深入浅出Spring原理及实战】「夯实基础系列」360全方位渗透和探究SpringMVC的核心原理和运作机制(总体框架原理篇)
69 0
|
XML JSON 前端开发
SpringMVC系列(六)之JSON数据返回以及异常处理机制
SpringMVC系列(六)之JSON数据返回以及异常处理机制
|
JSON 前端开发 Java
SpringMVC之JSON数据返回&异常处理机制
SpringMVC之JSON数据返回&异常处理机制
89 0
|
JSON 前端开发 Java
【SpringMVC】JSON注解&全局异常处理机制(二)
【SpringMVC】JSON注解&全局异常处理机制(二)
66 0
|
存储 JSON 前端开发
SpringMVC之JSON返回&异常处理机制(带你学习新的SpringMVC武功秘籍)
SpringMVC之JSON返回&异常处理机制(带你学习新的SpringMVC武功秘籍)
202 0
|
XML JSON 开发框架
【推荐】SpringMVC与JSON数据返回及异常处理机制的使用
【推荐】SpringMVC与JSON数据返回及异常处理机制的使用
109 0
|
1月前
|
XML 存储 前端开发
手动开发-实现SpringMVC底层机制--小试牛刀
手动开发-实现SpringMVC底层机制--小试牛刀
14 0
|
JSON 前端开发 Java
SpringMVC之JSON返回及异常处理机制
SpringMVC之JSON返回及异常处理机制
57 0
|
6月前
SpringMVC异常处理机制
SpringMVC异常处理机制
35 0
|
SQL JSON fastjson
SpringMVC之JSON返回&异常处理机制
SpringMVC之JSON返回&异常处理机制
64 1