IOC容器对象及DispatcherServlet的编写
编写SpringMVC核心代码
前端控制器:DispatcherServlet
前端控制器主要是捕获来自浏览器、前端的请求,在服务器启动之前初始化spring容器中的组件。自定义DispatcherServlet类继承HttpServlet
public class DispatcherServlet extends HttpServlet {
// Spring ioc容器对象
private WebApplicationContext webApplicationContext;
// 存储URI和对象的方法映射关系
private List<HandlerMapping> handlerMappings = new ArrayList<>();
/**
* 加载DispatcherServlet类的初始方法
*/
@Override
public void init(ServletConfig config) {
// classpath: springmvc.xml 读取初始化的参数
String contextConfigLocation = config.getInitParameter("contextConfigLocation");
// 1.创建spring容器
webApplicationContext = new WebApplicationContext(contextConfigLocation);
// 2.初始化spring容器
webApplicationContext.refresh();
// 3.初始化请求映射 /user/query ----> Controller ----> method ----> parameters
initHandlerMappings();
System.out.println("请求地址和控制器方法的映射关系:" + handlerMappings);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
}
/**
* 初始化请求映射
*/
private void initHandlerMappings() {
// 判断容器中是否有bean对象
if(webApplicationContext.iocMap.isEmpty()) {
throw new ContextException("Spring容器为空");
}
for (Map.Entry<String, Object> entry: webApplicationContext.iocMap.entrySet()) {
Class<?> clazz = entry.getValue().getClass();
Object ctl = entry.getValue(); // 当前的对象
// 判断clazz是否有@Controller注解
if(clazz.isAnnotationPresent(Controller.class)) {
// 处理有@Controller注解的类(下面讲解)
parseHandlerFromController(clazz, ctl);
}
}
}
}
Spring容器对象:WebApplicationContext
创建WebApplicationContext类(Spring容器对象)
public class WebApplicationContext {
// 配置文件名
private String contextConfigLocation;
// 扫描指定包的类名列表
private List<String> classNames = new ArrayList<>();
// Spring的IOC容器
public Map<String, Object> iocMap = new ConcurrentHashMap<>();
public WebApplicationContext(String contextConfigLocation) {
this.contextConfigLocation = contextConfigLocation;
}
/**
* 容器初始化
*/
public void refresh(){
// 扫描配置文件扫描的包
String basePackage = XmlParser.getBasePackage(contextConfigLocation.split(":")[1]);
assert basePackage != null;
// 以','来分割出各个包名
String[] basePackages = basePackage.split(",");
// 判断存在
if(basePackages.length > 0) {
for(String pack: basePackages) {
// com.example.controller
// com.example.service
try {
// 执行包扫描的方法,将每个包以参数放进去,去除首尾空格
executeScanPackage(pack.trim());
// 实例化对象
executeInstance();
// 实例化Spring容器中bean对象
executeAutowired();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("扫描的包:" + classNames);
System.out.println("ioc容器中的对象:" + iocMap);
}
}
/**
*
* @param pack 扫描包
*/
public void executeScanPackage(String pack) {
// 获取当前包的类路径,用/去替换掉.
URL url = this.getClass().getClassLoader().getResource("/" + pack.replaceAll("\\.", "/"));
// 路径:/com/example/controller
assert url != null;
// 获取文件路径
String path = url.getFile();
// new File()
File dir = new File(path);
// for循环去递归,扫描当前路径下的文件\文件夹
for(File f: Objects.requireNonNull(dir.listFiles())) {
if(f.isDirectory()) {
// 文件夹(再去指定executeScanPackage方法)
executeScanPackage(pack+"."+f.getName());
} else {
// 文件 获取className然后加入到容器的classNames列表中
String className = pack+"."+f.getName().replaceAll(".class", "");
classNames.add(className);
}
}
}
/**
* 实例化bean对象
*/
public void executeInstance() {
// 判断容器中的classNames是否为空
if(classNames.size() == 0) {
// 没有要实例化的对象 抛出自定义异常
throw new ContextException("没有要实例化的class");
}
for (String className : classNames) {
try {
// 通过反射获取当前类
Class<?> clazz = Class.forName(className);
// 判断当前类是否是Controller类(加@Controller注解)
if(clazz.isAnnotationPresent(Controller.class)) {
// 控制层的类 com.springmvc.controller.UserController
// userController 控制层对象的名字
// System.out.println(clazz.getSimpleName()) 处理成首字母小写;
String beanName = clazz.getSimpleName().substring(0, 1).toLowerCase() + clazz.getSimpleName().substring(1);
// 将beanName放入iocMap中
// key(beanName) -> value((Object)beanName通过反射获取到对象类)
iocMap.put(beanName, clazz.newInstance());
// 如上: 判断当前类是否是Service类(加@Service注解)
} else if(clazz.isAnnotationPresent(Service.class)) {
// com.springmvc.controller.UserServiceImpl
// 获取Service(value="")的value值
Service serviceAnnotation = clazz.getAnnotation(Service.class);
String beanName = serviceAnnotation.value();
// 判断Service(value="")的value是否为空
if("".equals(beanName)) {
// 取当前Service类的接口
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> c1 : interfaces) {
beanName = c1.getSimpleName().substring(0, 1).toLowerCase() + c1.getSimpleName().substring(1);
iocMap.put(beanName, clazz.newInstance());
}
} else {
// 在Service(value="us") beanName = us
iocMap.put(beanName, clazz.newInstance());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 实现spring容器中bean的注入(自动装配)
*/
private void executeAutowired() throws IllegalAccessException {
// 判断iocMap中是否为空
if(iocMap.isEmpty()) {
// 为空则抛出异常
throw new ContextException("没有找到初始化bean对象");
}
// 遍历iocMap
for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
String key = entry.getKey(); // beanName
Object bean = entry.getValue(); // bean
// 获取到当前对象里面定义的Field
Field[] declaredFields = bean.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
// 如果字段有Autowired的注解
if(declaredField.isAnnotationPresent(Autowired.class)) {
// 先判断是否有value
Autowired autowired = declaredField.getAnnotation(Autowired.class);
String beanName = autowired.value();
// 如果value为空
if("".equals(beanName)) {
Class<?> type = declaredField.getType();
// 获取当前字段首字母小写(等价于获取iocMap中的key)
beanName = type.getSimpleName().substring(0, 1).toLowerCase() + type.getSimpleName().substring(1);
}
// 强制访问类的属性
declaredField.setAccessible(true);
// 属性注入 调用反射给属性注入值
declaredField.set(bean, iocMap.get(beanName));
}
}
}
}
}
自定义:ContextException
// 继承RuntimeException类重写getMessage方法
public class ContextException extends RuntimeException {
public ContextException(String message) {
super(message);
}
public ContextException(Throwable cause) {
super(cause);
}
@Override
public String getMessage() {
return super.getMessage();
}
}
处理@Controller类:parseHandlerFromController
/**
* 通过控制器类解析请求映射
* @param clazz Class
*/
private void parseHandlerFromController(Class<?> clazz, Object ctl) {
String uriPrefix = "";
// 去判断Controller类是否有RequestMapping注解
if(clazz.isAnnotationPresent(RequestMapping.class)){
// 获取RequestMapping中的value值
uriPrefix = clazz.getDeclaredAnnotation(RequestMapping.class).value();
}
// 获取当前类定义的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
// 判断是否有@ResponseBody注解(默认:false)
boolean isResponseBody = false;
if(declaredMethod.isAnnotationPresent(ResponseBody.class)) {
// 有@ResponseBody注解:true
isResponseBody = true;
}
// 判断方法上是否有@RequestMapping注解
if(declaredMethod.isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestMapping = declaredMethod.getAnnotation(RequestMapping.class);
// 获取RequestMapping的value
String URI = uriPrefix + requestMapping.value();
// 解析方法上的请求参数
List<String> paramNameList = new ArrayList<>();
// 遍历方法上的参数
for(Parameter parameter: declaredMethod.getParameters()) {
// 判断是否有@RequestParam注解
if(parameter.isAnnotationPresent(RequestParam.class)) {
// 控制当前方法形参是否为必须的 后期还需优化required = false的时候
if(parameter.getDeclaredAnnotation(RequestParam.class).required()) {
// 解析@RequestParam的value
paramNameList.add(parameter.getDeclaredAnnotation(RequestParam.class).value());
} else {
paramNameList.add(parameter.getName());
}
} else {
if("HttpServletRequest".equals(parameter.getType().getSimpleName())){
// 处理方法参数是有HttpServletRequest
paramNameList.add("HttpServletRequest");
} else if("HttpServletResponse".equals(parameter.getType().getSimpleName())){
// 处理方法参数是有HttpServletResponse
paramNameList.add("HttpServletResponse");
} else {
paramNameList.add(parameter.getName());
}
}
}
int size = paramNameList.size();
String[] params = paramNameList.toArray(new String[size]);
// new HandlerMapping() 然后添加在handlerMappings中
HandlerMapping handlerMapping = new HandlerMapping(URI, ctl, declaredMethod, params, isResponseBody);
handlerMappings.add(handlerMapping);
}
}
}
处理应映射器对象:HandlerMapping
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HandlerMapping {
private String uri; // 请求的URI
private Object controller; // 对应的控制器
private Method method; // 对应控制器执行的方法
private String[] args; // 方法上的参数
private boolean isResponseBody; // 方法是否加了@ResponseBody注解
}