Spring Boot學習4:web篇(下)-Spring boot (Servlet,Jsp)學習

一枚程式設計師發表於2018-02-08
1.傳統Servlet回顧
什麼是Servlet:小服務端應用,是一種基於Java的web元件,用於生成動態內容,由容器管理。servlet是平臺無關的java類組成,並且由Java web伺服器載入執行


什麼是Servlet容器?

Filter生命週期

Servlet生命週期

2.Servlet On Spring Boot
1)Servlet元件掃描
org.springframework.boot.web.servlet.ServletComponentScan
指定包路徑掃描
指定類掃描



2)註解方式註冊
2.1)Servlet

2.1.1)Servlet元件掃描
例1:建立專案spring-boot-lesson-4
建立一個包servlet,建立一個Servlet:MyServlet,並繼承HttpServlet

@WebServlet(
        name="myServlet",   //servlet名稱
        urlPatterns = "/myServlet"  //url對映路徑
)
public class MyServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Writer writer = resp.getWriter();
        writer.write("<html><body><h1>hello world</h1></body></html>");
        //super.doGet(req, resp);
    }
}


然後在SpringBoot的啟動程式SpringBootLesson4Application中,掃描Servlet元件進行註冊

@SpringBootApplication
@ServletComponentScan(basePackages = {"servlet"})
public class SpringBootLesson4Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootLesson4Application.class, args);
    }
}


啟動Spring Boot訪問localhost:8080/myServlet,就可以看到Hello World顯示在介面上



2.1.2)如果希望加上初始化引數呢?
        initParams = {
                @WebInitParam(name="myName", value="myValue" )
        }
例2:
@WebServlet(
        name="myServlet",
        urlPatterns = "/myServlet",
        initParams = {
                @WebInitParam(name="myName", value="myValue" )
        }
)
public class MyServlet extends HttpServlet {

    private String value;
    @Override
    public void init(ServletConfig config) throws ServletException {
        value = config.getInitParameter("myName");
    }

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        Writer writer = resp.getWriter();
        writer.write("<html><body><h1>hello world</h1><br/><h2>myValue:"+value+"</h2></body></html>");

        //super.doGet(req, resp);
    }
}

2.2)Filter
OncePerRequestFilter:這是一個實現Filter的抽象類
例1:建立包,建立Filter類:MyFilter,並實現OncePerRequestFilter
我們可以針對某個Servlet進行過濾
servletNames="myServlet"
和urlPattern = "/myServlet" 兩者的配置效果是一樣的,一個是servletName的過來,一個是url的過來

@WebFilter(
        servletNames= "myServlet"
)
public class MyFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        ServletContext servletContext = request.getServletContext();
        servletContext.log("/myServlet is filting");
        filterChain.doFilter(request,response);
    }
}


修改Spring Boot啟動程式上的掃描包,新增Filter包的掃描,或者擴大掃描範圍

@SpringBootApplication
@ServletComponentScan(basePackages = {"com/segmentfault"})
public class SpringBootLesson4Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootLesson4Application.class, args);
    }
}



重新整理3次,就有3次日誌:
2018-02-06 14:32:46.900  INFO 8232 --- [nio-8080-exec-3] o.a.c.c.C.[Tomcat].[localhost].[/]       : /myServlet is filting
2018-02-06 14:32:47.088  INFO 8232 --- [nio-8080-exec-5] o.a.c.c.C.[Tomcat].[localhost].[/]       : /myServlet is filting
2018-02-06 14:32:47.289  INFO 8232 --- [nio-8080-exec-9] o.a.c.c.C.[Tomcat].[localhost].[/]       : /myServlet is filting

2.3)監聽器
實現Request的監聽,

例子:

@WebListener
public class MyServletRequestListener implements ServletRequestListener {

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        ServletContext servletContext = sre.getServletContext();
        servletContext.log("/myListener is initialized..");
    }
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        ServletContext servletContext = sre.getServletContext();
        servletContext.log("/myListener is destroyed..");
    }

}

執行程式:我們可以看出servlet,filter和listener執行的順序,並且都是在一個執行緒中執行的。
2018-02-08 10:19:46.576  INFO 20224 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : /myListener is initialized..
2018-02-08 10:19:46.578  INFO 20224 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : /myServlet is filting
2018-02-08 10:19:46.578  INFO 20224 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : /myServlet is doGet...
2018-02-08 10:19:46.578  INFO 20224 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : /myListener is destroyed..



3)Spring Boot API方式註冊

建立spring.segmentfault.setvlet,spring.segmentfault.filter,spring.segmentfault.listener三個包
並建立3個類Servlet2,Filter2,Listener2
public class Servlet2 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = req.getServletContext();
        servletContext.log("myServlet2 doGet...");
        Writer writer = resp.getWriter();
        writer.write("hello world2");
    }
}



public class Filter2 extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        ServletContext servletContext = request.getServletContext();
        servletContext.log("/myFilter2 is filtering");
        filterChain.doFilter(request,response);
    }
}



