springmvc零配置

springmvc零配置

spring之前都是采用spring.xml,springmvc.xml,web.xml三个配置文件完成web项目配置,但是随着注解开发的应用升级,逐渐抛弃了这种繁重的xml风格开发,本文主要介绍mvc零配置原理以及spring boot的雏形

mvc零配置

官方给我们如下代码替换掉web.xml

public class LryWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletCxt) {
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig1.class);
//        ac.refresh();//这行代码在我电脑上跑会出错,原因未知,另外我好奇的是注释掉这行代码spring的环境是怎么初始化完成的
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
}

AppConfig1

@Configuration
@ComponentScan("com.lry")
@EnableWebMvc
public class AppConfig1 implements WebMvcConfigurer {
	
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/page/", ".html");
    }
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new FastJsonHttpMessageConverter());
    }

}

HelloController

@Controller
public class HelloController {

    @GetMapping("hello")
    @ResponseBody
    public String hello(){
        return "hello SpringMVC";
    }

    @GetMapping("user")
    @ResponseBody
    public User user(){
        User user = new User("lry",20);
        return user;
    }

    @GetMapping("index")
    public String index(){
        return "index";
    }

}

pom依赖

 <dependencies>
        <!--spring -core-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.9.RELEASE</version>
        </dependency>

        <!--web-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.9.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>8.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-el</artifactId>
            <version>8.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <version>8.5.5</version>
        </dependency>

	 <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.47</version>
    </dependency>
    </dependencies>

就上面三个类就完成了mvc的环境,一个xml都没有。

servlet3新特性

思考上面例子如下问题:LryWebApplicationInitializer 的onStartup是如何被调用到的
我们可以给onStartup方法打个断点,看看调用链,结果发现如下类

@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {
	
    public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
    	遍历webAppInitializerClasses反射调用每一个WebApplicationInitializer的onStartup方法
    }
}

上述代码属于servlet3的新特性,只要我们在resources下建一个 META-INF.services文件夹,里面添加一个文件名字为javax.servlet.ServletContainerInitializer的文件,文件内容是实现ServletContainerInitializer接口的类的全路径。

例如spring-web的下图
在这里插入图片描述
这个文件的内容是org.springframework.web.SpringServletContainerInitializer

tomcat启动的时候会执行SpringServletContainerInitializer的onStartup方法,并且会把实现@HandlesTypes里面的value接口的所有类找到给onStartup的第一个参数webAppInitializerClasses,然后spring遍历webAppInitializerClasses回调onStartup方法就会执行到LryWebApplicationInitializer 。

我们可以自己写一个MySpringServletContainerInitializer 实现ServletContainerInitializer ,然后把MySpringServletContainerInitializer的全路径配置到那个文件中,tomcat启动也会帮我们执行
示例如下

@HandlesTypes({MyWebApplicationInitializer.class})
public class MySpringServletContainerInitializer implements ServletContainerInitializer {
    @Override
    public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
        Iterator<Class<?>> it = webAppInitializerClasses.iterator();
        while (it.hasNext()) {
            Class clazz = it.next();
            try {

                MyWebApplicationInitializer myWebApplicationInitializer = (MyWebApplicationInitializer) clazz.newInstance();

                myWebApplicationInitializer.onStartup(servletContext);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

    }
}



public class LiuWebApplicationInitializer implements MyWebApplicationInitializer{
    @Override
    public void onStartup(ServletContext servletContext) {
//        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
//        ac.register(AppConfig1.class);
////        ac.refresh();
//
//        DispatcherServlet servlet = new DispatcherServlet(ac);
//        ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
//        registration.setLoadOnStartup(1);
//        registration.addMapping("/");
    }
}





public interface MyWebApplicationInitializer {

    void onStartup(ServletContext servletContext) throws ServletException;

}

内嵌tomcat

public class MySpringApplication {
    public static void main(String[] args) throws ServletException {
        MySpringApplication.run();
    }
    public static void run() throws ServletException {
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8080);
        String sourcePath = MySpringApplication.class.getResource("/").getPath();

        //告訴tomcat你的源碼在哪裏
        Context ctx = tomcat.addWebapp("/",new File("src/main/webapp").getAbsolutePath());
        WebResourceRoot resources = new StandardRoot(ctx);
        resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/classes",

                sourcePath, "/"));
        ctx.setResources(resources);
        try {
            tomcat.start();
            tomcat.getServer().await();
        } catch (LifecycleException e) {
            e.printStackTrace();
        }
    }
}

这段代码会去调用SpringServletContainerInitializer 的 onStartup方法,我们只需要把这段代码加上,上面代码都不用改,就可以代替外部tomcat执行

发布了164 篇原创文章 · 获赞 81 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/LiuRenyou/article/details/104170894