基于注解的springmvc开发

原理简析

1. 背景知识:org.springframework.web.ServletContainerInitializer接口

org.springframework.web.ServletContainerInitializer接口在基于注解的springmvc开发中用于代替web.xml。它只有一个方法:onStartup,可以在其中注册servlet、拦截器(Filter)、监听器(Listener)这三大组件。另外,ServletContainerInitializer还可以使用@HandlesTypes在onStartup方法的参数列表中注入感兴趣的类。servlet容器启动时,会扫描每个jar包的项目根目录下的/META-INF/services/javax.servlet.ServletContainerInitializer文件,执行这个文件中指定的ServletContainerInitializer接口的实现类的onStartup方法。

2. org.springframework.web包提供的ServletContainerInitializer实现类

org.springframework.web包的/META-INF/services/javax.servlet.ServletContainerInitializer文件指定了ServletContainerInitializer接口的实现类:SpringServletContainerInitializer,首先来看一下这个类的spring源码:

package org.springframework.web;

@HandlesTypes(WebApplicationInitializer.class)  //(1)
public class SpringServletContainerInitializer implements ServletContainerInitializer {

    @Override
    public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
            throws ServletException {

        List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();

        if (webAppInitializerClasses != null) {
            for (Class<?> waiClass : webAppInitializerClasses) {
                // Be defensive: Some servlet containers provide us with invalid classes,
                // no matter what @HandlesTypes says...
                if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
                        WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                    try {
                        initializers.add((WebApplicationInitializer) waiClass.newInstance());  //(2)
                    }
                    catch (Throwable ex) {
                        throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
                    }
                }
            }
        }

        if (initializers.isEmpty()) {
            servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
            return;
        }

        servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
        AnnotationAwareOrderComparator.sort(initializers);
        for (WebApplicationInitializer initializer : initializers) {
            initializer.onStartup(servletContext);  //(3)
        }
    }

}

(1) 通过@HandlesType注解在onStartup方法的参数列表中注入感兴趣的类,即WebApplicationInitializer;

(2) 将WebApplicationInitializer的每个实现类,都新建一个实例,并放入initializers列表中;

(3) 遍历initializers列表,对每个WebApplicationInitializer实例执行其onStartup方法。

下一个问题是:WebApplicationInitializer有哪些实现类,是用来干什么的?

扫描二维码关注公众号,回复: 6116547 查看本文章

3. WebApplicationInitializer的实现类

WebApplicationInitializer的实现类有很多,重点看一下AbstractAnnotationConfigDispatcherServletInitializer

package org.springframework.web.servlet.support;

public abstract class AbstractAnnotationConfigDispatcherServletInitializer
        extends AbstractDispatcherServletInitializer {

    @Override
    @Nullable
    protected WebApplicationContext createRootApplicationContext() {
        Class<?>[] configClasses = getRootConfigClasses();
        if (!ObjectUtils.isEmpty(configClasses)) {
            AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
            context.register(configClasses);
            return context;
        }
        else {
            return null;
        }
    }

    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        Class<?>[] configClasses = getServletConfigClasses();
        if (!ObjectUtils.isEmpty(configClasses)) {
            context.register(configClasses);
        }
        return context;
    }

    @Nullable
    protected abstract Class<?>[] getRootConfigClasses();

    @Nullable
    protected abstract Class<?>[] getServletConfigClasses();

}

这个类提供了两个方法的实现,以及两个抽象方法供子类继承

(1) createRootApplicationContext:创建根容器;

(2) createServletApplicationContext:创建servlet容器;

(3) getRootConfigClasses:抽象类,用于注册根容器的配置类,相当于spring.xml;

(4) getServletConfigClasses:抽象的类,用于注册servlet容器的配置类,相当于springmvc.xml;

另外,它还从AbstractDispatcherServletInitializer类继承了getServletMappings方法,用于注册servlet的映射。

因此,我们可以自定义一个WebApplicationInitializer,继承AbstractAnnotationConfigDispatcherServletInitializer;在servlet容器启动时,会创建spring根容器和servlet容器,代替web.xml配置文件。

4. 根容器和servlet容器

根容器用于管理@Service、@Repository等业务逻辑层和数据库交互层组件;

servlet容器用于管理@Controller、ViewResolver、HandlerMapping等跟页面处理有关的组件。

使用步骤

0. 导包或添加依赖:spring-web、spring-webmvc

1. 编写数据库访问层、业务逻辑层、控制层等组件,这个跟基于配置文件的springmvc没有区别;

2. 编写根容器和servlet容器的配置类,这里不需要添加@Configuration注解;

3. 自定义WebApplicationInitializer实现类,继承AbstractAnnotationConfigDispatcherServletInitializer;

4. 在3的实现类中注册根容器和servlet容器的配置类,以及servlet映射。

示例Demo

猜你喜欢

转载自www.cnblogs.com/dubhlinn/p/10808879.html