public class Listener2 implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        ServletContext servletContext = sre.getServletContext();
        servletContext.log("myListener2 is destroyed");
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        ServletContext servletContext = sre.getServletContext();
        servletContext.log("myListener2 is initialized");
    }
}


在springboot啟動程式中,我們可以註冊servlet,filter,listener元件

@SpringBootApplication
@ServletComponentScan(basePackages = {"com/segmentfault"})
public class SpringBootLesson4Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootLesson4Application.class, args);
    }


    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        servletRegistrationBean.setName("myServlet2");
        servletRegistrationBean.setServlet(new Servlet2());
        servletRegistrationBean.addUrlMappings("/spring/myServlet2");
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new Filter2());
        filterRegistrationBean.setName("myFilter2");
        filterRegistrationBean.addServletNames("myServlet2");
        //設定請求方式過濾
        filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST,DispatcherType.FORWARD,DispatcherType.INCLUDE);
        return filterRegistrationBean;
    }

    @Bean
    public ServletListenerRegistrationBean servletListenerRegistrationBean(){
        ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
        servletListenerRegistrationBean.setListener(new Listener2());
        return servletListenerRegistrationBean;
    }
}



此時我們訪問http://localhost:8080/spring/myServlet2
控制檯列印,這樣我們就實現了spring boot api方式註冊servlet,filter,listener元件
2018-02-08 10:13:02.857  INFO 7648 --- [nio-8080-exec-8] o.a.c.c.C.[Tomcat].[localhost].[/]       : myListener2 is initialized
2018-02-08 10:13:02.858  INFO 7648 --- [nio-8080-exec-8] o.a.c.c.C.[Tomcat].[localhost].[/]       : /myListener is initialized..
2018-02-08 10:13:02.860  INFO 7648 --- [nio-8080-exec-8] o.a.c.c.C.[Tomcat].[localhost].[/]       : /myFilter2 is filtering
2018-02-08 10:13:02.860  INFO 7648 --- [nio-8080-exec-8] o.a.c.c.C.[Tomcat].[localhost].[/]       : myServlet2 doGet...
2018-02-08 10:13:02.860  INFO 7648 --- [nio-8080-exec-8] o.a.c.c.C.[Tomcat].[localhost].[/]       : /myListener is destroyed..
2018-02-08 10:13:02.861  INFO 7648 --- [nio-8080-exec-8] o.a.c.c.C.[Tomcat].[localhost].[/]       : myListener2 is destroyed






對於RequestContextHolder的理解
裡面儲存著ServletRequestAttribute,放在ThreadLocal中,這樣,在一個執行緒中都可以獲取到同一個物件,同時,在request結束的時候,就會銷燬ThreadLocal中的物件
區域性原始碼:
public abstract class RequestContextHolder  {

    private static final boolean jsfPresent =
            ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());

    private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
            new NamedThreadLocal<RequestAttributes>("Request attributes");

    private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
            new NamedInheritableThreadLocal<RequestAttributes>("Request context");


銷燬的時候:

/**
 * Reset the RequestAttributes for the current thread.
 */
public static void resetRequestAttributes() {
    requestAttributesHolder.remove();
    inheritableRequestAttributesHolder.remove();
}



例子:我們在Filter2加一個方法doSomething,在方法中通過RequestContextHolder獲取到request物件,並進行相關操作

public class Filter2 extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        doSomething();
        filterChain.doFilter(request,response);
    }

    public void doSomething(){
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        ServletContext servletContext = request.getServletContext();
        servletContext.log(request.getRequestURI()+" is filtering");
    }
}




3.JSP On Spring Boot
springboot建議使用模板引擎開發,jsp在spring boot中是受限制的,所以我們需要啟用
啟用:
1)實現
讓SpringBootLesson4Application繼承SpringBootServletInitializer,並重寫configure方法,

//組裝工作
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
    builder.sources(SpringBootLesson4Application.class);
    return builder;
}

2)新增依賴

<!--jsp 渲染引擎-->
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>
<!--jstl-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>


3)





4.Q&A

1)SpringBoot作為web容器時候與spring3時候效能提升多少?

2)我還在使用1.3版本,有必要升級到1.5嗎?坑多嗎?logback就是個坑!
不建議升級到1.5版本,至少LoggingSystem中的某個標記去了,導致logback這個坑,並且去除了log4j1
另外,還有Velocity也去除了。
如果需要升級,建議升級到2.0版本

3)SpringBoot對於註解的方式,大專案怎麼樣?好管理嗎?
SpringBoot是使用自動裝配的方式做的,其實SpringBoot在初始化的時候,裝配了大量的類、元件等
可以看spring.factories的autoconfigure,可以看到自動裝配的元件很多,大部分我們聽也沒聽過

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer

# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.JspTemplateAvailabilityProvider



InternalViewResolver是在WebMvcAutoConfiguration




3)springboot會不會有spring和springmvc關於父子容器aop失效的問題
springboot是有一個main程式啟動類,和以前的方式不太一樣。
springmvc是dispatcherServlet上下文建立的,
而springboot是將dispatcherServlet作為一個元件建立的



4)













相關文章