Springboot之---强大的Servlet(三)

简介: 如今回头看下Servlet不仅如此强大,还具有很强烈的参考意义,能在现如今流行的大部分框架中找到它的影子。下面文章不止与探索Servlet,可能在其中穿插其他的关联知识点,旨在能从此次的学习中获取更多的知识点参考资料总结,转化为自己的理解输出,在文中我尽量以截图+复制全限定类名的方式记录,以便感兴趣的再次查找。

AnnotationConfigWebApplicationContext

流程
AnnotationConfigWebApplicationContext-->WebApplicationContext-->ApplicationContext
核心方法:loadBeanDefinitions

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
        //加载Bean
        AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
        //扫描注解
        ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
        //装配Bean
        BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
        if (beanNameGenerator != null) {
            reader.setBeanNameGenerator(beanNameGenerator);
            scanner.setBeanNameGenerator(beanNameGenerator);
            //注册Bean
            beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
        }

        ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
        if (scopeMetadataResolver != null) {
            reader.setScopeMetadataResolver(scopeMetadataResolver);
            scanner.setScopeMetadataResolver(scopeMetadataResolver);
        }

        if (!this.annotatedClasses.isEmpty()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Registering annotated classes: [" +
                        StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
            }
            //注册Bean
            reader.register(ClassUtils.toClassArray(this.annotatedClasses));
        }

        if (!this.basePackages.isEmpty()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Scanning base packages: [" +
                        StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
            }
            //扫描指定基包
            scanner.scan(StringUtils.toStringArray(this.basePackages));
        }

        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            for (String configLocation : configLocations) {
                try {
                    Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
                    if (logger.isTraceEnabled()) {
                        logger.trace("Registering [" + configLocation + "]");
                    }
                    reader.register(clazz);
                }
                catch (ClassNotFoundException ex) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Could not load class for config location [" + configLocation +
                                "] - trying package scan. " + ex);
                    }
                    int count = scanner.scan(configLocation);
                    if (count == 0 && logger.isDebugEnabled()) {
                        logger.debug("No annotated classes found for specified class/package [" + configLocation + "]");
                    }
                }
            }
        }
    }

BeanPostProcessor(后置处理器)

public interface BeanPostProcessor {

    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}

在上面的context中随处可见对BeanPostProcessor的方法调用,用于检查标记接口或用代理封装,在Bean对象在实例化和依赖注入完毕后调用,第三方扩展功能均会实现此接口,在Bean的初始化时,通过InitializingBean来调用afterPropertiesSet方法。

ApplicationContextAware

在某些特殊的情况下,Bean需要实现某个功能,但该功能必须借助于Spring容器才能实现,此时就必须让该Bean先获取Spring容器,然后借助于Spring容器实现该功能。为了让Bean获取它所在的Spring容器,可以让该Bean实现ApplicationContextAware接口。ApplicationContextAware 通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware接口中的setApplicationContext方法。在ApplicationContextAware的实现类中,就可以通过这个上下文环境对象得到Spring容器中的Bean。看到—Aware就知道是干什么的了,就是属性注入的,但是这个ApplicationContextAware的不同地方在于,实现了这个接口的bean,当spring容器初始化的时候,会自动的将ApplicationContext注入进来。

public interface ApplicationContextAware extends Aware {
    /*
        设置此对象在其中运行的ApplicationContext。通常,此调用将用于初始化对象。
    */
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

@Component
public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        //setContext
        applicationContext = context;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    //获取Bean
    public static <T> T getBean(Class<T> requiredType){
        return getApplicationContext().getBean(requiredType);
    }
    public static <T> T getBean(String name){
        return (T) getApplicationContext().getBean(name);
    }
}

ResourceLoaderAware

ResourceLoaderAware是特殊的标记接口,它希望拥有一个ResourceLoader 引用的对象。

public interface ResourceLoaderAware {
   void setResourceLoader(ResourceLoader resourceLoader);
}

当实现了 ResourceLoaderAware接口的类部署到application context(比如受Spring管理的bean)中时,它会被application context识别为 ResourceLoaderAware。 接着application context会调用setResourceLoader(ResourceLoader)方法,并把自身作为参数传入该方法(记住,所有Spring里的application context都实现了ResourceLoader接口)。

既然 ApplicationContext 就是ResourceLoader,那么该bean就可以实现 ApplicationContextAware接口并直接使用所提供的application context来载入资源,但是通常更适合使用特定的满足所有需要的 ResourceLoader实现。 这样一来,代码只需要依赖于可以看作辅助接口的资源载入接口,而不用依赖于整个Spring ApplicationContext 接口。

从Spring 2.5开始, 你可以使用ResourceLoader 的自动装配来代替实现 ResourceLoaderAware 接口。“传统的” constructor及 byType的自动装配模式 (第 3.3.5 节 “自动装配(autowire)协作者”已有论述)现在可以分别为构造方法参数及setter方法参数提供 ResourceLoader 类型的依赖。请使用新式的基于注解的自动装配特性以提供更大的灵活性(包括装配属性及多个方法参数的能力)。在这种情况下,只要属性、构造方法或者方法被 @Autowired注解修饰,ResourceLoader 就会被装配到需要ResourceLoader类型的属性、构造方法参数或者方法参数中

