实现SpringMVC底层机制(二)
文章目录
- 1. 动态获取spring配置文件
- 1.修改SunWebApplicationContext.java
- 2.修改SunDispatcherServlet.java
- 2.自定义Service注解
- 1.需求分析
- 2.编写Monster.java
- 3.自定义Service注解
- 4.编写Service接口MonsterService.java
- 5.编写Service实现类MonsterServiceImpl.java
- 6.修改SunWebApplicationContext.java的executeInstance方法,增加对Service注解的扫描
- 7.debug测试
- 3.完成自定义Autowired注解
- 1.自定义Autowired注解
- 2.在SunWebApplicationContext.java中添加方法executeAutoWired完成属性的自动装配
- 3.修改MonsterController.java来使用Autowired注解
- 4.单元测试
- 4.当前阶段完成的任务
- 自定义两个注解
- 目前对SpringMVC容器的简单理解
1. 动态获取spring配置文件
1.修改SunWebApplicationContext.java
2.修改SunDispatcherServlet.java
2.自定义Service注解
1.需求分析
2.编写Monster.java
package com.Sun.entity; /** * @author 孙显圣 * @version 1.0 */ 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 + '}'; } }
3.自定义Service注解
package com.Sun.sunspringmvc.annotation; import java.lang.annotation.*; /** * 自定义注解,用于标识一个service * * @author 孙显圣 * @version 1.0 */ @Target(ElementType.TYPE) //作用于目标是类 @Retention(RetentionPolicy.RUNTIME) //作用范围 @Documented public @interface Service { String value() default ""; }
4.编写Service接口MonsterService.java
package com.Sun.sunspringmvc.annotation; import java.lang.annotation.*; /** * 自定义注解,用于标识一个service * * @author 孙显圣 * @version 1.0 */ @Target(ElementType.TYPE) //作用于目标是类 @Retention(RetentionPolicy.RUNTIME) //作用范围 @Documented public @interface Service { }
5.编写Service实现类MonsterServiceImpl.java
package com.Sun.service.Impl; import com.Sun.entity.Monster; import com.Sun.service.MonsterService; import com.Sun.sunspringmvc.annotation.Service; import java.util.ArrayList; import java.util.List; /** * @author 孙显圣 * @version 1.0 */ @Service public class MonsterServiceImpl implements MonsterService { public List listMonsters() { ArrayList monsters = new ArrayList(); monsters.add(new Monster(1, "牛魔王", "芭蕉扇", 500)); monsters.add(new Monster(2, "蜘蛛精", "吐口水", 200)); return monsters; } }
6.修改SunWebApplicationContext.java的executeInstance方法,增加对Service注解的扫描
//编写方法,将符合要求的类反射创建对象,并封装到单例池中 public void executeInstance() { //遍历所有全类名 for (String classPath : classFullPathList) { try { //反射 Class aClass = Class.forName(classPath); //判断是否有Controller注解 if (aClass.isAnnotationPresent(Controller.class)) { //有注解,当他是单例的,反射创建bean对象,放到单例池中,默认首字母小写 //获取类名首字母小写 String name = aClass.getSimpleName().substring(0, 1).toLowerCase() + aClass.getSimpleName().substring(1); //放到单例池中 singleObjects.put(name, aClass.newInstance()); } else if (aClass.isAnnotationPresent(Service.class)) { //获取注解对象 Service annotation = aClass.getAnnotation(Service.class); //获取注解的value String value = annotation.value(); //为了使注入的都是同一个对象,所以在这里使用反射创建实例 Object bean = aClass.newInstance(); //如果注解的value是空的,则使用默认机制注入到单例池中 if ("".equals(value)) { //1.使用类名首字母小写来注入 String simpleName = aClass.getSimpleName(); String beanName = simpleName.substring(0,1).toLowerCase() + simpleName.substring(1); singleObjects.put(beanName, bean); //2.使用接口名首字母小写来注入 Class[] interfaces = aClass.getInterfaces(); //遍历所有接口类型,进行注入 for (Class anInterface : interfaces) { //获取接口的名称 String interfaceSimpleName = anInterface.getSimpleName(); //获取首字母小写 String beanName2 = interfaceSimpleName.substring(0,1).toLowerCase() + interfaceSimpleName.substring(1); //进行注入 singleObjects.put(beanName2, bean); } } else { //如果value不是空的,则按照value的值进行注入 singleObjects.put(value, bean); } } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } }
7.debug测试
3.完成自定义Autowired注解
1.自定义Autowired注解
package com.Sun.sunspringmvc.annotation; import java.lang.annotation.*; /** * @author 孙显圣 * @version 1.0 */ @Target(ElementType.FIELD) //作用目标是字段 @Retention(RetentionPolicy.RUNTIME) //作用范围 @Documented public @interface AutoWired { String value() default ""; }
2.在SunWebApplicationContext.java中添加方法executeAutoWired完成属性的自动装配
//编写方法,完成属性的自动装配 public void executeAutoWired() throws IllegalAccessException { //首先判断容器是否为空 if (singleObjects.isEmpty()) { return; } //遍历容器中的所有bean对象 for (Object beanObject : singleObjects.values()) { //得到Class对象 Class aClass = beanObject.getClass(); //得到所有字段 Field[] declaredFields = aClass.getDeclaredFields(); for (Field declaredField : declaredFields) { //判断这些字段是否有自动装配的注解 if (declaredField.isAnnotationPresent(AutoWired.class)) { //得到这个注解的value AutoWired annotation = declaredField.getAnnotation(AutoWired.class); String value = annotation.value(); Object findBeanObject = null; //用来存储从容器中查找到的值 //先判断这个注解的value有没有值 if ("".equals(value)) { //如果注解没有值则按照默认的方式处理,即按照类型的首字母小写来查找 String simpleName = declaredField.getType().getSimpleName(); String beanName = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1); //从容器中查找 findBeanObject = singleObjects.get(beanName); } else { //这个注解的value不是空的,则按照他的这个value在容器中查找 findBeanObject = singleObjects.get(value); } if (findBeanObject == null) { throw new RuntimeException("容器中不存在你要装配的bean"); } else { //进行依赖注入,需要指定给哪个对象的字段赋值 //反射爆破 declaredField.setAccessible(true); declaredField.set(beanObject, findBeanObject); } } } } }
3.修改MonsterController.java来使用Autowired注解
4.单元测试
4.当前阶段完成的任务
自定义两个注解
- 自定义Service注解:在原有的扫描所有文件全类名的基础上增加逻辑,判断是否具有Service注解,并根据value值或者默认方案将其注入到bean中
- 自定义Autowired注解
- 遍历所有单例池对象,获取对应的Class对象
- 获取每个对象的所有字段
- 对每个字段判断是否有Autowired注解,如果有则按照类型首字母小写或者value值来进行依赖注入
目前对SpringMVC容器的简单理解
- tomcat启动,加载中央控制器
- 获取spring配置文件路径,使用这个路径创建一个spring容器
- 调用spring容器的init方法,初始化spring容器
- 读取配置文件,得到要扫描的包,从而得到包的工作路径
- 根据工作路径来得到包内所哟class文件的全路径
- 遍历所有class文件的全路径,得到Class对象
- 使用反射扫描指定注解,反射创建bean对象,放到单例池中
- Autowired依赖注入
- 扫描单例池,得到所有对象,从而得到Class对象
- 使用反射得到所有字段信息,判断是否有Autowied注解,如果有则根据一定规则从单例池中查找bean对象进行依赖注入
- 初始化映射对象列表
- 扫描单例池,得到Class对象
- 通过反射判断是否有RequestMapping注解,如果有则使用反射获取url和Method对象,再加上当前的对象,封装到映射对象中
- 将这个映射对象添加到映射对象列表
- 请求分发
- 浏览器向中央控制器发送请求
- 中央控制器根据请求的uri和映射对象列表的url进行比对
- 如果匹配则反射调用Controller的方法
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。