Springboot之强大的Servlet「二」

举报
赵KK日常技术记录 发表于 2023/06/29 21:18:17 2023/06/29
【摘要】 接上篇文章,上篇文中讲到了上下文与监听器的简单分析,接下来详细介绍请求与响应的细节。ContextLoaderServlet与下文中的ContextLoaderListener功能完全相同12345678<servlet> <servlet-name>context</servlet-name> <servlet-class> org.sp...

接上篇文章,上篇文中讲到了上下文与监听器的简单分析,接下来详细介绍请求与响应的细节。


ContextLoaderServlet与下文中的ContextLoaderListener功能完全相同

1
2
3
4
5
6
7
8

<servlet>
         <servlet-name>context</servlet-name>
         <servlet-class>
           org.springframework.web.context.ContextLoaderServlet
         </servlet-class>
         <load-on-startup>1</load-on-startup>
</servlet> 

HttpServletResponse响应码


监听器: 实现接口、标记

比如MQ,观察者模式,所有的时间监听都会继承 extend java.util.EventListener接口,但里面什么都没有,称之为mark接口,经典实现:ContextLoaderListener、RequestContextListener(重要)

1
2
3
4
5
6
7
/**
 * A tagging interface that all event listener interfaces must extend.
 * @since 1.1
 */
public interface EventListener {
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.
 * Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
 *
 * <p>As of Spring 3.1, {@code ContextLoaderListener} supports injecting the root web
 * application context via the {@link #ContextLoaderListener(WebApplicationContext)}
 * constructor, allowing for programmatic configuration in Servlet 3.0+ environments.
 * See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
 *
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 17.02.2003
 * @see #setContextInitializers
 * @see org.springframework.web.WebApplicationInitializer
 */
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {


}

见名知意既然包含contextLoader必然跟上线文息息相关,在初始化容器时加载配置~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

@Override
    public void requestInitialized(ServletRequestEvent requestEvent) {
        if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
            throw new IllegalArgumentException(
                    "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
        }
        HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
        ServletRequestAttributes attributes = new ServletRequestAttributes(request);
        request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
        //将请求对象放入ThreadLocal中
        LocaleContextHolder.setLocale(request.getLocale());
        RequestContextHolder.setRequestAttributes(attributes);
    }

重要:Servlet在同一个线程中,当初始化时放到对象里,当请求销毁时,自动将Threadlocal对象销毁,防止了内存泄漏的问题
当有请求到达时,会从线程池中取出一个线程来执行任务,执行完毕后再将线程回收至线程池,这样当前请求不可能拿到上一个请求保存在ThreadLocal对象里的值


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

@Override
    public void requestDestroyed(ServletRequestEvent requestEvent) {
        ServletRequestAttributes attributes = null;
        Object reqAttr = requestEvent.getServletRequest().getAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE);
        if (reqAttr instanceof ServletRequestAttributes) {
            attributes = (ServletRequestAttributes) reqAttr;
        }
        RequestAttributes threadAttributes = RequestContextHolder.getRequestAttributes();
        if (threadAttributes != null) {
            // We're assumably within the original request thread...
            LocaleContextHolder.resetLocaleContext();
            RequestContextHolder.resetRequestAttributes();
            if (attributes == null && threadAttributes instanceof ServletRequestAttributes) {
                attributes = (ServletRequestAttributes) threadAttributes;
            }
        }
        if (attributes != null) {
            attributes.requestCompleted();
        }
    }


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
 * Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.
 * Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
 *
 * <p>As of Spring 3.1, {@code ContextLoaderListener} supports injecting the root web
 * application context via the {@link #ContextLoaderListener(WebApplicationContext)}
 * constructor, allowing for programmatic configuration in Servlet 3.0+ environments.
 * See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
 *
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 17.02.2003
 * @see #setContextInitializers
 * @see org.springframework.web.WebApplicationInitializer
 */
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

}

插播一句:在书写过程中发现某URL响应变慢,在分析SQL时,用到了in查询,执行分析计划用到了索引

Servlet on Springboot

组件声明注解:

servletContext—ApplicationContext

组件扫描:ServletComponentScan

熟悉波~ 是不是应用跟Springboot的@ComponentScan如出一辙

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServletComponentScanRegistrar.class)
public @interface ServletComponentScan {

    /**
     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
     * declarations e.g.: {@code @ServletComponentScan("org.my.pkg")} instead of
     * {@code @ServletComponentScan(basePackages="org.my.pkg")}.
     * @return the base packages to scan
     */
    @AliasFor("basePackages")
    String[] value() default {};

    /**
     * Base packages to scan for annotated servlet components. {@link #value()} is an
     * alias for (and mutually exclusive with) this attribute.
     * <p>
     * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
     * package names.
     * @return the base packages to scan
     */
    @AliasFor("value")
    String[] basePackages() default {};

    /**
     * Type-safe alternative to {@link #basePackages()} for specifying the packages to
     * scan for annotated servlet components. The package of each class specified will be
     * scanned.
     * @return classes from the base packages to scan
     */
    Class<?>[] basePackageClasses() default {};

}

配置声明:@interface 暴露SpringBean @Bean
事件:Event

filter:

webFilter
OncePerRequestFilter:只调用一次且是线程安全的
而其子类得
ApplicationContextHeaderFilter调用的dofilter方法就是我们上面提到的真正在请求中执行的filter

激活Springbootweb


文无第一,武无第二,没有最好的技术框架或体系,只有最适合当下业务的框架或体系
谈谈你对技术的理解:天上飞的理念,必定有落地的实现

组装SpringApplicationBuilder

你看看这名字就知道他以后干啥的,并且它包含了太多太多的东西,
SpringApplication和ApplicationContext实例的生成器,基本包含了所有的SpringbootApplacation特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private final SpringApplication application;

private ConfigurableApplicationContext context;

private SpringApplicationBuilder parent;
AtomicBoolean是不是的看看
private final AtomicBoolean running = new AtomicBoolean(false);

private final Set<Class<?>> sources = new LinkedHashSet<>();

private final Map<String, Object> defaultProperties = new LinkedHashMap<>();

private ConfigurableEnvironment environment;

private Set<String> additionalProfiles = new LinkedHashSet<>();

private boolean registerShutdownHookApplied;

private boolean configuredAsChild = false;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@SpringBootApplication
public class TestProfiles {
 
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(TestProfiles.class)
                .properties("spring.config.location=classpath:/test-profiles.yml")
                .properties("spring.profiles.active=oracle")
                .run(args);
        // 输出变量
        System.out.println(context.getEnvironment().getProperty("jdbc.driver"));
 
        // 启动第二个Spring容器,指定端口为8848
        ConfigurableApplicationContext context2 = new SpringApplicationBuilder(TestProfiles.class)
                .properties("spring.config.location=classpath:/test-profiles.yml")
                .properties("spring.profiles.active=mysql")
                .properties("server.port=8848")
                .run(args);
        // 输出变量
        System.out.println(context2.getEnvironment().getProperty("jdbc.driver"));
    }
}

Springboot自动装配

/META-INF/spring.factories

XXXAotuConfigration
NIO不是异步IO而是非阻塞IO
java9推崇模块化

ClassLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args) {
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    while (true) {

        System.out.println(contextClassLoader.getClass().getName());
        ClassLoader parent = contextClassLoader.getParent();
        if (parent == null) {
            break;
        }

    }

    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    System.out.println(systemClassLoader.getClass().getName());
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。