{"id":23897484,"url":"https://github.com/halfmoonly/handson-spring","last_synced_at":"2025-04-10T17:05:05.809Z","repository":{"id":216437497,"uuid":"741293197","full_name":"Halfmoonly/handson-spring","owner":"Halfmoonly","description":"理解技术最好的方式是造轮子。handson-spring采用多分支开发，每个分支都是可运行的程度，并融合了大量优雅的设计模式，帮助初学者捅破窗户纸，突破技术瓶颈，俯瞰框架原理","archived":false,"fork":false,"pushed_at":"2025-02-12T11:35:12.000Z","size":386,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T14:46:06.518Z","etag":null,"topics":["servlet","spring","springmvc","tomcat"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Halfmoonly.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-01-10T05:03:00.000Z","updated_at":"2025-02-12T11:35:15.000Z","dependencies_parsed_at":"2025-04-10T17:02:18.053Z","dependency_job_id":null,"html_url":"https://github.com/Halfmoonly/handson-spring","commit_stats":null,"previous_names":["lyflexi/handson_miniframework","halfmoonly/minispringframework","halfmoonly/handson-spring"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Halfmoonly%2Fhandson-spring","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Halfmoonly%2Fhandson-spring/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Halfmoonly%2Fhandson-spring/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Halfmoonly%2Fhandson-spring/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Halfmoonly","download_url":"https://codeload.github.com/Halfmoonly/handson-spring/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248260164,"owners_count":21074207,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["servlet","spring","springmvc","tomcat"],"created_at":"2025-01-04T17:16:10.161Z","updated_at":"2025-04-10T17:05:05.798Z","avatar_url":"https://github.com/Halfmoonly.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# handson-spring\n为什么要创建该项目？\n\n虽然 Spring 是开源的，但是面对如此庞大且复杂的源代码，总会让初学者显得束手无措。\n\nSpring 是 Java 开发事实上的平台。深入理解 Spring 基础框架的底层原理很有必要，它能让我们以不变应万变，把握住技术快速流变中相对稳定的内核。\n\n业界总是说“不要重新造轮子”，话虽不错，不过那是对商业机构说的，对我们来说，只有自己动手重新造轮子才能真正地理解知识。\n\n本项目采用多分支开发，从一个最简单的程序开始，一步步堆积演化，每写一小段代码，都是一个可运行的程度。我希望你能够抵达山顶，一览众山小。帮作者点点⭐⭐，谢谢支持\n\n\n## 开发环境\n- javax.servlet-api\n- tomcat10-\n- Idea\n- jdk8\n  \n说明：Tomcat 10是第一个不再使用javax.servlet和相关包的版本，MiniSpringFramework没有对Tomcat 10做适配。\n\u003e 在Tomcat 10+中，Servlet API已经迁移到了Jakarta EE命名空间（jakarta.servlet）。这是因为Java EE已经转移到了Eclipse基金会，并更名为Jakarta EE。因此，Servlet API也需要进行相应的更改\n\n## 环境配置\n以main分支为例\n\nhttp://tomcat.apache.org/ ，下载apache-tomcat-9.0.6并解压\n\n![img.png](img.png)\n\n启动入口编辑edit configuration\n\n![img_1.png](img_1.png)\n\n关键配置，deployment指定war包和tomcat请求上下文\n\n![img_2.png](img_2.png)\n\n启动！\n```shell\nC:\\Users\\hasee\\apache-tomcat-9.0.6\\bin\\catalina.bat run\n[2025-01-03 09:44:05,471] Artifact handson-spring:war: Waiting for server connection to start artifact deployment…\nUsing CATALINA_BASE:   \"C:\\Users\\hasee\\AppData\\Local\\JetBrains\\IntelliJIdea2024.3\\tomcat\\fffd6e1b-2d2b-458c-9129-d313d43d12ab\"\nUsing CATALINA_HOME:   \"C:\\Users\\hasee\\apache-tomcat-9.0.6\"\nUsing CATALINA_TMPDIR: \"C:\\Users\\hasee\\apache-tomcat-9.0.6\\temp\"\nUsing JRE_HOME:        \"C:\\Users\\hasee\\.jdks\\corretto-1.8.0_392\"\nUsing CLASSPATH:       \"C:\\Users\\hasee\\apache-tomcat-9.0.6\\bin\\bootstrap.jar;C:\\Users\\hasee\\apache-tomcat-9.0.6\\bin\\tomcat-juli.jar\"\n03-Jan-2025 21:44:07.237 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Server version:        Apache Tomcat/9.0.6\n03-Jan-2025 21:44:07.241 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Mar 5 2018 09:34:35 UTC\n03-Jan-2025 21:44:07.241 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Server number:         9.0.6.0\n03-Jan-2025 21:44:07.241 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Windows 10\n03-Jan-2025 21:44:07.242 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            10.0\n03-Jan-2025 21:44:07.242 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64\n03-Jan-2025 21:44:07.242 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             C:\\Users\\hasee\\.jdks\\corretto-1.8.0_392\\jre\n03-Jan-2025 21:44:07.242 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version:           1.8.0_392-b08\n03-Jan-2025 21:44:07.242 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor:            Amazon.com Inc.\n03-Jan-2025 21:44:07.242 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:         C:\\Users\\hasee\\AppData\\Local\\JetBrains\\IntelliJIdea2024.3\\tomcat\\fffd6e1b-2d2b-458c-9129-d313d43d12ab\n03-Jan-2025 21:44:07.242 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:         C:\\Users\\hasee\\apache-tomcat-9.0.6\n03-Jan-2025 21:44:07.243 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=C:\\Users\\hasee\\AppData\\Local\\JetBrains\\IntelliJIdea2024.3\\tomcat\\fffd6e1b-2d2b-458c-9129-d313d43d12ab\\conf\\logging.properties\n03-Jan-2025 21:44:07.243 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager\n03-Jan-2025 21:44:07.243 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcom.sun.management.jmxremote=\n03-Jan-2025 21:44:07.243 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcom.sun.management.jmxremote.port=1099\n03-Jan-2025 21:44:07.243 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcom.sun.management.jmxremote.ssl=false\n03-Jan-2025 21:44:07.243 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcom.sun.management.jmxremote.password.file=C:\\Users\\hasee\\AppData\\Local\\JetBrains\\IntelliJIdea2024.3\\tomcat\\fffd6e1b-2d2b-458c-9129-d313d43d12ab\\jmxremote.password\n03-Jan-2025 21:44:07.243 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcom.sun.management.jmxremote.access.file=C:\\Users\\hasee\\AppData\\Local\\JetBrains\\IntelliJIdea2024.3\\tomcat\\fffd6e1b-2d2b-458c-9129-d313d43d12ab\\jmxremote.access\n03-Jan-2025 21:44:07.244 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.rmi.server.hostname=127.0.0.1\n03-Jan-2025 21:44:07.244 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048\n03-Jan-2025 21:44:07.244 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources\n03-Jan-2025 21:44:07.244 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dignore.endorsed.dirs=\n03-Jan-2025 21:44:07.244 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=C:\\Users\\hasee\\AppData\\Local\\JetBrains\\IntelliJIdea2024.3\\tomcat\\fffd6e1b-2d2b-458c-9129-d313d43d12ab\n03-Jan-2025 21:44:07.244 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=C:\\Users\\hasee\\apache-tomcat-9.0.6\n03-Jan-2025 21:44:07.244 ��Ϣ [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=C:\\Users\\hasee\\apache-tomcat-9.0.6\\temp\n03-Jan-2025 21:44:07.245 ��Ϣ [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded APR based Apache Tomcat Native library [2.0.3] using APR version [1.7.2].\n03-Jan-2025 21:44:07.245 ��Ϣ [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].\n03-Jan-2025 21:44:07.245 ��Ϣ [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]\n03-Jan-2025 21:44:07.253 ��Ϣ [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.8 7 Feb 2023]\n03-Jan-2025 21:44:07.352 ��Ϣ [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler [\"http-nio-8080\"]\n03-Jan-2025 21:44:07.369 ��Ϣ [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read\n03-Jan-2025 21:44:07.377 ��Ϣ [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler [\"ajp-nio-8009\"]\n03-Jan-2025 21:44:07.382 ��Ϣ [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read\n03-Jan-2025 21:44:07.382 ��Ϣ [main] org.apache.catalina.startup.Catalina.load Initialization processed in 577 ms\n03-Jan-2025 21:44:07.427 ��Ϣ [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]\n03-Jan-2025 21:44:07.427 ��Ϣ [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/9.0.6\n03-Jan-2025 21:44:07.441 ��Ϣ [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [\"http-nio-8080\"]\n03-Jan-2025 21:44:07.457 ��Ϣ [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [\"ajp-nio-8009\"]\n03-Jan-2025 21:44:07.460 ��Ϣ [main] org.apache.catalina.startup.Catalina.start Server startup in 77 ms\nConnected to server\n[2025-01-03 09:44:07,557] Artifact handson-spring:war: Artifact is being deployed, please wait…\n03-Jan-2025 21:44:08.633 ��Ϣ [RMI TCP Connection(2)-127.0.0.1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.\n.........MyBeanFactoryPostProcessor...........\ntry to registerBeanPostProcessors\n registerBeanPostProcessors : com.minis.scheduling.annotation.AsyncAnnotationBeanPostProcessor\nget bean null -------------- asyncAnnotationBeanPostProcessor\nasyncAnnotationBeanPostProcessor bean created. com.minis.scheduling.annotation.AsyncAnnotationBeanPostProcessor : com.minis.scheduling.annotation.AsyncAnnotationBeanPostProcessor@26a88d9\nhandle properties for bean : asyncAnnotationBeanPostProcessor\n bean registerded............. asyncAnnotationBeanPostProcessor\n class proxy after bean post processor class com.minis.scheduling.annotation.AsyncAnnotationBeanPostProcessor\n bean registerded............. asyncAnnotationBeanPostProcessor\nnormal bean -------------- asyncAnnotationBeanPostProcessor----------------com.minis.scheduling.annotation.AsyncAnnotationBeanPostProcessor@26a88d9\n registerBeanPostProcessors : com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor\nget bean null -------------- autowiredAnnotationBeanPostProcessor\nautowiredAnnotationBeanPostProcessor bean created. com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor : com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@2eb36cae\nhandle properties for bean : autowiredAnnotationBeanPostProcessor\n bean registerded............. autowiredAnnotationBeanPostProcessor\n class proxy after bean post processor class com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor\n bean registerded............. autowiredAnnotationBeanPostProcessor\nnormal bean -------------- autowiredAnnotationBeanPostProcessor----------------com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@2eb36cae\n registerBeanPostProcessors : com.test.LogBeanPostProcessor\nget bean null -------------- logBeanPostProcessor\nlogBeanPostProcessor bean created. com.test.LogBeanPostProcessor : com.test.LogBeanPostProcessor@2be12115\nhandle properties for bean : logBeanPostProcessor\n bean registerded............. logBeanPostProcessor\n class proxy after bean post processor class com.test.LogBeanPostProcessor\n bean registerded............. logBeanPostProcessor\nnormal bean -------------- logBeanPostProcessor----------------com.test.LogBeanPostProcessor@2be12115\n registerBeanPostProcessors : com.minis.aop.framework.autoproxy.BeanNameAutoProxyCreator\nget bean null -------------- autoProxyCreator\nautoProxyCreator bean created. com.minis.aop.framework.autoproxy.BeanNameAutoProxyCreator : com.minis.aop.framework.autoproxy.BeanNameAutoProxyCreator@48f89de1\nhandle properties for bean : autoProxyCreator\n bean registerded............. autoProxyCreator\npostProcessBeforeInitialization : autoProxyCreator\n class proxy after bean post processor class com.minis.aop.framework.autoproxy.BeanNameAutoProxyCreator\npostProcessAfterInitialization : autoProxyCreator\n bean registerded............. autoProxyCreator\nnormal bean -------------- autoProxyCreator----------------com.minis.aop.framework.autoproxy.BeanNameAutoProxyCreator@48f89de1\nget bean null -------------- bbs\nbbs bean created. com.test.service.BaseBaseService : com.test.service.BaseBaseService@55636380\nhandle properties for bean : bbs\nget bean null -------------- aservice\naservice bean created. com.test.service.AServiceImpl : com.test.service.AServiceImpl@7218ed14\nhandle properties for bean : aservice\nget bean null -------------- baseservice\nbaseservice bean created. com.test.service.BaseService : com.test.service.BaseService@49f37c5f\nhandle properties for bean : baseservice\n bean registerded............. baseservice\nnormal bean -------------- bbs----------------com.test.service.BaseBaseService@55636380\nautowire bbs for bean baseservice\nautowire bbs for bean baseservice : com.test.service.BaseBaseService@55636380 class : class com.test.service.BaseBaseService\npostProcessBeforeInitialization : baseservice\n try to create proxy for : baseservice\n match?baseservice:action*\n class proxy after bean post processor class com.test.service.BaseService\npostProcessAfterInitialization : baseservice\n bean registerded............. baseservice\nnormal bean -------------- baseservice----------------com.test.service.BaseService@49f37c5f\n bean registerded............. aservice\npostProcessBeforeInitialization : aservice\n try to create proxy for : aservice\n match?aservice:action*\n class proxy after bean post processor class com.test.service.AServiceImpl\npostProcessAfterInitialization : aservice\n bean registerded............. aservice\nnormal bean -------------- aservice----------------com.test.service.AServiceImpl@7218ed14\n bean registerded............. bbs\npostProcessBeforeInitialization : bbs\n try to create proxy for : bbs\n match?bbs:action*\n class proxy after bean post processor class com.test.service.BaseBaseService\n..........call init-mothod..........\npostProcessAfterInitialization : bbs\n bean registerded............. bbs\nnormal bean -------------- bbs----------------com.test.service.BaseBaseService@55636380\nbean exist -------------- aservice----------------com.test.service.AServiceImpl@7218ed14\nnormal bean -------------- aservice----------------com.test.service.AServiceImpl@7218ed14\nbean exist -------------- baseservice----------------com.test.service.BaseService@49f37c5f\nnormal bean -------------- baseservice----------------com.test.service.BaseService@49f37c5f\nget bean null -------------- userService\nuserService bean created. com.test.service.UserService : com.test.service.UserService@11314941\nhandle properties for bean : userService\n bean registerded............. userService\nget bean null -------------- jdbcTemplate\njdbcTemplate bean created. com.minis.jdbc.core.JdbcTemplate : com.minis.jdbc.core.JdbcTemplate@b6c3afb\nhandle properties for bean : jdbcTemplate\nget bean null -------------- dataSource\ndataSource bean created. com.minis.jdbc.pool.PooledDataSource : com.minis.jdbc.pool.PooledDataSource@576ba6cf\nhandle properties for bean : dataSource\n bean registerded............. dataSource\npostProcessBeforeInitialization : dataSource\n try to create proxy for : dataSource\n match?dataSource:action*\n class proxy after bean post processor class com.minis.jdbc.pool.PooledDataSource\npostProcessAfterInitialization : dataSource\n bean registerded............. dataSource\nnormal bean -------------- dataSource----------------com.minis.jdbc.pool.PooledDataSource@576ba6cf\n bean registerded............. jdbcTemplate\npostProcessBeforeInitialization : jdbcTemplate\n try to create proxy for : jdbcTemplate\n match?jdbcTemplate:action*\n class proxy after bean post processor class com.minis.jdbc.core.JdbcTemplate\npostProcessAfterInitialization : jdbcTemplate\n bean registerded............. jdbcTemplate\nnormal bean -------------- jdbcTemplate----------------com.minis.jdbc.core.JdbcTemplate@b6c3afb\nautowire jdbcTemplate for bean userService\nautowire jdbcTemplate for bean userService : com.minis.jdbc.core.JdbcTemplate@b6c3afb class : class com.minis.jdbc.core.JdbcTemplate\npostProcessBeforeInitialization : userService\n try to create proxy for : userService\n match?userService:action*\n class proxy after bean post processor class com.test.service.UserService\npostProcessAfterInitialization : userService\n bean registerded............. userService\nnormal bean -------------- userService----------------com.test.service.UserService@11314941\nget bean null -------------- taskExecutor\ntaskExecutor bean created. com.minis.scheduling.concurrent.ThreadPoolTaskExecutor : com.minis.scheduling.concurrent.ThreadPoolTaskExecutor@32e7afd3\nhandle properties for bean : taskExecutor\n bean registerded............. taskExecutor\npostProcessBeforeInitialization : taskExecutor\n try to create proxy for : taskExecutor\n match?taskExecutor:action*\n class proxy after bean post processor class com.minis.scheduling.concurrent.ThreadPoolTaskExecutor\npostProcessAfterInitialization : taskExecutor\n bean registerded............. taskExecutor\nnormal bean -------------- taskExecutor----------------com.minis.scheduling.concurrent.ThreadPoolTaskExecutor@32e7afd3\nget bean null -------------- asyncExecutionInterceptor\nasyncExecutionInterceptor bean created. com.minis.aop.AsyncExecutionInterceptor : com.minis.aop.AsyncExecutionInterceptor@286f25b5\nhandle properties for bean : asyncExecutionInterceptor\nbean exist -------------- taskExecutor----------------com.minis.scheduling.concurrent.ThreadPoolTaskExecutor@32e7afd3\nnormal bean -------------- taskExecutor----------------com.minis.scheduling.concurrent.ThreadPoolTaskExecutor@32e7afd3\n bean registerded............. asyncExecutionInterceptor\npostProcessBeforeInitialization : asyncExecutionInterceptor\n try to create proxy for : asyncExecutionInterceptor\n match?asyncExecutionInterceptor:action*\n class proxy after bean post processor class com.minis.aop.AsyncExecutionInterceptor\npostProcessAfterInitialization : asyncExecutionInterceptor\n bean registerded............. asyncExecutionInterceptor\nnormal bean -------------- asyncExecutionInterceptor----------------com.minis.aop.AsyncExecutionInterceptor@286f25b5\nget bean null -------------- asyncAnnotationAdvisor\nasyncAnnotationAdvisor bean created. com.minis.scheduling.annotation.AsyncAnnotationAdvisor : com.minis.scheduling.annotation.AsyncAnnotationAdvisor@6633dbc4\nhandle properties for bean : asyncAnnotationAdvisor\nbean exist -------------- asyncExecutionInterceptor----------------com.minis.aop.AsyncExecutionInterceptor@286f25b5\nnormal bean -------------- asyncExecutionInterceptor----------------com.minis.aop.AsyncExecutionInterceptor@286f25b5\n bean registerded............. asyncAnnotationAdvisor\npostProcessBeforeInitialization : asyncAnnotationAdvisor\n try to create proxy for : asyncAnnotationAdvisor\n match?asyncAnnotationAdvisor:action*\n class proxy after bean post processor class com.minis.scheduling.annotation.AsyncAnnotationAdvisor\npostProcessAfterInitialization : asyncAnnotationAdvisor\n bean registerded............. asyncAnnotationAdvisor\nnormal bean -------------- asyncAnnotationAdvisor----------------com.minis.scheduling.annotation.AsyncAnnotationAdvisor@6633dbc4\nbean exist -------------- asyncAnnotationBeanPostProcessor----------------com.minis.scheduling.annotation.AsyncAnnotationBeanPostProcessor@26a88d9\nnormal bean -------------- asyncAnnotationBeanPostProcessor----------------com.minis.scheduling.annotation.AsyncAnnotationBeanPostProcessor@26a88d9\nbean exist -------------- autowiredAnnotationBeanPostProcessor----------------com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@2eb36cae\nnormal bean -------------- autowiredAnnotationBeanPostProcessor----------------com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@2eb36cae\nbean exist -------------- logBeanPostProcessor----------------com.test.LogBeanPostProcessor@2be12115\nnormal bean -------------- logBeanPostProcessor----------------com.test.LogBeanPostProcessor@2be12115\nbean exist -------------- autoProxyCreator----------------com.minis.aop.framework.autoproxy.BeanNameAutoProxyCreator@48f89de1\nnormal bean -------------- autoProxyCreator----------------com.minis.aop.framework.autoproxy.BeanNameAutoProxyCreator@48f89de1\nget bean null -------------- action\naction bean created. com.test.service.Action1 : com.test.service.Action1@36e0c1fe\nhandle properties for bean : action\n bean registerded............. action\npostProcessBeforeInitialization : action\n try to create proxy for : action\n match?action:action*\nactionbean name matched, action* create proxy for com.test.service.Action1@36e0c1fe\n class proxy after bean post processor class com.minis.aop.framework.ProxyFactoryBean\npostProcessAfterInitialization : action\n bean registerded............. action\nfactory bean -------------- action----------------com.minis.aop.framework.ProxyFactoryBean@73cf43a9\nget bean null -------------- advisor\nadvisor bean created. com.minis.aop.NameMatchMethodPointcutAdvisor : com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nhandle properties for bean : advisor\nget bean null -------------- beforeAdvice\nbeforeAdvice bean created. com.test.service.MyBeforeAdvice : com.test.service.MyBeforeAdvice@84b1199\nhandle properties for bean : beforeAdvice\n bean registerded............. beforeAdvice\npostProcessBeforeInitialization : beforeAdvice\n try to create proxy for : beforeAdvice\n match?beforeAdvice:action*\n class proxy after bean post processor class com.test.service.MyBeforeAdvice\npostProcessAfterInitialization : beforeAdvice\n bean registerded............. beforeAdvice\nnormal bean -------------- beforeAdvice----------------com.test.service.MyBeforeAdvice@84b1199\n bean registerded............. advisor\npostProcessBeforeInitialization : advisor\n try to create proxy for : advisor\n match?advisor:action*\n class proxy after bean post processor class com.minis.aop.NameMatchMethodPointcutAdvisor\npostProcessAfterInitialization : advisor\n bean registerded............. advisor\nnormal bean -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nget bean null -------------- action2\naction2 bean created. com.test.service.Action2 : com.test.service.Action2@1dc470dd\nhandle properties for bean : action2\n bean registerded............. action2\npostProcessBeforeInitialization : action2\n try to create proxy for : action2\n match?action2:action*\naction2bean name matched, action* create proxy for com.test.service.Action2@1dc470dd\n class proxy after bean post processor class com.minis.aop.framework.ProxyFactoryBean\npostProcessAfterInitialization : action2\n bean registerded............. action2\nfactory bean -------------- action2----------------com.minis.aop.framework.ProxyFactoryBean@21b62e08\nbean exist -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nnormal bean -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nget bean null -------------- executorTest\nexecutorTest bean created. com.test.service.ExecutorTest : com.test.service.ExecutorTest@32112a64\nhandle properties for bean : executorTest\n bean registerded............. executorTest\nbean exist -------------- taskExecutor----------------com.minis.scheduling.concurrent.ThreadPoolTaskExecutor@32e7afd3\nnormal bean -------------- taskExecutor----------------com.minis.scheduling.concurrent.ThreadPoolTaskExecutor@32e7afd3\nautowire taskExecutor for bean executorTest\nautowire taskExecutor for bean executorTest : com.minis.scheduling.concurrent.ThreadPoolTaskExecutor@32e7afd3 class : class com.minis.scheduling.concurrent.ThreadPoolTaskExecutor\npostProcessBeforeInitialization : executorTest\n try to create proxy for : executorTest\n match?executorTest:action*\n class proxy after bean post processor class com.test.service.ExecutorTest\npostProcessAfterInitialization : executorTest\n bean registerded............. executorTest\nnormal bean -------------- executorTest----------------com.test.service.ExecutorTest@32112a64\nbean exist -------------- beforeAdvice----------------com.test.service.MyBeforeAdvice@84b1199\nnormal bean -------------- beforeAdvice----------------com.test.service.MyBeforeAdvice@84b1199\nbean exist -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nnormal bean -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nbean exist -------------- dataSource----------------com.minis.jdbc.pool.PooledDataSource@576ba6cf\nnormal bean -------------- dataSource----------------com.minis.jdbc.pool.PooledDataSource@576ba6cf\nbean exist -------------- jdbcTemplate----------------com.minis.jdbc.core.JdbcTemplate@b6c3afb\nnormal bean -------------- jdbcTemplate----------------com.minis.jdbc.core.JdbcTemplate@b6c3afb\nget bean null -------------- contextListener\ncontextListener bean created. com.test.MyListener : com.test.MyListener@5abd8161\nhandle properties for bean : contextListener\n bean registerded............. contextListener\npostProcessBeforeInitialization : contextListener\n try to create proxy for : contextListener\n match?contextListener:action*\n class proxy after bean post processor class com.test.MyListener\npostProcessAfterInitialization : contextListener\n bean registerded............. contextListener\nnormal bean -------------- contextListener----------------com.test.MyListener@5abd8161\nget bean null -------------- beanFactoryPostProcessor\nbeanFactoryPostProcessor bean created. com.test.MyBeanFactoryPostProcessor : com.test.MyBeanFactoryPostProcessor@71127363\nhandle properties for bean : beanFactoryPostProcessor\n bean registerded............. beanFactoryPostProcessor\npostProcessBeforeInitialization : beanFactoryPostProcessor\n try to create proxy for : beanFactoryPostProcessor\n match?beanFactoryPostProcessor:action*\n class proxy after bean post processor class com.test.MyBeanFactoryPostProcessor\npostProcessAfterInitialization : beanFactoryPostProcessor\n bean registerded............. beanFactoryPostProcessor\nnormal bean -------------- beanFactoryPostProcessor----------------com.test.MyBeanFactoryPostProcessor@71127363\nget bean null -------------- handlerMapping\nhandlerMapping bean created. com.minis.web.method.annotation.RequestMappingHandlerMapping : com.minis.web.method.annotation.RequestMappingHandlerMapping@242f7071\nhandle properties for bean : handlerMapping\n bean registerded............. handlerMapping\npostProcessBeforeInitialization : handlerMapping\n try to create proxy for : handlerMapping\n match?handlerMapping:action*\n class proxy after bean post processor class com.minis.web.method.annotation.RequestMappingHandlerMapping\npostProcessAfterInitialization : handlerMapping\n bean registerded............. handlerMapping\nnormal bean -------------- handlerMapping----------------com.minis.web.method.annotation.RequestMappingHandlerMapping@242f7071\nget bean null -------------- handlerAdapter\nhandlerAdapter bean created. com.minis.web.method.annotation.RequestMappingHandlerAdapter : com.minis.web.method.annotation.RequestMappingHandlerAdapter@55ae5bf6\nhandle properties for bean : handlerAdapter\nget bean null -------------- messageConverter\nmessageConverter bean created. com.minis.http.converter.DefaultHttpMessageConverter : com.minis.http.converter.DefaultHttpMessageConverter@3d073db2\nhandle properties for bean : messageConverter\nget bean null -------------- objectMapper\nobjectMapper bean created. com.minis.util.DefaultObjectMapper : com.minis.util.DefaultObjectMapper@62746e9b\nhandle properties for bean : objectMapper\n bean registerded............. objectMapper\npostProcessBeforeInitialization : objectMapper\n try to create proxy for : objectMapper\n match?objectMapper:action*\n class proxy after bean post processor class com.minis.util.DefaultObjectMapper\npostProcessAfterInitialization : objectMapper\n bean registerded............. objectMapper\nnormal bean -------------- objectMapper----------------com.minis.util.DefaultObjectMapper@62746e9b\n bean registerded............. messageConverter\npostProcessBeforeInitialization : messageConverter\n try to create proxy for : messageConverter\n match?messageConverter:action*\n class proxy after bean post processor class com.minis.http.converter.DefaultHttpMessageConverter\npostProcessAfterInitialization : messageConverter\n bean registerded............. messageConverter\nnormal bean -------------- messageConverter----------------com.minis.http.converter.DefaultHttpMessageConverter@3d073db2\nget bean null -------------- webBindingInitializer\nwebBindingInitializer bean created. com.test.DateInitializer : com.test.DateInitializer@1aaa3474\nhandle properties for bean : webBindingInitializer\n bean registerded............. webBindingInitializer\npostProcessBeforeInitialization : webBindingInitializer\n try to create proxy for : webBindingInitializer\n match?webBindingInitializer:action*\n class proxy after bean post processor class com.test.DateInitializer\npostProcessAfterInitialization : webBindingInitializer\n bean registerded............. webBindingInitializer\nnormal bean -------------- webBindingInitializer----------------com.test.DateInitializer@1aaa3474\n bean registerded............. handlerAdapter\npostProcessBeforeInitialization : handlerAdapter\n try to create proxy for : handlerAdapter\n match?handlerAdapter:action*\n class proxy after bean post processor class com.minis.web.method.annotation.RequestMappingHandlerAdapter\npostProcessAfterInitialization : handlerAdapter\n bean registerded............. handlerAdapter\nnormal bean -------------- handlerAdapter----------------com.minis.web.method.annotation.RequestMappingHandlerAdapter@55ae5bf6\nbean exist -------------- webBindingInitializer----------------com.test.DateInitializer@1aaa3474\nnormal bean -------------- webBindingInitializer----------------com.test.DateInitializer@1aaa3474\nbean exist -------------- messageConverter----------------com.minis.http.converter.DefaultHttpMessageConverter@3d073db2\nnormal bean -------------- messageConverter----------------com.minis.http.converter.DefaultHttpMessageConverter@3d073db2\nbean exist -------------- objectMapper----------------com.minis.util.DefaultObjectMapper@62746e9b\nnormal bean -------------- objectMapper----------------com.minis.util.DefaultObjectMapper@62746e9b\nget bean null -------------- viewResolver\nviewResolver bean created. com.minis.web.servlet.view.InternalResourceViewResolver : com.minis.web.servlet.view.InternalResourceViewResolver@9c7fb88\nhandle properties for bean : viewResolver\n bean registerded............. viewResolver\npostProcessBeforeInitialization : viewResolver\n try to create proxy for : viewResolver\n match?viewResolver:action*\n class proxy after bean post processor class com.minis.web.servlet.view.InternalResourceViewResolver\npostProcessAfterInitialization : viewResolver\n bean registerded............. viewResolver\nnormal bean -------------- viewResolver----------------com.minis.web.servlet.view.InternalResourceViewResolver@9c7fb88\nbean exist -------------- bbs----------------com.test.service.BaseBaseService@55636380\nnormal bean -------------- bbs----------------com.test.service.BaseBaseService@55636380\nbean exist -------------- aservice----------------com.test.service.AServiceImpl@7218ed14\nnormal bean -------------- aservice----------------com.test.service.AServiceImpl@7218ed14\nbean exist -------------- baseservice----------------com.test.service.BaseService@49f37c5f\nnormal bean -------------- baseservice----------------com.test.service.BaseService@49f37c5f\nbean exist -------------- userService----------------com.test.service.UserService@11314941\nnormal bean -------------- userService----------------com.test.service.UserService@11314941\nbean exist -------------- taskExecutor----------------com.minis.scheduling.concurrent.ThreadPoolTaskExecutor@32e7afd3\nnormal bean -------------- taskExecutor----------------com.minis.scheduling.concurrent.ThreadPoolTaskExecutor@32e7afd3\nbean exist -------------- asyncExecutionInterceptor----------------com.minis.aop.AsyncExecutionInterceptor@286f25b5\nnormal bean -------------- asyncExecutionInterceptor----------------com.minis.aop.AsyncExecutionInterceptor@286f25b5\nbean exist -------------- asyncAnnotationAdvisor----------------com.minis.scheduling.annotation.AsyncAnnotationAdvisor@6633dbc4\nnormal bean -------------- asyncAnnotationAdvisor----------------com.minis.scheduling.annotation.AsyncAnnotationAdvisor@6633dbc4\nbean exist -------------- asyncAnnotationBeanPostProcessor----------------com.minis.scheduling.annotation.AsyncAnnotationBeanPostProcessor@26a88d9\nnormal bean -------------- asyncAnnotationBeanPostProcessor----------------com.minis.scheduling.annotation.AsyncAnnotationBeanPostProcessor@26a88d9\nbean exist -------------- autowiredAnnotationBeanPostProcessor----------------com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@2eb36cae\nnormal bean -------------- autowiredAnnotationBeanPostProcessor----------------com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@2eb36cae\nbean exist -------------- logBeanPostProcessor----------------com.test.LogBeanPostProcessor@2be12115\nnormal bean -------------- logBeanPostProcessor----------------com.test.LogBeanPostProcessor@2be12115\nbean exist -------------- autoProxyCreator----------------com.minis.aop.framework.autoproxy.BeanNameAutoProxyCreator@48f89de1\nnormal bean -------------- autoProxyCreator----------------com.minis.aop.framework.autoproxy.BeanNameAutoProxyCreator@48f89de1\nbean exist -------------- action----------------com.minis.aop.framework.ProxyFactoryBean@73cf43a9\nfactory bean -------------- action----------------com.minis.aop.framework.ProxyFactoryBean@73cf43a9\nbean exist -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nnormal bean -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nbean exist -------------- action2----------------com.minis.aop.framework.ProxyFactoryBean@21b62e08\nfactory bean -------------- action2----------------com.minis.aop.framework.ProxyFactoryBean@21b62e08\nbean exist -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nnormal bean -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nbean exist -------------- executorTest----------------com.test.service.ExecutorTest@32112a64\nnormal bean -------------- executorTest----------------com.test.service.ExecutorTest@32112a64\nbean exist -------------- beforeAdvice----------------com.test.service.MyBeforeAdvice@84b1199\nnormal bean -------------- beforeAdvice----------------com.test.service.MyBeforeAdvice@84b1199\nbean exist -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nnormal bean -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nbean exist -------------- dataSource----------------com.minis.jdbc.pool.PooledDataSource@576ba6cf\nnormal bean -------------- dataSource----------------com.minis.jdbc.pool.PooledDataSource@576ba6cf\nbean exist -------------- jdbcTemplate----------------com.minis.jdbc.core.JdbcTemplate@b6c3afb\nnormal bean -------------- jdbcTemplate----------------com.minis.jdbc.core.JdbcTemplate@b6c3afb\nbean exist -------------- contextListener----------------com.test.MyListener@5abd8161\nnormal bean -------------- contextListener----------------com.test.MyListener@5abd8161\nbean exist -------------- beanFactoryPostProcessor----------------com.test.MyBeanFactoryPostProcessor@71127363\nnormal bean -------------- beanFactoryPostProcessor----------------com.test.MyBeanFactoryPostProcessor@71127363\nbean exist -------------- handlerMapping----------------com.minis.web.method.annotation.RequestMappingHandlerMapping@242f7071\nnormal bean -------------- handlerMapping----------------com.minis.web.method.annotation.RequestMappingHandlerMapping@242f7071\nbean exist -------------- handlerAdapter----------------com.minis.web.method.annotation.RequestMappingHandlerAdapter@55ae5bf6\nnormal bean -------------- handlerAdapter----------------com.minis.web.method.annotation.RequestMappingHandlerAdapter@55ae5bf6\nbean exist -------------- webBindingInitializer----------------com.test.DateInitializer@1aaa3474\nnormal bean -------------- webBindingInitializer----------------com.test.DateInitializer@1aaa3474\nbean exist -------------- messageConverter----------------com.minis.http.converter.DefaultHttpMessageConverter@3d073db2\nnormal bean -------------- messageConverter----------------com.minis.http.converter.DefaultHttpMessageConverter@3d073db2\nbean exist -------------- objectMapper----------------com.minis.util.DefaultObjectMapper@62746e9b\nnormal bean -------------- objectMapper----------------com.minis.util.DefaultObjectMapper@62746e9b\nbean exist -------------- viewResolver----------------com.minis.web.servlet.view.InternalResourceViewResolver@9c7fb88\nnormal bean -------------- viewResolver----------------com.minis.web.servlet.view.InternalResourceViewResolver@9c7fb88\n.........refreshed.........beans count : 26\nget bean null -------------- autowiredAnnotationBeanPostProcessor\nbean exist -------------- autowiredAnnotationBeanPostProcessor----------------com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@2eb36cae\nnormal bean -------------- autowiredAnnotationBeanPostProcessor----------------com.minis.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@2eb36cae\nget bean null -------------- com.test.controller.HelloWorldBean\ncom.test.controller.HelloWorldBean bean created. com.test.controller.HelloWorldBean : com.test.controller.HelloWorldBean@6e18c91e\nhandle properties for bean : com.test.controller.HelloWorldBean\n bean registerded............. com.test.controller.HelloWorldBean\nget bean null -------------- baseservice\nbean exist -------------- baseservice----------------com.test.service.BaseService@49f37c5f\nnormal bean -------------- baseservice----------------com.test.service.BaseService@49f37c5f\nautowire baseservice for bean com.test.controller.HelloWorldBean\nautowire baseservice for bean com.test.controller.HelloWorldBean : com.test.service.BaseService@49f37c5f class : class com.test.service.BaseService\nget bean null -------------- userService\nbean exist -------------- userService----------------com.test.service.UserService@11314941\nnormal bean -------------- userService----------------com.test.service.UserService@11314941\nautowire userService for bean com.test.controller.HelloWorldBean\nautowire userService for bean com.test.controller.HelloWorldBean : com.test.service.UserService@11314941 class : class com.test.service.UserService\nget bean null -------------- action\nbean exist -------------- action----------------com.minis.aop.framework.ProxyFactoryBean@73cf43a9\nfactory bean -------------- action----------------com.minis.aop.framework.ProxyFactoryBean@73cf43a9\nbean exist -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nnormal bean -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nautowire action for bean com.test.controller.HelloWorldBean\nautowire action for bean com.test.controller.HelloWorldBean : null class : class com.sun.proxy.$Proxy5\nget bean null -------------- action2\nbean exist -------------- action2----------------com.minis.aop.framework.ProxyFactoryBean@21b62e08\nfactory bean -------------- action2----------------com.minis.aop.framework.ProxyFactoryBean@21b62e08\nbean exist -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nnormal bean -------------- advisor----------------com.minis.aop.NameMatchMethodPointcutAdvisor@4310831f\nautowire action2 for bean com.test.controller.HelloWorldBean\nautowire action2 for bean com.test.controller.HelloWorldBean : null class : class com.sun.proxy.$Proxy5\nget bean null -------------- executorTest\nbean exist -------------- executorTest----------------com.test.service.ExecutorTest@32112a64\nnormal bean -------------- executorTest----------------com.test.service.ExecutorTest@32112a64\nautowire executorTest for bean com.test.controller.HelloWorldBean\nautowire executorTest for bean com.test.controller.HelloWorldBean : com.test.service.ExecutorTest@32112a64 class : class com.test.service.ExecutorTest\n class proxy after bean post processor class com.test.controller.HelloWorldBean\n bean registerded............. com.test.controller.HelloWorldBean\nnormal bean -------------- com.test.controller.HelloWorldBean----------------com.test.controller.HelloWorldBean@6e18c91e\nbean exist -------------- com.test.controller.HelloWorldBean----------------com.test.controller.HelloWorldBean@6e18c91e\nnormal bean -------------- com.test.controller.HelloWorldBean----------------com.test.controller.HelloWorldBean@6e18c91e\nget bean null -------------- handlerMapping\nbean exist -------------- handlerMapping----------------com.minis.web.method.annotation.RequestMappingHandlerMapping@242f7071\nnormal bean -------------- handlerMapping----------------com.minis.web.method.annotation.RequestMappingHandlerMapping@242f7071\nget bean null -------------- handlerAdapter\nbean exist -------------- handlerAdapter----------------com.minis.web.method.annotation.RequestMappingHandlerAdapter@55ae5bf6\nnormal bean -------------- handlerAdapter----------------com.minis.web.method.annotation.RequestMappingHandlerAdapter@55ae5bf6\nget bean null -------------- viewResolver\nbean exist -------------- viewResolver----------------com.minis.web.servlet.view.InternalResourceViewResolver@9c7fb88\nnormal bean -------------- viewResolver----------------com.minis.web.servlet.view.InternalResourceViewResolver@9c7fb88\n[2025-01-03 09:44:08,884] Artifact handson-spring:war: Artifact is deployed successfully\n[2025-01-03 09:44:08,885] Artifact handson-spring:war: Deploy took 1,328 milliseconds\nbean exist -------------- com.test.controller.HelloWorldBean----------------com.test.controller.HelloWorldBean@6e18c91e\nnormal bean -------------- com.test.controller.HelloWorldBean----------------com.test.controller.HelloWorldBean@6e18c91e\n03-Jan-2025 21:44:17.455 ��Ϣ [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [C:\\Users\\hasee\\apache-tomcat-9.0.6\\webapps\\manager]\n03-Jan-2025 21:44:17.499 ��Ϣ [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [C:\\Users\\hasee\\apache-tomcat-9.0.6\\webapps\\manager] has finished in [43] ms\n\n```\n## 项目结构\n一层层对照 Spring 框架的现有结构，让原理理解起来不再困难。\n1. 第一部分： IoC 容器 。IoC 容器是 Spring 核心中的核心，Spring 抽象出 Bean 这个概念，用一个容器管理所有的 Bean，并解决上层应用的业务对象之间的耦合问题。后面所有的特性都依赖于 Bean 的概念和这个容器。因此即使我们简单地说 Spring 框架就是一个 IoC 容器也未尝不可。这个部分我们会从一个极简容器开始，逐步扩展增强，最终实现一个完整的 IoC 容器，包含 Spring 框架对应的核心功能，实现 Bean 的管理。基于这个核心，逐步扩展到 MiniSpring 的其他特性。打好这个基础，后面的学习会事半功倍。\n   \n2. 第二部分：MVC 。MVC 是 Spring 支持 Web 模式的程序结构，它是基于 Servlet 技术实现的。基本思路是利用 Servlet 机制，用一个单一的 Servlet 拦截所有请求，然后根据请求里面的的信息把任务分派给不同的业务类处理，实现原始的 MVC 结构。在这一部分，我们还会将 MVC 与第一部分的 IoC 容器结合起来，构成一个更大、更完整的框架。在一步步的构造过程中，我们会重点讲解大师们怎么逐步拆解这个 Servlet 的功能，把专业的事情交给专门的部件去做，最后构建成一个完整的体系。\n\n3. 第三部分：JDBC Template 。JDBC Tempalte 是 Spring 对数据访问的一个实现，我们会重点分析 Spring 的实现方法，体现 Rodd Johnson 对简洁实用原则的把握。这一部分，我们会学习如何提取出一个 JDBC 访问的模板，来固化访问数据库的流程，怎么自动绑定参数值，简化上层应用程序。在此基础之上，我们还将了解到如何通过数据库连接池提高访问性能，以及模仿 MyBatis 将 SQL 语句配置到外部文件中。通过这部分的学习，我们可以了解到，整个 JDBC Template 的实现都是运用了前面 IoC 管理 Bean 的方式，将数据的访问抽象成一个个 Bean，注入到系统中。由此，更能深刻体会到 IoC 容器的功用。\n\n4. 第四部分：AOP 。AOP 是 Spring 框架中实践面向切面编程的探索。面向对象和面向切面，两者一纵一横，编织成完整的程序结构。在这一部分，我们将了解到 Spring AOP 所采用的一个实现方式：JDK 动态代理。我们会学习动态代理的原理，以及如何用这个技术动态插入业务逻辑，实现切面的特性。最后我们将再一次看到 AOP 与 IoC 的结合，使用 BeanPostProcessor 自动生成动态代理。这时你就会体会到，我前面说的“IoC 是 Spring 框架核心中的核心”。\n\n5. 第五部分：ThreadPool 。这一章我们在Spring层面复现了异步线程池，防止主线程被长业务请求所阻塞。不仅如此，我们还封装了ThreadPoolExecutor，扩展了Future接口支持添加回调函数，重写了FutureTask类用于执行回调函数\n    \n在这一步一步的演化过程中，我们对 Spring 的模仿逐渐成型。我坚持一个原则，就是每一步都是可以运行的，都会有看得见的收获，一起见证Spring 的风采。 《诗经》有云：“有匪君子，如切如磋，如琢如磨”。任何一个技术领域都是这样，不断练习，反复琢磨，最后才能站在山顶！ git分支结构如下所示：\n\n- geekA_ioc01_nativeClassPathXmlApplicationContext：实现了一个简易的IOC容器ClassPathXmlApplicationContext，耦合了Resource，耦合了Reader，耦合了BeanFactory的功能\n- geekA_ioc02_expandBeanDefinition：扩展了BeanDefinition的定义信息，支持Setter注入，支持构造注入，维护单实例Bean，并且解耦了ClassPathXmlApplicationContext\n- geekA_ioc03_realizeDIAndCircleDI：实现了依赖注入，引入二级缓存，解决了循环依赖\n- geekA_ioc04_AutowireCapableBeanFactoryAndProcessor：定义BeanPostProcessor接口，实现了AutowireCapableBeanFactoryAndProcessor支持@Autowired注入\n- geekA_ioc05_iocengineDefaultListableBeanFactory：构建完整的工厂体系DefaultListableBeanFactory\n- geekA_ioc06_fullContextSystemAndEvent：构建完整的ApplicationContext上下文体系并添加容器事件\n- geekB_mvc01_xmlMapping：基于原生Servlet和xml路由配置，实现一种最简单的请求响应，通过response.getWriter().append(objResult.toString());来返回请求结果\n- geekB_mvc02_AnnoatationRequestMapping：实现基于@RequestMapping注解的mvc\n- geekB_mvc03_Integratedioc：将springmvc与spring容器进行整合\n- geekB_mvc04_uncouplingWAC：对WebApplicationContext进行解耦，实现springmvc父子容器XmlWebApplicationContext和AnnotationConfigWebApplicationContext\n- geekB_mvc05_HandlerMappingAndAdapter：实现HandlerMapping和HandlerAdapter，把请求解析和请求执行两步操作解耦\n- geekB_mvc06_requestDataBinder：实现请求路径参数与请求方法参数对象进行绑定\n- geekB_mvc07_ModelAndView：实现springmvc的响应值Response处理，新增两种处理方式：1.@ResponseBody（返回json串，用于前后端分离）2.拼串寻找jsp页面（已淘汰）\n- geekC_jdbc01_IntegratediocJdbcTemplateAndDataSource：实现一个JdbcTemplate，并且封装数据源DataSource，最终将JdbcTemplate和DataSource与IOC容器做了整合\n- geekC_jdbc02_expandTemplateAndSingleResponsibilitPrinciple：扩展了JdbcTemplate，根据单一职责，抽取出关于SQL输入参数处理的组件ArgumentPreparedStatementSetter，抽取出处理SQL返回结果与对象的绑定的组件RowMapper和ResultSetExtractor\n- geekC_jdbc03_PooledDataSource：实现了数据库（源）连接池PooledDataSource，并与IOC整合，替换SingleConnectionDataSource\n- geekC_jdbc04_realizeBatisSqlSession：仿写了mybatis框架，实现了配置化SQL语句\n- geekD_aop01_IntegratediocDynamicProxyByFactoryBean：原生的jdk动态代理还是会暴露代码，因为我们完成了零代码侵入的动态代理的框架封装\n- geekD_aop02_uncouplingByInterceptorAndInvocation：解耦Interceptor和Invocation，实现三种Interceptor（默认环绕，前置，后置）\n- geekD_aop03_realizePointcutToMatchmethods：实现配置化的切入点表达式，批量增强目标方法\n- geekD_aop04_AutoProxyCreatorToMatchclasss：添加配置化的AutoProxyCreator后置处理器，批量代理目标类\n- geekE_threadpool01_addCallback：\n  - 封装了ThreadPoolExecutor，名为ThreadPoolTaskExecutor用于执行异步任务，并整合进IOC容器\n  - 扩展了顶级Future接口，名为ListenableFuture使其支持注册回调函数\n  - 根据单一职责原则，创建回调函数仓库ListenableFutureCallbackRegistry.java，用于维护回调函数队列：双队列\n  - 为了执行前面注册的回调函数，继承了FutureTask类，名为ListenableFutureTask，\n    - 持有回调函数仓库ListenableFutureCallbackRegistry的单向引用\n    - 重写了的done方法：run()-set()-finishCompletion()-protected done()\n- geekE_threadpool02_AsyncAnnotationBeanPostProcessor：支持了@Async注解，越来越像Spring了\n  - 仿照@Autowired注解解析思路，新建后置处理器AsyncAnnotationBeanPostProcessor，返回AOP增强对象\n  - 仿照AOP实现原理，AsyncExecutionInterceptor，用于封装异步线程的创建逻辑，不再像用户暴露\n  - 新建AsyncAnnotationAdvisor持有AsyncExecutionInterceptor的单向引用\n  - 扩展JdkDynamicAopProxy，使其支持PointcutAdvisor和AsyncAnnotationAdvisor两种Advisor\n\n\n帮作者点点⭐⭐，带你向更高处卷：\n- 手写服务器Tomcat：https://github.com/Halfmoonly/handson-tomcat\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhalfmoonly%2Fhandson-spring","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhalfmoonly%2Fhandson-spring","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhalfmoonly%2Fhandson-spring/lists"}