Servlet与HttpServlet

流程
类图标明很是明显,在这个图中展示了servlet,tomcat,Springboot的关系,完美解释了那句Springboot是内嵌了tomcat的嵌入式引擎,嵌入式容器的说法~

而HttpServlet即是大部分请求的处理对象,嵌入式引擎---->嵌入式容器---->webfilter---->weblistener
javax.servlet.ServletContext#addServlet(java.lang.String, java.lang.Class<? extends javax.servlet.Servlet>)返回一个ServletRegistration对象,可用于进一步
配置已注册的servlet
javax.servlet.ServletRegistration
public interface ServletRegistration extends Registration {

    /**
     * TODO
     * @param urlPatterns The URL patterns that this Servlet should be mapped to
     * @return TODO
     * @throws IllegalArgumentException if urlPattern is null or empty
     * @throws IllegalStateException if the associated ServletContext has
     *                                  already been initialised
     */URL必须映射
    public Set<String> addMapping(String... urlPatterns);

    public Collection<String> getMappings();

    public String getRunAsRole();

    public static interface Dynamic
    extends ServletRegistration, Registration.Dynamic {
        public void setLoadOnStartup(int loadOnStartup);
        public Set<String> setServletSecurity(ServletSecurityElement constraint);
        public void setMultipartConfig(MultipartConfigElement multipartConfig);
        public void setRunAsRole(String roleName);
    }
}

思考:为什么Applacationcontext会有那么多重载方法?

 @Override
    public ServletRegistration.Dynamic addServlet(String servletName, String className) {
        return addServlet(servletName, className, null, null);
    }


    @Override
    public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
        return addServlet(servletName, null, servlet, null);
    }


    @Override
    public ServletRegistration.Dynamic addServlet(String servletName,
            Class<? extends Servlet> servletClass) {
        return addServlet(servletName, servletClass.getName(), null, null);
    }

--用在不同场景下解决同一类问题
而在HttpServlet中的关键方法service可看到平时请求接口的所有方法
流程
流程

目录
相关文章
|
1月前
|
缓存 Java Spring
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
文章比较了在Servlet和Spring Boot中获取Cookie、Session和Header的方法,并提供了相应的代码实例,展示了两种方式在实际应用中的异同。
158 3
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
|
4月前
|
XML Java 应用服务中间件
springboot定制嵌入式的servlet
SpringBoot允许定制嵌入式Servlet容器,如修改配置或更换默认的Tomcat。配置可通过`application.properties`设置`server.port`和`server.tomcat.*`属性。此外,可创建`EmbeddedServletContainerCustomizer` Bean来自定义容器,例如改变端口。要替换默认的Tomcat,需排除`spring-boot-starter-tomcat`依赖,并引入`spring-boot-starter-jetty`。
|
5月前
|
Java 应用服务中间件 容器
手写SpringBoot(二)之动态切换Servlet容器
我们在切换serlvet容器的时候,会将SpringBoot默认的tomcat jar包给排除掉,换上我们需要的jar包,比如jetty。
40 0
|
Java 应用服务中间件 容器
25 SpringBoot使用外置的Servlet容器
25 SpringBoot使用外置的Servlet容器
52 0
|
6月前
|
Java 应用服务中间件 Maven
框架的优点(SpringBoot VS Servlet)
框架的优点(SpringBoot VS Servlet)
|
6月前
|
前端开发 Java 容器
SpringBoot中注册Servlet、Filter和Listener(代码和注解两种方式)
SpringBoot中注册Servlet、Filter和Listener(代码和注解两种方式)
126 0
|
前端开发 Java 应用服务中间件
24 SpringBoot配置嵌入式Servlet容器
24 SpringBoot配置嵌入式Servlet容器
81 0
24 SpringBoot配置嵌入式Servlet容器
|
Java API Spring
在spring boot中添加servlet filter *Listener
在spring boot中添加servlet filter *Listener
在spring boot中添加servlet filter *Listener
|
消息中间件 负载均衡 Java
Springboot之---强大的Servlet(十 一)
如今回头看下Servlet不仅如此强大,还具有很强烈的参考意义,能在现如今流行的大部分框架中找到它的影子。下面文章不止与探索Servlet,可能在其中穿插其他的关联知识点,旨在能从此次的学习中获取更多的知识点参考资料总结,转化为自己的理解输出,在文中我尽量以截图+复制全限定类名的方式记录,以便感兴趣的再次查找。
114 0
|
消息中间件 SQL 缓存
Springboot之---强大的Servlet(十)
如今回头看下Servlet不仅如此强大,还具有很强烈的参考意义,能在现如今流行的大部分框架中找到它的影子。下面文章不止与探索Servlet,可能在其中穿插其他的关联知识点,旨在能从此次的学习中获取更多的知识点参考资料总结,转化为自己的理解输出,在文中我尽量以截图+复制全限定类名的方式记录,以便感兴趣的再次查找。
144 0