手写简易版Spring框架-1详解编程语言

前言

为了巩固学习Spring框架,我尝试通过手写spring,实现SpringMVC基本功能来学习Spring源码。

实现功能

这次先写了一个简易的框架,实现了最基本的IoC功能,以及springmvc中常用的注解,具体如下:

  • @Controller
  • @RequestMapping
  • @RequestParam
  • @Autowired
  • @Bean

代码

内嵌服务器

采用了apache的embed-core包在项目中内置了一个tomcat服务器,直接调用一个自己写的start()方法即可启动。本包在gradle中依赖如下:

// https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-corecompile 
group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.5.23' 

下面是TomcatServer类:

/** 
 * Created by makersy on 2019 
 */ 
 
public class TomcatServer {
    
 
    private Tomcat tomcat; 
    private String[] args; 
 
    public TomcatServer(String[] args) {
    
        this.args = args; 
    } 
 
    //启动类 
    public void startTomcat() throws LifecycleException {
    
        tomcat = new Tomcat(); 
        tomcat.setPort(6699); 
        tomcat.start(); 
        Context context = new StandardContext(); 
        context.setPath(""); 
        context.addLifecycleListener(new Tomcat.FixContextListener());  //默认监听器 
        DispatcherServlet servlet = new DispatcherServlet();  //前端控制器 
        Tomcat.addServlet(context, "dispatcherServlet", servlet).setAsyncSupported(true);  //支持异步的servlet 
        context.addServletMappingDecoded("/", "dispatcherServlet");  //为Servlet绑定映射,/表示可以处理所有uri 
        tomcat.getHost().addChild(context); 
 
        Thread awaitThread = new Thread("tomcat_await_thread"){
    
            @Override 
            public void run() {
    
                TomcatServer.this.tomcat.getServer().await();  //声明该线程一直在等待 
            } 
        }; 
        //设置为非守护线程 
        awaitThread.setDaemon(false); 
        //使该线程等待 
        awaitThread.start(); 
    } 
} 

DispatcherServlet(用来维护Servlet)

DispatcherServlet类进行servlet的维护,实现请求分发。

/** 
 * Created by makersy on 2019 
 */ 
 
public class DispatcherServlet implements Servlet {
    
 
    @Override 
    public void init(ServletConfig config) throws ServletException {
    
 
    } 
 
    @Override 
    public ServletConfig getServletConfig() {
    
        return null; 
    } 
 
    @Override 
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    
        for (MappingHandler mappingHandler : HandlerManager.mappingHandlerList) {
    
            try {
    
                if (mappingHandler.handle(req, res)) {
    
                    return; 
                } 
            } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
    
                e.printStackTrace(); 
            } 
        } 
    } 
 
    @Override 
    public String getServletInfo() {
    
        return null; 
    } 
 
    @Override 
    public void destroy() {
    
 
    } 
} 
 

MappingHandler

MappingHandler用来处理经过dispatcherservlet的请求uri,每个MappingHandler处理其匹配的uri请求。

/** 
 * Created by makersy on 2019 
 */ 
 
public class MappingHandler {
    
 
    private String uri; 
    private Method method; 
    private Class<?> controller; 
    private String[] args; 
 
    public boolean handle(ServletRequest request, ServletResponse response) throws IllegalAccessException, InstantiationException, InvocationTargetException, IOException {
    
        String requestUri = ((HttpServletRequest)request).getRequestURI(); 
        if (!uri.equals(requestUri)) {
    
            return false; 
        } 
 
        Object[] parameters = new Object[args.length]; 
        for (int i = 0; i < args.length; i++) {
    
            parameters[i] = request.getParameter(args[i]); 
        } 
 
        Object ctl = BeanFactory.getBean(controller); 
        Object res = method.invoke(ctl, parameters); 
        response.getWriter().println(res.toString()); 
        return true; 
    } 
    public MappingHandler(String uri, Method method, Class<?> controller, String[] args) {
    
        this.uri = uri; 
        this.method = method; 
        this.controller = controller; 
        this.args = args; 
    } 
} 
 

HandlerManager

HandlerManager负责处理controller注解,将其转换为handler。

