设为首页 加入收藏

TOP

Spring源码探究:容器(四)
2018-12-13 10:09:53 】 浏览:576
Tags:Spring 源码 探究 容器
问题是,“在项目中,自定义切面注解在 Controller 层正常工作,却在 Service 层无法正常工作?”看完这个,其实并没有解答该问题,咱们下面继续看 SpringMVC Bean的加载流程,看完 SpringMVC 后,答案会自动浮出水面。


SpringMVC 容器 Bean 加载流程

同样,从 web.xml 中的 SpringMVC 配置出发,里面有 DispatcherServlet,这是 SpringMVC 的入口,跟进之后发现方法较多,无法知道会执行哪个方法。但是咱们要记住,DispatcherServlet 本质上是一个 Servlet,通过它的继承关系图也可以证明:

DispatcherServlet继承关系图

看一下 Servlet 的接口:

public interface Servlet {
    public void init(ServletConfig config) throws ServletException;
    public ServletConfig getServletConfig();
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
    public String getServletInfo();
    public void destroy();
}

从 Servlet 接口方法中可以看出,Servlet 的入口是 init 方法,层层跟进(一定要根据 DispatcherServlet 继承图跟进),进入到了 FrameworkServlet 的 initServletBean() 方法,进入方法,贴出重点代码:

this.webApplicationContext = initWebApplicationContext();

字面理解,初始化 SpringMVC Web容器,进入探究:

WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

前面咱们提到,Spring 容器初始化完成之后,放入了 servletContext 中。这里又从 servletContext 获取到了 Spring 容器

wac = createWebApplicationContext(rootContext);

字面理解创建 Web 应用容器,且参数是 Spring 容器。跟进方法:

ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

创建web应用容器,即咱们所理解的 SpringMVC 容器在此创建了;

wac.setParent(parent);

这里是重点,SpringMVC 容器将 Spring 容器设置成了自己的父容器

configureAndRefreshWebApplicationContext(wac);

这个方法刚才在分析 Spring Bean 加载流程时,分析过了。其中有一段,前面说,“暂且跳过,后续会回来分析这一段”。现在开始分析:

在 AbstractBeanFactory 类 doGetBean 方法,有这么一段:

// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    // Not found -> check parent.
    String nameToLookup = originalBeanName(name);
    if (args != null) {
            // Delegation to parent with explicit args.
        return (T) parentBeanFactory.getBean(nameToLookup, args);
    }
    else {
        // No args -> delegate to standard getBean method.
        return parentBeanFactory.getBean(nameToLookup, requiredType);
    }
}

这里其实是在获取父容器中的 Bean,若获取到,直接拿到 Bean,这个方法就结束了。结论:子容器可以使用父容器里的 Bean,反之则不行。


现在来解答咱们的问题

<bean class="com.foo.service.processor.PrintTimeProcessor"/>

当上门这句话放在 springmvc.xml 中时,名为 “printTimeProcessor” 的 Bean 会存在于 SpringMVC 容器,那么 Spring 容器是无法获取它的。而 Service 层恰巧是存在于 Spring 容器中,所以 “printTimeProcessor” 切面对 Service 层不起作用。而 Controller 层本身存在于 SpringMVC 容器,所以 Controller 层可以正常工作。而当它放在 spring.xml 中时,”printTimeProcessor” 是存在于 Spring 容器中,SpringMVC 容器是 Spring 容器的子容器,子容器可以获取到父容器的 Bean,所以 Controller 层与 Service 层都能获取到该 Bean,所有都能正常使用它。

首页 上一页 1 2 3 4 下一页 尾页 4/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇从零开始用好Maven:从HelloWorld.. 下一篇每周10道Java面试题:面向对象, ..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目