继上篇miniTomcat(https://mp.csdn.net/editor/html/115064859) 后继续根据spring IOC(控制反转)和aop(切面)原理来实现自动注入和切面代理。
最终实现的效果,实现自动注入@controller @component @Aspect注解,并模拟mvc处理minitmcat 的请求
package com.hole.mvcController;
import com.hole.http.HttpServletRequest;
import com.hole.http.HttpServletResponse;
import com.hole.iocFactory.Controller;
import com.hole.iocFactory.RequestMapping;
import com.hole.iocFactory.RequestParam;
import com.hole.iocFactory.mvc.RequestMethod;
import com.hole.server.Processor;
import com.hole.servlet.HttpServlet;
@Controller
public class TestController implements Processor {
@RequestMapping(value = "/get", method = RequestMethod.GET)
public String testGet(@RequestParam(value = "testParam") String testParam){
return "test get OK";
}
@RequestMapping(value = "/post", method = RequestMethod.POST)
public String tesPost(@RequestParam(value = "testParam") String testParam){
return "test post OK";
}
@Override
public void process(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
}
}
处理结果
res:test get OK
IOC控制反转和AOP功能
扫描指定包或者文件,识别标示性注解,例如@controller @component 等,将class对象保存至Bean工厂,在注入相应属性@AtuoAnnotion,实现注入。
实际中会存在复杂的情况,例如循环依赖问题,spring采用的三级缓存保存处理(class工厂层(一级,以后做代理包装类的作用),实例化层(防止实例代理后产生变化)以及最终的实例(最终保存的实例))
只是实现简单功能,不用考虑复杂情况,直接用map保存实例,aop处理后再次更新实例。
package com.hole.iocFactory;
import com.hole.server.InterceptorImpHttp2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* @description: 注解类扫描
* @author: guozi
* @create: 2021-03-23
*/
public class ClassScanner {
public static final Logger logger = LoggerFactory.getLogger(ClassScanner.class);
// 线程上下文类加载器默认是应用类加载器,即 ClassLoader.getSystemClassLoader();
// 从线程获取的classLoader,防止不同环境下classloader不一致
private ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
/**
* 存放解析的class
*/
private List<Class<?>> classList = new ArrayList<>();
/**
* 限定pkg的类, /com/aws/controller
*/
private String path = "";
public ClassScanner(){
}
public ClassScanner(String path){
path = path;
}
/**
* @param pkgName 要扫描的包名位置
*/
public List<Class<?>> scanClass(String pkgName){
//处理路径
String path = pkgName.replace(".", "/");
try{
// 使用类加载器对象的 getResources(ResourceName) 方法获取资源集
// Enumeration 是古老的迭代器版本,可当成 Iterator 使用
//path = path + "/miniSpring.jar";
Enumeration<URL> resources = classLoader.getResources(path);
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
// 获取协议类型,判断是否为 jar 包
if (url.getProtocol().equals("jar")) {
dealJar(url);
} else if (url.getProtocol().equals("file")) {
//处理文件
//URL转换为file类型,File构造方法里有File(URI uri)
File file = new File(url.toURI());
dealFile(pkgName, file);
}
}
}catch (IOException | URISyntaxException e){
e.printStackTrace();
}
return classList;
}
/**
* 处理class 文件
*/
protected void dealClass(Class<?> clazz){
logger.info("扫描的class:{}, class属性:{}", clazz.getName(), clazz.getDeclaredFields());
}
/**
* 处理jar文件
*/
private void dealJar(URL url){
// 将打开的 url 返回的 URLConnection 转换成其子类 JarURLConnection 包连接
try{
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
Enumeration<JarEntry> jarEntries = jarFile.entries();
while(jarEntries.hasMoreElements()){
JarEntry jarEntry = jarEntries.nextElement();
//如果不是*.class则不处理
if(jarEntry.isDirectory() || !jarEntry.getName().endsWith(".class") ){
continue;
}
//判断是否限定了pkg,若不在pkg中,则跳过
if(path.length() != 0 && !jarEntry.getName().startsWith(path)){
continue;
}
//处理class,加载该类
String className = jarEntry.getName().substring(0, jarEntry.getName().lastIndexOf(".class"))
.replace("/", ".");
Class<?> clazz = Class.forName(className);
classList.add(clazz);
dealClass(clazz);
}
}catch (IOException | ClassNotFoundException e){
e.printStackTrace();
}
}
/**
* 处理file目录
*/
private void dealFile(String path, File file){
if(file.exists()){
File[] files = file.listFiles();
for(File childFile : files){
String fileName = childFile.getName();
if(childFile.isDirectory()){
dealFile(path + "." + childFile.getName(), childFile);
}else{
if(fileName.endsWith(".class")){
dealClass(childFile, path);
}
}
}
}
}
/**
* 处理class类文件
*/
private void dealClass(File file, String classPath){
try{
int index = file.getName().lastIndexOf(".class");
String classFullPath = classPath + "." +file.getName().substring(0, index);
Class<?> clazz = Class.forName(classFullPath);
classList.add(clazz);
dealClass(clazz);
}catch (ClassNotFoundException e){
e.printStackTrace();
}
}
public List<Class<?>> getClassList() {
return classList;
}
}
package com.hole.iocFactory;
import com.hole.exception.ClassNotBeInjectedException;
import com.hole.iocFactory.aspect.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description: bean工厂,实现注解自动注入
* @author: guozi
* @create: 2021-03-23
*/
public class BeanFactory {
/**
* bean管理map
*/
private static Map<Class<?>, Object> beans = new ConcurrentHashMap<>();
/**
* 带有 @AutoWired 注解修饰的属性的类
*/
private static Set<Class<?>> beansHasAutoWiredField = Collections.synchronizedSet(new HashSet<>());
public Object getBean(Class<?> clazz){
try{
if(beans.get(clazz) == null){
if(!clazz.isAnnotationPresent(Component.class) && !clazz.isAnnotationPresent(Controller.class)){
throw new ClassNotBeInjectedException("该类没有注解");
}
Object singleInstance = clazz.newInstance();
beans.put(clazz, singleInstance);
}
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
return beans.get(clazz);
}
/**
* 处理扫描的类(目前只处理Controller Component ),生成实例,并放入工厂,同时注入相应属性
*/
public void initBeans(List<Class<?>> classList){
//重新保存一份扫描类
List<Class<?>> classesToCreate = new ArrayList<>(classList);
//备注解的切面类
List<Class<?>> aspectClasses = new ArrayList<>();
//分开处理两中类
for(Class<?> clazz : classesToCreate){
if(clazz.isAnnotationPresent(Aspect.class)){
//处理切面类
aspectClasses.add(clazz);
}else{
//处理其他标注类
createBean(clazz);
}
}
//单独处理切面类
resolveAop(aspectClasses);
//重新更新Annotation引用的类
for(Class<?> clazz : beansHasAutoWiredField){
createBean(clazz);
}
}
/**
*为bean创建单实例,并注入相关属性
*/
private void createBean(Class<?> clazz){
try{
//暂时只处理 @Component / @Controller 注解的类
if(!clazz.isAnnotationPresent(Component.class) && !clazz.isAnnotationPresent(Controller.class)){
return;
}
//初始化对象
Object instance = null;
if(beans.get(clazz) == null){
instance = clazz.newInstance();
beans.put(clazz, instance);
}else{
instance = beans.get(clazz);
}
for(Field field : clazz.getDeclaredFields()){
if(!field.isAnnotationPresent(AutoWired.class)){
continue;
}
//保存bean,后续aop需要利用代理更新
beansHasAutoWiredField.add(clazz);
Class<?> fieldType = field.getType();
if(fieldType.isInterface()){
//若注入的是接口,则需要第一个实现类
for(Class<?> key:beans.keySet()){
if(fieldType.isAssignableFrom(key)){
fieldType = key;
break;
}
}
}
field.set(instance, getBean(fieldType));
}
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
private void resolveAop( List<Class<?>> aspectClazz){
if(aspectClazz.size() == 0){
return ;
}
try{
for(Class<?> clazz : aspectClazz){
Object target = null;
String method = null;
String pointcutName = null; //切点函数
Method before = null;
Method after = null;
//反射获取切点作用对象和切点作用方法
for(Method me : clazz.getMethods()){
if(me.isAnnotationPresent(Pointcut.class)){
String pointcut = me.getAnnotation(Pointcut.class).value();
String classStr = pointcut.substring(0, pointcut.lastIndexOf("."));
target = Thread.currentThread().getContextClassLoader().loadClass(classStr).newInstance();
method = pointcut.substring(pointcut.lastIndexOf(".") + 1);
pointcutName = me.getName();
}
}
//反射获取切面函数
for(Method me : clazz.getMethods()){
if(me.isAnnotationPresent(Before.class)){
String value = me.getAnnotation(Before.class).value();
value = value.substring(0, value.indexOf("("));
if (value.equals(pointcutName)) {
before = me;
}
}else if(me.isAnnotationPresent(After.class)){
String value = me.getAnnotation(After.class).value();
value = value.substring(0, value.indexOf("("));
if (value.equals(pointcutName)) {
after = me;
}
}
}
//重新代理对象
AspectProxy aspectProxy = new AspectProxy(before, after, target, method, clazz.newInstance());
BeanFactory.beans.put(target.getClass(), aspectProxy.createProxy());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Map<Class<?>, Object> getBeans(){
return beans;
}
}
mvc功能
mvc主要是处理minitomcat 请求,根据url params method 来确定请求的Controller,实际mvc请求根据不同注解有个排序方式,选择最符合的controller method来处理请求
这里简单处理,以url为请求map的key值,来检查请求和请求处理方法的映射
package com.hole.iocFactory.mvc;
import com.hole.iocFactory.Controller;
import com.hole.iocFactory.RequestMapping;
import com.hole.iocFactory.RequestParam;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @description: 管理controller params get/post 路径 -> hash -> map 方法
* @author: guozi
* @create: 2021-03-23
*/
public class HandlerManager {
/**
* 单独管理controller注解,简单处理,以请求路径的hash值为key值
*/
public static Map<String, RequestHandler> handlerMap = new HashMap<>();
public static void resolveHandler( Map<Class<?>, Object> beans){
beans.keySet().stream().filter(clazz -> clazz.isAnnotationPresent(Controller.class))
.forEach(HandlerManager::parseHandlerFromController);
}
private static void parseHandlerFromController(Class<?> clazz){
//解析带有request的method
Arrays.stream(clazz.getDeclaredMethods()).filter(method -> method.isAnnotationPresent(RequestMapping.class))
.forEach(method -> {
String url = method.getAnnotation(RequestMapping.class).value();
RequestMethod[] requestMethod = method.getAnnotation(RequestMapping.class).method();
String[] params = Arrays.stream(method.getParameters())
.filter(parameter -> parameter.isAnnotationPresent(RequestParam.class))
.map(parameter -> parameter.getAnnotation(RequestParam.class).value())
.toArray(String[]::new);
handlerMap.put(url, new RequestHandler(clazz, url,method, params, requestMethod[0]));
});
}
}
package com.hole.iocFactory.mvc;
import com.hole.http.HttpServletRequest;
import com.hole.http.HttpServletResponse;
import com.hole.iocFactory.BeanFactory;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @description: 请求处理类
* @author: guozi
* @create: 2021-03-23
*/
public class RequestHandler implements IRequestHandler{
/**
* controller对象
*/
private Class<?> controller;
/**
* 请求路径
*/
private String url;
/**
* 处理方法
*/
private Method method;
/**
* 方法参数
*/
private String[] params;
/**
* 请求方式
*/
private RequestMethod requestMethod;
RequestHandler(Class<?> target, String url, Method method, String[] params, RequestMethod requestMethod){
this.controller = target;
this.url = url;
this.method = method;
this.params = params;
this.requestMethod = requestMethod;
}
/**
* 实际处理该请求
*/
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
try{
//获取url
String url = httpServletRequest.getRequestUrlNoParam();
//根据请求url获取对应的request枚举类
RequestMethod urlRequestMethod = RequestMethod.getEnumMap(httpServletRequest.getMethod());
if(urlRequestMethod == null){
urlRequestMethod = RequestMethod.GET;
}
//获取参数
Object[] urlParameters = new Object[params.length];
for(int i = 0; i < params.length; i++){
//从请求中获取键值,传给controller函数
urlParameters[i] = httpServletRequest.getParameters(params[i]);
}
Object response = method.invoke(BeanFactory.getBeans().get(controller), urlParameters);
//输入html内容
PrintWriter printWriter = httpServletResponse.getWriter();
printWriter.print("HTTP/1.1 200 OK\r\n\r\n");
printWriter.print("res:" + response.toString());
// printWriter.print("<html>");
// printWriter.print("<body>");
// printWriter.print("<p>");
// printWriter.print("</p>");
// printWriter.print("</body>");
// printWriter.print("</html>");
printWriter.flush();
printWriter.close();
}catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
minitomcat请求分发过程
package com.hole.server;
import com.hole.http.HttpServletRequest;
import com.hole.http.HttpServletResponse;
import com.hole.iocFactory.mvc.HandlerManager;
import com.hole.iocFactory.mvc.IRequestHandler;
import com.hole.iocFactory.mvc.RequestHandler;
import com.hole.servlet.ServletContext;
import com.hole.util.InterceptorProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* @describtion: 客户端连接信息处理服务
* @author: guozi
* @create: 2021-01-25
*/
public class ServerService implements Runnable{
/**
* 连接客户端信息
*/
private Socket client;
public static final Logger logger = LoggerFactory.getLogger(ServerService.class);
public ServerService(Socket socket){
super();
this.client = socket;
}
@Override
public void run() {
InputStream input = null;
OutputStream output = null;
try{
input = this.client.getInputStream();
output = this.client.getOutputStream();
}catch (Exception e){
logger.error("客户端{}连接断开,原因:{}", this.client.getRemoteSocketAddress(), e.getMessage());
return;
}
//采用的是http协议,基于连接信息,创建http请求和响应对象
HttpServletRequest httpServletRequest = new HttpServletRequest(input);
HttpServletResponse httpServletResponse = new HttpServletResponse(httpServletRequest, output);
//判断是否是动态还是静态请求,动态请求包括.action->要给到的处理类
String url = httpServletRequest.getRequestUrlNoParam();
//servlet处理 , 链式步骤处理过来的请求
IRequestHandler interceptorProxy = null;
//判断是否有对应url 有的处理请求
if(HandlerManager.handlerMap.get(url) != null){
//servlet处理 , 链式步骤处理过来的请求
interceptorProxy = HandlerManager.handlerMap.get(url);
for(String interceptor : ServletContext.interceptorContext.values()){
interceptorProxy = (IRequestHandler) InterceptorProxy.bind(interceptorProxy,interceptor);
}
//判断是否存在责任链,是的话启用
if(interceptorProxy != null){
interceptorProxy.handle(httpServletRequest, httpServletResponse);
}else{
HandlerManager.handlerMap.get(url).handle(httpServletRequest, httpServletResponse);
}
}else{
Processor processor = new StaticProcessor();
processor.process(httpServletRequest, httpServletResponse);
//httpServletResponse.getWriter().println("no controller to handle");
}
// //责任链默认
// if(url.contains(".action")){
// processor = new DynamicProcessor();
// }else{
// processor = new StaticProcessor();
// }
// //servlet处理 , 链式步骤处理过来的请求
// Processor interceptorProxy = processor;
// for(String interceptor : ServletContext.interceptorContext.values()){
// interceptorProxy = (Processor) InterceptorProxy.bind(interceptorProxy,interceptor);
// }
// interceptorProxy.process(httpServletRequest, httpServletResponse);
try{
//http是短连接,需要及时关闭
this.client.close();
}catch (Exception e){
logger.error("客户端{}连接断开失败,原因:{}", this.client.getRemoteSocketAddress(), e.getMessage());
}
}
}