SpringMVC内嵌Tomcat9免web.xml

家住魔仙堡 提交于 2020-03-10 16:32:33

目的

有时候需要一个小web项目,而懒得单独下载tomcat运行,想直接像springboot一样打包成一个可运行jar执行,方便快捷

原理

具体原理可百度嵌入式tomcat,这里就简单介绍一下

在Tomcat8以上版本支持一个配置启动的东西,意思就是tomcat启动时会自动去扫描所有 jar 中目录为「 META-INF/services/ 」中是否有个名字是「javax.servlet.ServletContainerInitializer」的配置文件,然后根据里面内容反编译启动等等一系列操作,具体如下图配置:

如上图配置后tomcat启动时就会自动生成HelloServlet了,大概原理就这样,不过SpringMVC已经把上图中的基本配置已经搞定直接使用即可,具体往下看

普通Maven项目的依赖

<properties>
    <spring.version>5.2.3.RELEASE</spring.version>
</properties>


    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>9.0.30</version>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <version>9.0.30</version>
        </dependency>

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

    </dependencies>

主要SpringMVC配置

Spring官网:https://docs.spring.io/spring/docs/5.0.14.RELEASE/spring-framework-reference/web.html#spring-web

代码中的 app.xml 是普通Spring项目的配置,关于SpringMVC配置就代码中已加入的注解式配置


public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    // 返回Spring应用根容器中定义的beans,对应ContextLoaderListener,是Spring根容器
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[]{RootConfig.class};
    }
    //protected Class<?>[] getRootConfigClasses() {
    //    return new Class[0];
    //}

    // 返回Spring MVC应用容器中定义的beans,对应DispatcherServlet中加载的bean
    // Spring MVC容器是根容器的子容器,子容器可以看到根容器中定义的beans,反之不行
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[]{ServletConfig.class};
    }

    // 指定映射拦截URL
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    // 修改 通过重写此方法修改DispatcherServlet的名称,对应<servlet-name></servlet-name>标签
    @Override
    protected String getServletName() {
        return super.getServletName();
    }

    @Override
    protected Filter[] getServletFilters() {
        return new Filter[]{new SimpleFilter()};
    }
}
@Configuration
@ImportResource(locations = "classpath:config/app.xml")
public class RootConfig {
    private final Logger logger = LoggerFactory.getLogger(RootConfig.class);

    @Bean
    public ApplicationContextAware applicationContextAware(ApplicationContext ctx) {
        return args -> {
            /**
            System.err.println("beans:");
            String[] beanNames = ctx.getBeanDefinitionNames();
            //Arrays.sort(beanNames);
            for (String beanName : beanNames) {
                System.err.println("---> " + beanName);
            }
             */
            System.out.println("Beans: " + ctx.getBeanDefinitionCount());
            logger.info("==========- 启动完成 -==========");
        };
    }

}
@Configuration
@EnableWebMvc //@EnableWebMvc 同等 WebMvcConfigurationSupport
@ComponentScan("com.*.*.web.controller")
public class ServletConfig {

    @Bean
    public ViewResolver viewResolver() { // 配置 视图解析器
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF");
        viewResolver.setSuffix(".jsp");
        viewResolver.setExposeContextBeansAsAttributes(true);
        //viewResolver.setOrder(0);
        //viewResolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);
        return viewResolver;
    }
}

 

Tomcat启动代码

package com.fourlambs.proxyip;

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.descriptor.web.ErrorPage;

import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;

/**
 * @Author yuwan [2020-02-07]
 * @Date February, 07, Friday
 * @Comment ...
 */
public class AppMain {

    static void testPort(int port) throws IOException {
        // 检测端口是否被占用
        ServerSocket socket = null;
        try {
            socket = new ServerSocket(port);
        } catch (IOException e) {
            System.err.println(port + " 端口已被占用");
            System.exit(0);
            return;
        } finally {
            socket.close();
        }
    }

    public static void main(String[] args) {
        int port = 8080;
        try {
            if (args.length > 0) {
                port = Integer.parseInt(args[0]);
            }
            testPort(port);

            // Windows系统上运行必须要有webapps文件夹,不然启动不了,辣鸡!
            String osName = System.getProperties().getProperty("os.name");
            if (osName.toLowerCase().contains("windows")) {
                String path = AppMain.class.getResource("/").getPath() + "/webapps";
                File file = new File(path);
                if (!file.exists()) {
                    file.mkdir();
                }
            }

            Tomcat tomcat = new Tomcat();
            //System.setProperty("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", "true");

            String baseDir = Thread.currentThread().getContextClassLoader().getResource("").getPath();

            tomcat.setBaseDir(baseDir);
            tomcat.setPort(port);

            Context ctx = tomcat.addWebapp("", baseDir);
            ctx.setParentClassLoader(Thread.currentThread().getContextClassLoader());
            //ctx.setLoader(new WebappLoader(Thread.currentThread().getContextClassLoader()));
            ctx.setRequestCharacterEncoding("UTF-8");

            ErrorPage ep = new ErrorPage();
            //ep.setErrorCode(404);
            ep.setLocation("/error");
            ctx.addErrorPage(ep);

            // 特殊资源
            //StandardRoot resources = new StandardRoot(ctx);
            //WebResourceSet resourceSet = new EmptyResourceSet(resources);
            //WebResourceSet resourceSet = new DirResourceSet(resources, "/", "/", "/");
            //resources.addPreResources(resourceSet);
            //ctx.setResources(resources);

            Connector connector = tomcat.getConnector();
            connector.setAttribute("maxThreads", 500);
            //connector.setAttribute("minSpareThreads", 2);

            //tomcat.enableNaming();
            tomcat.start();
            tomcat.getServer().await();
        } catch (Exception e) {
            System.err.println("启动错误 Error:" + e.getMessage());
            System.err.println("命令启动时第一个参数为端口号(默认端口" + port + ")");
            e.printStackTrace();
        }
    }


}

 

Tomcat简单嵌入重中之重就是上面的tomcat启动代码。。。。难点是官网没有文档,憋来没办法去研究源码。。。阿帕奇是个大坑比!!

重点代码已列出来了,仅供学习参考!高级的tomcat配置及使用建议最好还是老老实实下载tomcat来运行和配置

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!