/** 
 * Created by makersy on 2019 
 */ 
 
public class HandlerManager {
    
 
    public static List<MappingHandler> mappingHandlerList = new ArrayList<>(); 
 
    /** 
     * 将list中的controller转化为MappingHandler 
     * @param classList 类列表 
     */ 
    public static void resolveMappingHandler(List<Class<?>> classList) {
    
        for (Class<?> cls : classList) {
    
            if (cls.isAnnotationPresent(Controller.class)) {
    
                parseHandlerFromController(cls); 
            } 
        } 
    } 
 
    /** 
     * 将controller转化为handler 
     * @param cls 
     */ 
    private static void parseHandlerFromController(Class<?> cls) {
    
        Method[] methods = cls.getDeclaredMethods(); 
        for (Method method : methods) {
    
            //判断方法是否有RequestMapping注解 
            if (!method.isAnnotationPresent(RequestMapping.class)) {
    
                continue; 
            } 
            String uri = method.getDeclaredAnnotation(RequestMapping.class).value(); 
            List<String> paramNameList = new ArrayList<>(); 
            //获取method的带有RequestParam注解的参数,形成一个list 
            for (Parameter parameter : method.getParameters()) {
    
                if (parameter.isAnnotationPresent(RequestParam.class)) {
    
                    paramNameList.add(parameter.getDeclaredAnnotation(RequestParam.class).value()); 
                } 
            } 
            String[] params = paramNameList.toArray(new String[paramNameList.size()]); 
            MappingHandler mappingHandler = new MappingHandler(uri, method, cls, params); 
            HandlerManager.mappingHandlerList.add(mappingHandler); 
        } 
    } 
} 
 

ClassScanner

负责扫描一个jar包下面的所有类。用于初始化时获取所有类的列表,从而进行依赖注入,以及controller扫描。

/** 
 * Created by makersy on 2019 
 */ 
 
public class ClassScanner {
    
 
    /** 
     * 扫描一个包下面的所有类 
     * @param packageName 包名 
     * @return 
     * @throws IOException 
     * @throws ClassNotFoundException 
     */ 
    public static List<Class<?>> scanClass(String packageName) throws IOException, ClassNotFoundException {
    
        List<Class<?>> classList = new ArrayList<>(); 
        String path = packageName.replace(".", "/");  //将包名转化为路径名 
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();  //获取类加载器 
        Enumeration<URL> resources = classLoader.getResources(path); 
        while (resources.hasMoreElements()) {
    
            URL resource = resources.nextElement(); 
            if (resource.getProtocol().contains("jar")) {
     //如果资源类型是jar包 
                JarURLConnection jarURLConnection = (JarURLConnection) resource.openConnection(); 
                String jarFilePath = jarURLConnection.getJarFile().getName(); 
                classList.addAll(getClassesFromJar(jarFilePath, path)); 
            } else {
    
                //todo 
            } 
        } 
        return classList; 
    } 
 
    /** 
     * 获取一个jar包下所有类 
     * @param jarFilePath 
     * @param path 
     * @return 类的list 
     * @throws IOException 
     * @throws ClassNotFoundException 
     */ 
    private static List<Class<?>> getClassesFromJar(String jarFilePath, String path) throws IOException, ClassNotFoundException {
    
        List<Class<?>> classes = new ArrayList<>(); 
        JarFile jarFile = new JarFile(jarFilePath); 
        Enumeration<JarEntry> jarEntries = jarFile.entries(); 
        while (jarEntries.hasMoreElements()) {
    
            JarEntry jarEntry = jarEntries.nextElement(); 
            String entryName = jarEntry.getName(); 
            if (entryName.startsWith(path) && entryName.endsWith(".class")) {
    
                String classFullName = entryName.replace("/", ".").substring(0, entryName.length() - 6);  //类的全限定名 
                classes.add(Class.forName(classFullName)); 
            } 
        } 
        return classes; 
    } 
} 

Controller、RequestMapping和RequestParam注解

关于注解,可以参考我之前的文章:Java的注解

Controller

/** 
 * Created by makersy on 2019 
 */ 
 
@Documented 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.TYPE) 
public @interface Controller {
    
} 

RequestMapping

