- 浏览: 75721 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
liuxiang00435057:
能把源码共享下吗,或者发一份给我,liuxiang004350 ...
权限管理:RBAC(基于角色的访问控制)的实现 -
ZHJason:
太强大了。。。哈哈。。
婚恋中的经济学 -
m635674608:
有机会。。请教下。。
ASM字节码框架 -
m635674608:
不错。。我也在研究asm了、、、
ASM字节码框架 -
kuloujianzun:
我敢肯定,这段程序跑不了,WorkingEnvironment ...
drools4.0学习实践(一)
Spring2.5源码解读 之 基于annotation的Controller实现原理分析(1)
网上已有许多关于Spring源码解读的文章,但对于SpringMVC中基于annotation的Controller这一块,目前还没发现有相关源码解读的文章,这几天,一直在研究SpringMVC,小有所获。这里,对Spring中基于annotation的Controller的实现原理作下简单分析,作为以后学习的参考资料,如果有人也对此感兴趣,也欢迎一起研究,交流心得。
快速开始SpringMVC
1、导入核心JAR,有两种导入方式
* 导入全部JAR:spring.jar
* 导入最小JAR:spring-core、spring-beans、spring-context、spring-web、spring-webmvc
第三方依赖JAR:commons-logging.jar
2、配置核心servlet:
* 3、配置包扫描列表
在[servlet-name]-servlet中配置:
将所有基于annotation的handler放在test包下即可。
相当简洁的配置,体现出了的Sping的强大、灵活,不过估计不会有人这样用Spring,呵呵
源码分析之旅:
SpringMVC的核心是DispatcherServlet,网上已经有对该类的简单分析,见后面参考资料。对于handler扫描、初始化映射关系等,以后有时间再详细解读,这里只是稍微提一下:
DispatcherServlet的初始化:
该初始方法主要完成两件工作:
* 1、将容器中配置(在applicationContext.xml中定义)的HandlerMapping、LocaleResolver等等初始化
* 2、如果容器中未配置,则使用默认策略,该默认策略定义在DispatcherServlet.properties文件中
这其中有几个比较重要的组件(也称管道)需要初始化,包括HandlerMapping、HandlerAdapter、ViewResolver。
HandlerMapping
我们从DispatcherServlet的doService方法入手:
可以看出,对于请求的处理实际上是由doDispatch()完成的,这里只对与annotation相关的部分进行分析:
再来看查找handler的过程:
实际查找handler的过程由DefaultAnnotationHandlerMapping类完成。从它的继承层次可以看出,匹配的主要工作都由其父类完成了。在父类中定义了算法的骨架,具体的处理交由子类完成,这是Templet设计模式的典型应用。[[BR]]
先看父类AbstractHandlerMapping中定义的算法骨架:
AbstractHandlerMapping的子类AbstractUrlHandlerMapping中getHandlerInternal的定义:
子类DefaultAnnotationHandlerMapping中@RequestMapping的匹配过程:
请求方法及参数的匹配过程由ServletAnnotationMappingUtils类的静态方法完成,逻辑比较简单:
至此,handler的匹配过程结束,bean的实例作为匹配的handler返回。可以看出,匹配过程并未深入到方法一级,如果类级别和方法级别都定义了url,在这一层次会忽略方法级别的。其实,spring也不推荐在类级别和方法级别同时定义url。[[BR]]
再回到DispatcherServlet中,找到匹配handler后,下一步就要去调用handler,调用的方式有许多,spring抽像出了一个接口HandlerAdapter,接口的定义:
DispatcherServlet中寻找合适的HandlerAdapter的过程:
基于annotation的handler则是由AnnotationMethodHandlerAdapter进行处理,来看AnnotationMethodHandlerAdapter中相关处理代码:
好了,到这里,handler已确定,由谁去处理handler也已确定,剩下的工作就是如何调用了。来看具体的调用代码:
其中,确定具体调用哪个方法这个过程比较复杂,由ServletHandlerMethodResolver完成。
完成方法调用,由父类HandlerMethodInvoker完成:
至此,handler的方法调用至此结束。我们的分析也告一段落。但对于spring的处理远还未结束,后面还有许多的收尾工作,至于是什么,以后再说,呵呵
参考资料:
* 关于IOC容器的源码分析:http://www.iteye.com/wiki/Spring-source/1226-Spring%E6%BA%90%E4%BB%A3%E7%A0%81%E8%A7%A3%E6%9E%90(%E4%B8%80%EF%BC%89%EF%BC%9AIOC%E5%AE%B9%E5%99%A8
* 关于Spring MVC基于Controller接口的handler的源码分析:http://www.iteye.com/wiki/Spring-source/1222-Spring%E6%BA%90%E4%BB%A3%E7%A0%81%E8%A7%A3%E6%9E%90(%E5%9B%9B%EF%BC%89%EF%BC%9ASpring%20MVC
网上已有许多关于Spring源码解读的文章,但对于SpringMVC中基于annotation的Controller这一块,目前还没发现有相关源码解读的文章,这几天,一直在研究SpringMVC,小有所获。这里,对Spring中基于annotation的Controller的实现原理作下简单分析,作为以后学习的参考资料,如果有人也对此感兴趣,也欢迎一起研究,交流心得。
快速开始SpringMVC
1、导入核心JAR,有两种导入方式
* 导入全部JAR:spring.jar
* 导入最小JAR:spring-core、spring-beans、spring-context、spring-web、spring-webmvc
第三方依赖JAR:commons-logging.jar
2、配置核心servlet:
<servlet> <servlet-name>SpringServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringServlet</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
* 3、配置包扫描列表
在[servlet-name]-servlet中配置:
<context:component-scan base-package="com.spring.test" />
将所有基于annotation的handler放在test包下即可。
相当简洁的配置,体现出了的Sping的强大、灵活,不过估计不会有人这样用Spring,呵呵
源码分析之旅:
SpringMVC的核心是DispatcherServlet,网上已经有对该类的简单分析,见后面参考资料。对于handler扫描、初始化映射关系等,以后有时间再详细解读,这里只是稍微提一下:
DispatcherServlet的初始化:
protected void initStrategies(ApplicationContext context) { //方法入参为ApplicationContext,可证明在DispatcherServlet初始化之前,IoC容器已经开始工作了 initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); }
该初始方法主要完成两件工作:
* 1、将容器中配置(在applicationContext.xml中定义)的HandlerMapping、LocaleResolver等等初始化
* 2、如果容器中未配置,则使用默认策略,该默认策略定义在DispatcherServlet.properties文件中
这其中有几个比较重要的组件(也称管道)需要初始化,包括HandlerMapping、HandlerAdapter、ViewResolver。
HandlerMapping
我们从DispatcherServlet的doService方法入手:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { ... //将WebApplicationContext放在了request中 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); try { doDispatch(request, response); } ... }
可以看出,对于请求的处理实际上是由doDispatch()完成的,这里只对与annotation相关的部分进行分析:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ... try { ModelAndView mv = null; try { //查找匹配的handler mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { //如果没有,写入404错误 noHandlerFound(processedRequest, response); return; } //调用handler的方法 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); ... }
再来看查找handler的过程:
protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception { ... //初始时handlerMappings中有两个: //1、BeanNameUrlHandlerMapping:根据bean的名字查找匹配的handler,意味我们可以在容器中将bean名以url定义,如"/order/*" //2、DefaultAnnotationHandlerMapping:根据annotation定义查找 //每个handlerMapping中都维持有一个url-handler的HashMap,该列表在生成在初始化时完成 Iterator it = this.handlerMappings.iterator(); while (it.hasNext()) { HandlerMapping hm = (HandlerMapping) it.next(); ... handler = hm.getHandler(request);//实际的匹配过程交由handlerMapping完成 ... } return null; }
实际查找handler的过程由DefaultAnnotationHandlerMapping类完成。从它的继承层次可以看出,匹配的主要工作都由其父类完成了。在父类中定义了算法的骨架,具体的处理交由子类完成,这是Templet设计模式的典型应用。[[BR]]
先看父类AbstractHandlerMapping中定义的算法骨架:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request);//交由子类实现 if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } if (handler instanceof String) { //如果handler是String,即完整类名,在容器中定义 String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName);//从IoC中直接获取 } return getHandlerExecutionChain(handler, request); }
AbstractHandlerMapping的子类AbstractUrlHandlerMapping中getHandlerInternal的定义:
protected Object getHandlerInternal(HttpServletRequest request) throws Exception { Object handler = lookupHandler(lookupPath, request); if (handler == null) { ... } return handler; } protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // 直接匹配: Object handler = this.handlerMap.get(urlPath); if (handler != null) { validateHandler(handler, request);//@RequestMapping的其它属性匹配交由子类完成,如method和param的匹配 return buildPathExposingHandler(handler, urlPath); } // 正则表达式匹配: String bestPathMatch = null; for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) { String registeredPath = (String) it.next(); if (getPathMatcher().match(registeredPath, urlPath) && (bestPathMatch == null || bestPathMatch.length() < registeredPath.length())) { bestPathMatch = registeredPath;//可以看出,匹配原则是按照url更长则更匹配 } } if (bestPathMatch != null) { handler = this.handlerMap.get(bestPathMatch); validateHandler(handler, request);//@RequestMapping的其它属性匹配交由子类完成,如method和param的匹配 String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPathMatch, urlPath); return buildPathExposingHandler(handler, pathWithinMapping); } // No handler found... return null; }
子类DefaultAnnotationHandlerMapping中@RequestMapping的匹配过程:
protected void validateHandler(Object handler, HttpServletRequest request) throws Exception { RequestMapping mapping = this.cachedMappings.get(handler.getClass()); if (mapping == null) { mapping = AnnotationUtils.findAnnotation(handler.getClass(), RequestMapping.class); } if (mapping != null) { validateMapping(mapping, request);//具体的匹配在validateMapping中完成 } } protected void validateMapping(RequestMapping mapping, HttpServletRequest request) throws Exception { RequestMethod[] mappedMethods = mapping.method(); //请求方法是否匹配? if (!ServletAnnotationMappingUtils.checkRequestMethod(mappedMethods, request)) { String[] supportedMethods = new String[mappedMethods.length]; for (int i = 0; i < mappedMethods.length; i++) { supportedMethods[i] = mappedMethods[i].name(); } throw new HttpRequestMethodNotSupportedException(request.getMethod(), supportedMethods);//直接就抛异常了?似乎不妥,为什么不尝试下一个比较匹配的那个URL呢?也有可能是父类的算法定义有问题 } //请求参数是否匹配? String[] mappedParams = mapping.params(); if (!ServletAnnotationMappingUtils.checkParameters(mappedParams, request)) { throw new ServletException("Parameter conditions {" + StringUtils.arrayToDelimitedString(mappedParams, ", ") + "} not met for request parameters: " + request.getParameterMap()); } }
请求方法及参数的匹配过程由ServletAnnotationMappingUtils类的静态方法完成,逻辑比较简单:
public static boolean checkRequestMethod(RequestMethod[] methods, HttpServletRequest request) { if (!ObjectUtils.isEmpty(methods)) { boolean match = false; for (RequestMethod method : methods) { if (method.name().equals(request.getMethod())) { match = true; } } if (!match) { return false; } } return true; } public static boolean checkParameters(String[] params, HttpServletRequest request) { if (!ObjectUtils.isEmpty(params)) { for (String param : params) { int separator = param.indexOf('='); if (separator == -1) { if (param.startsWith("!")) { if (WebUtils.hasSubmitParameter(request, param.substring(1))) { return false; } } else if (!WebUtils.hasSubmitParameter(request, param)) { return false; } } else { String key = param.substring(0, separator); String value = param.substring(separator + 1); if (!value.equals(request.getParameter(key))) { return false; } } } } return true; }
至此,handler的匹配过程结束,bean的实例作为匹配的handler返回。可以看出,匹配过程并未深入到方法一级,如果类级别和方法级别都定义了url,在这一层次会忽略方法级别的。其实,spring也不推荐在类级别和方法级别同时定义url。[[BR]]
再回到DispatcherServlet中,找到匹配handler后,下一步就要去调用handler,调用的方式有许多,spring抽像出了一个接口HandlerAdapter,接口的定义:
public interface HandlerAdapter { boolean supports(Object handler); //是否支持此种类型的handler ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; //具体的处理过程 long getLastModified(HttpServletRequest request, Object handler); }
DispatcherServlet中寻找合适的HandlerAdapter的过程:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { /* spring默认提供四个HandlerAdapter: HttpRequestHandlerAdapter:处理HttpRequestHandler接口的实例 SimpleControllerHandlerAdapter:处理Controller接口的实例 ThrowawayControllerHandlerAdapter:已经过时 AnnotationMethodHandlerAdapter:处理annotation定义的实例 */ Iterator it = this.handlerAdapters.iterator(); while (it.hasNext()) { HandlerAdapter ha = (HandlerAdapter) it.next(); if (logger.isDebugEnabled()) { logger.debug("Testing handler adapter [" + ha + "]"); } if (ha.supports(handler)) { return ha; } } ... }
基于annotation的handler则是由AnnotationMethodHandlerAdapter进行处理,来看AnnotationMethodHandlerAdapter中相关处理代码:
//是否支持此类型的handler? public boolean supports(Object handler) { return getMethodResolver(handler).hasHandlerMethods(); } private ServletHandlerMethodResolver getMethodResolver(Object handler) { Class handlerClass = ClassUtils.getUserClass(handler); ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass); if (resolver == null) { resolver = new ServletHandlerMethodResolver(handlerClass);//在父类的构造方法中完成handler的解析 this.methodResolverCache.put(handlerClass, resolver);//缓存起来,方法调用时有用 } return resolver; } public final boolean hasHandlerMethods() { return !this.handlerMethods.isEmpty();//非常简单的判断,如果该类中的方法标记有@RequestMapping就返回true,也意味着它支持此种类型的handler }
好了,到这里,handler已确定,由谁去处理handler也已确定,剩下的工作就是如何调用了。来看具体的调用代码:
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ... if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { return invokeHandlerMethod(request, response, handler); } } } return invokeHandlerMethod(request, response, handler); } protected ModelAndView invokeHandlerMethod( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try { ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);//缓存中已有 Method handlerMethod = methodResolver.resolveHandlerMethod(request);//确定具体该调用哪个方法 ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver); ServletWebRequest webRequest = new ServletWebRequest(request, response); ExtendedModelMap implicitModel = new ExtendedModelMap();//方法入参ModelMap的原型 Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);//调用方法 ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);//构建ModelAndView methodInvoker.updateModelAttributes( handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);//处理ModelMap中的值 return mav; } catch (NoSuchRequestHandlingMethodException ex) { return handleNoSuchRequestHandlingMethod(ex, request, response); } }
其中,确定具体调用哪个方法这个过程比较复杂,由ServletHandlerMethodResolver完成。
public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException { ... for (Method handlerMethod : getHandlerMethods()) { RequestMappingInfo mappingInfo = new RequestMappingInfo(); RequestMapping mapping = AnnotationUtils.findAnnotation(handlerMethod, RequestMapping.class); mappingInfo.paths = mapping.value(); //如果类级别没有定义@RequestMapping,则使用方法级别定义的 if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) { mappingInfo.methods = mapping.method(); } if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) { mappingInfo.params = mapping.params(); } boolean match = false; if (mappingInfo.paths.length > 0) {//先检查url是否匹配 for (String mappedPath : mappingInfo.paths) { if (isPathMatch(mappedPath, lookupPath)) { if (checkParameters(mappingInfo, request)) { match = true; targetPathMatches.put(mappingInfo, mappedPath); } else { break; } } } } else { //如果没有定义url,则只需检查其它项是否匹配,如param、method match = checkParameters(mappingInfo, request); if (match && mappingInfo.methods.length == 0 && mappingInfo.params.length == 0 && resolvedMethodName != null && !resolvedMethodName.equals(handlerMethod.getName())) { match = false; } }//如果已经有匹配了,还须检查是否有歧义的调用? if (match) { Method oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod); if (oldMappedMethod != null && oldMappedMethod != handlerMethod) { if (methodNameResolver != null && mappingInfo.paths.length == 0) { if (!oldMappedMethod.getName().equals(handlerMethod.getName())) { if (resolvedMethodName == null) { resolvedMethodName = methodNameResolver.getHandlerMethodName(request); } if (!resolvedMethodName.equals(oldMappedMethod.getName())) { oldMappedMethod = null; } if (!resolvedMethodName.equals(handlerMethod.getName())) { if (oldMappedMethod != null) { targetHandlerMethods.put(mappingInfo, oldMappedMethod); oldMappedMethod = null; } else { targetHandlerMethods.remove(mappingInfo); } } } } if (oldMappedMethod != null) { ... } } } }//如果只有一个符合条件的方法 if (targetHandlerMethods.size() == 1) { return targetHandlerMethods.values().iterator().next(); }//如果有多个,还需确定最合适的方法 else if (!targetHandlerMethods.isEmpty()) { RequestMappingInfo bestMappingMatch = null; String bestPathMatch = null; for (RequestMappingInfo mapping : targetHandlerMethods.keySet()) { String mappedPath = targetPathMatches.get(mapping); if (bestMappingMatch == null) { bestMappingMatch = mapping; bestPathMatch = mappedPath; } else { if (isBetterPathMatch(mappedPath, bestPathMatch, lookupPath) || (!isBetterPathMatch(bestPathMatch, mappedPath, lookupPath) && (isBetterMethodMatch(mapping, bestMappingMatch) || (!isBetterMethodMatch(bestMappingMatch, mapping) && isBetterParamMatch(mapping, bestMappingMatch))))) { bestMappingMatch = mapping; bestPathMatch = mappedPath; } } } return targetHandlerMethods.get(bestMappingMatch); } else { throw new NoSuchRequestHandlingMethodException(lookupPath, request.getMethod(), request.getParameterMap()); } }
完成方法调用,由父类HandlerMethodInvoker完成:
public final Object invokeHandlerMethod( Method handlerMethod, Object handler, NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { ... Object[] args = resolveHandlerArguments(handlerMethod, handler, webRequest, implicitModel);//参数解析 return doInvokeMethod(handlerMethod, handler, args); }
至此,handler的方法调用至此结束。我们的分析也告一段落。但对于spring的处理远还未结束,后面还有许多的收尾工作,至于是什么,以后再说,呵呵
参考资料:
* 关于IOC容器的源码分析:http://www.iteye.com/wiki/Spring-source/1226-Spring%E6%BA%90%E4%BB%A3%E7%A0%81%E8%A7%A3%E6%9E%90(%E4%B8%80%EF%BC%89%EF%BC%9AIOC%E5%AE%B9%E5%99%A8
* 关于Spring MVC基于Controller接口的handler的源码分析:http://www.iteye.com/wiki/Spring-source/1222-Spring%E6%BA%90%E4%BB%A3%E7%A0%81%E8%A7%A3%E6%9E%90(%E5%9B%9B%EF%BC%89%EF%BC%9ASpring%20MVC
相关推荐
Spring 2.5是Spring框架的一个重要版本,它在...通过深入学习Spring 2.5的源码,开发者可以更好地理解Spring框架的设计思想和工作原理,从而提高开发效率和代码质量。同时,这也为理解后续版本的改进和发展奠定了基础。
2. **注解驱动开发(Annotation-based Development)**:Spring 2.5开始大规模支持Java注解,比如`@Service`、`@Repository`和`@Controller`,它们分别用于标记业务层、数据访问层和控制层的组件。这使得XML配置文件...
这个"Struts2+Spring2.5+Hibernate3+annotation 整合程序"旨在展示如何将这三大框架与注解(Annotation)技术结合,以实现更高效、更简洁的代码编写。 Struts2是一个基于MVC设计模式的Web应用框架,它主要负责处理...
Struts1.3、Spring2.5 和 Hibernate3.3 是经典的 Java Web 开发框架组合,它们在企业级应用中广泛使用。这个组合被称为“SSH”(Struts-Spring-Hibernate),它允许开发者构建可扩展且松耦合的后端系统。在本项目中...
以下将详细讲解 Spring 2.5 中的 IOC 实现原理以及如何创建简单的应用。 **1. IOC 简介** IOC 是一种设计模式,它将对象的创建和管理交给容器处理,使得代码更加松耦合。Spring 框架通过 XML 配置文件或注解方式来...
标题中的“基于Annotation的Struts2.0+Hibernate3.3+Spring2.5整合开发”指的是使用注解的方式将三个流行的Java企业级框架——Struts2、Hibernate和Spring进行集成开发。这样的集成有助于简化配置,提高代码的可读性...
1. **Spring_demo_04_aop_introduction** - 这个例子可能是对Spring的面向切面编程(AOP)的介绍,AOP允许我们在不修改原有代码的情况下,实现如日志记录、性能监控等功能。 2. **Spring_demo_07_dataSource** - ...
在Spring2.5中,IoC容器通过使用注解(Annotation)进一步简化了配置,例如`@Component`、`@Service`、`@Repository`和`@Controller`,这些注解用于标记组件类,使得容器能自动发现并管理它们。此外,`@Autowired`...
花了些时间做了一个实验,彻底弄懂了spring Annotation注入的方式。凡带有@Component,@Controller,@Service,@Repository 标志的等于告诉Spring这类将自动产生对象,而@Resource则等于XML配置中的ref,告诉spring此处...
1. **依赖注入(Dependency Injection, DI)**:Spring Annotation中最常用的注解之一是`@Autowired`,它实现了自动装配bean。当在类的字段或构造器上使用`@Autowired`时,Spring会自动寻找类型匹配的bean并注入。...
1. **IoC(Inversion of Control)控制反转**:Spring的核心特性之一,它通过依赖注入(Dependency Injection,DI)来实现。IoC使得组件之间的依赖关系由容器管理,而不是由组件自身管理,从而降低了代码的耦合度。 ...
标题 "SpringIOC_SpringMVC_SpringAnnotation_JPA" 涵盖了四个核心的Java开发框架技术,它们是Spring框架的重要组成部分。Spring框架是一个开源的应用框架,它为Java开发者提供了一个全面的基础设施,用于构建可扩展...
这篇博客"spring源代码分析:annotation支持的实现"探讨了Spring如何通过注解处理来实现组件扫描和依赖注入。我们将深入探讨以下几个关键知识点: 1. **组件扫描(Component Scanning)**: - 组件扫描是Spring...
深入理解Spring源码需要对Java反射、动态代理、设计模式等有扎实的基础。建议从以下几个步骤入手: 1. 了解基本架构和模块划分。 2. 分析核心类如ApplicationContext、BeanFactory和DispatcherServlet的实现。 3. ...
通过研究这个版本的源码,开发者可以深入理解Spring的工作原理,从而更好地优化应用、排查问题以及学习先进的设计模式。 1. **IoC(控制反转)与DI(依赖注入)** Spring的核心功能之一是依赖注入,它允许对象之间...
1. **@Controller**: 这个注解是定义一个类为Spring MVC的Controller。它标志着该类是一个处理HTTP请求的bean。通常,我们会在这个类中定义处理请求的方法,这些方法会使用其他的注解来指定请求映射。 2. **@...