/** 
 * Created by makersy on 2019 
 */ 
 
@Documented 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface RequestMapping {
    
    String value(); 
} 

RequestParam

/** 
 * Created by makersy on 2019 
 */ 
 
@Documented 
@Retention(RetentionPolicy.RUNTIME)  //保存级别 
@Trget(ElementType.PARAMETER) 
public @interface RequestParam {
    
    String value(); 
} 

BeanFactory

这个是IoC的重点部分,所有的依赖都是由BeanFactory处理并注入的。

package top.makersy.beans; 
 
import top.makersy.web.mvc.Controller; 
 
import java.lang.reflect.Field; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Map; 
import java.util.concurrent.ConcurrentHashMap; 
 
/** 
 * Created by makersy on 2019 
 */ 
 
public class BeanFactory {
    
 
    //用一个类和实例的映射来模拟Bean工厂 
    private static Map<Class<?>, Object> classToBean = new ConcurrentHashMap<>(); 
 
    //从映射中获取Bean 
    public static Object getBean(Class<?> cls){
    
        return classToBean.get(cls); 
    } 
 
    /** 
     * Bean初始化,将表中所有类的依赖都加入 classToBean 这个映射中 
     * @param classList 包中所有类的集合 
     * @throws Exception 
     */ 
    public static void initBean(List<Class<?>> classList) throws Exception {
    
        List<Class<?>> toCreate = new ArrayList<>(classList);  //新建1个list来存放,以免改变了传入List的值 
        //一一初始化每一个类直到将类集合全部初始化完为止 
        while (toCreate.size() != 0) {
    
            int remainSize = toCreate.size(); 
            for (int i = 0; i < toCreate.size(); i++) {
    
                if (finishCreate(toCreate.get(i))) {
    
                    toCreate.remove(i); 
                } 
            } 
            // 当要创建的Bean列表长度始终不变时,说明出现了Bean之间相互依赖的问题。 
            // 因为我们采取的策略是当前Bean创建失败就去创建下一个,这样后面的创建完了有来重新创建前 
            // 面的依赖,如果这个阶段了list长度始终不变,那么说明Bean之间存在相互的依赖,A不创建B没 
            // 法创建,B不创建A也没法创建。 
            // 这里不进行处理,而是直接抛出异常 
            if (toCreate.size() == remainSize) {
    
                throw new Exception("cycle dependency!"); 
            } 
        } 
    } 
 
    private static boolean finishCreate(Class<?> cls) throws IllegalAccessException, InstantiationException {
    
        if (!cls.isAnnotationPresent(Bean.class) && !cls.isAnnotationPresent(Controller.class)) {
    
            return true; 
        } 
 
        Object bean = cls.newInstance(); 
        //获取所有字段,处理其中需要自动注入的 
        for (Field field : cls.getDeclaredFields()) {
    
            //处理 autowired 注解,自动注入 
            if (field.isAnnotationPresent(Autowired.class)) {
    
                Class<?> fieldType = field.getType(); 
                Object relianBean = BeanFactory.getBean(fieldType);  //从BeanFactory中获取依赖的Bean 
                //注意这里在BeanFactory中没有找到依赖的Bean时就返回false,放弃创建当前Bean,转而创建后面的。 
                if (relianBean == null) {
    
                    return false; 
                } 
                field.setAccessible(true);  //关闭安全检查 
                field.set(bean, relianBean);  //将bean的field值更新为relianBean,field值即需要注入的依赖 
            } 
        } 
        classToBean.put(cls, bean); 
        return true; 
    } 
} 

Autowired、Bean注解

Autowired

/** 
 * Created by makersy on 2019 
 */ 
 
@Documented 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD) 
public @interface Autowired {
    
} 

Bean

/** 
 * Created by makersy on 2019 
 */ 
 
@Documented 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.TYPE) 
public @interface Bean {
    
} 

最后

因为是刚开始,所以只实现了一些基础功能,ioc的循环依赖处理、aop都还没有实现,后面我会在此基础上进行完善。

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/19358.html

(0)
上一篇 2021年7月19日 22:08
下一篇 2021年7月19日 22:08

相关推荐

发表回复

登录后才能评论