Spring Boot微服务

0.073字数 3978阅读 1184

Spring Boot微服务

SpringBoot揭秘:快速构建微服务体系

http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/

Why 微服务

  • 并行开发,快速迭代,独立交付
  • 多个WAR包部署在Web容器中,扩展能力受限于Web容器作为一个进程的现状,同时应用间为线程隔离。现在普遍做法是一个Tomcat只部署一个WAR,实现进程的天然隔离. SpringBoot还能以Jar包的形式部署,而不需要另外安装Tomcat(SpringBoot内置tomcat)
微服务演变历程

Spring IoC

  • 两种方式

    IoC两种方式
    • DI(依赖注入):被动接受其依赖的其他组件被IoC容器注入

    • DL(依赖查找):主动从某个服务注册地查找其依赖的服务

    public class DemoApplication {
    
        public static void main(String[] args) {
            ApplicationContext context = new FileSystemXmlApplicationContext("...");
            DemoService service = context.getBean(DemoService.class);
            service.doSomething();
        }
    }
    
  • 两个阶段

    • 收集注册
        手动组装
        <bean id="mockService" class="..MockServiceImpl">
            ...
        </bean>
        或者自动扫描
        <context:component-scan base-package="com.lyf">
    
    • 分析组装:分析这些已经在IoC容器中的bean,然后根据它们之间的依赖关系先后组装它们.(XML方式注解方式 @Autowired @Inject)

SpringBoot的工作机制

建立一个Spring Boot 应用

@SpringBootApplication
public class DemoApplication {

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

@SpringBootApplication

  • @SpringBootApplication 等于以下注解的合体(详见@SpringBootApplication接口源码)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//对于Spring应用,重要的只有下面三个注解
@Configuration
@EnableAutoConfiguration
@ComponentScan

@Configuration

  • 任何一个标注了@Configuration的Java类定义都是一个JavaConfig配置类,<font color=red>会被注册进IoC容器</font>(就像@Controller,@Service,@Repository一样),SpringBoot社区推荐使用基于JavaConfig的配置形式

    • XML 配置形式
    <bean id="mockService" class="..MockServiceImpl">
    ...
    </bean>
    
    • 基于JavaConfig的配置形式
    @Configuration
    public class MockConfiguration {
    
        //标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器,方法名将默认成为该bean定义的id
        @Bean
        public MockService mockService() {
            return new MockServiceImpl();
        }
    
    }
    
  • 依赖注入

    • XML 配置形式
    <bean id="mockService" class="..MockServiceImpl">
        <property name="dependencyService" ref="dependencyService" />
    </bean>
    
    • JavaConfig 形式
    @Configuration
    public class MockConfiguration {
    
        @Bean
        public MockService mockService() {
            return new MockServiceImpl(dependencyService());
        }
    
        /*
        如果有多个Bean调用该方法进行依赖注入, 只会new 一个DependencyServiceImpl().
        Spring通过拦截@Configuration类的方法调用来避免多次初始化同一类型对象的问题.
         一旦拥有拦截逻辑的子类发现当前方法没有对应的类型实例时才会去请求父类的同一方法来初始化对象实例, 否则直接返回之前的对象实例
         */
        @Bean
        public DependencyService dependencyService() {
            return new DependencyServiceImpl();
        }
    }
    
  • 调整自动配置的顺序

    @Configuration
    @AutoConfigureAfter(XXXX.class)//AutoConfigureBefore
    public class DemoConfiguration {...}
    

@EnableAutoConfiguration

  • Spring提供各种@EnableXXXX,简单概括:借助@Import的帮助,收集和注册特定场景相关的bean定义:

    • @EnableScheduling: 通过@Import将Spring调度框架相关的bean定义都加载IoC容器
    • @EnableMBeanExport: 通过@Import将JMX相关的bean定义都加载IoC容器
    • @EnableCaching
    • @EnableAutoConfiguration借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器,仅此而已!(即加载Spring框架定义的@configuration bean)
  • EnableAutoConfiguration 是复合Annotation,源码中如下定义

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(EnableAutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {...}
    
EnableAutoConfiguration得以生效的关键组件关系图

其中最关键的要属@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector类,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器
* EnableAutoConfigurationImportSelector类中使用了工具类SpringFactoriesLoader帮助进行智能自动配置,源码如下:

public class EnableAutoConfigurationImportSelector
      implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
      BeanFactoryAware, EnvironmentAware, Ordered {
...

/**
   * Return the auto-configuration class names that should be considered. By default
   * this method will load candidates using {@link SpringFactoriesLoader} with
   * {@link #getSpringFactoriesLoaderFactoryClass()}.
   * @param metadata the source metadata
   * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
   * attributes}
   * @return a list of candidate configurations
   */
  protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
          AnnotationAttributes attributes) {
      List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
              getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
      Assert.notEmpty(configurations,
              "No auto configuration classes found in META-INF/spring.factories. If you "
                      + "are using a custom packaging, make sure that file is correct.");
      return configurations;
  }
}

  • SpringFactoriesLoader的主要功能是从META-INF/spring.factories(properties文件)加载配置.在@EnableAutoConfiguration场景中为加载key为org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的一组@Configuration类

    //META-INF/spring.factories文件部分内容,注意key,value都是java类型的完整类名
    # 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.MessageSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\
    
  • 总结:

  1. @EnableAutoConfiguration就是从classpath中搜寻所有META-INF/spring.factories
  2. 将spring.factories中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的value通过反射实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类
  3. 汇总为一个并加载到IoC容器
    @EnableAutoConfiguration工作流程

@ComponentScan

  • 功能:自动扫描并加载符合条件的组件或bean定义,最终将这些bean加载到容器中
  • 对应XML配置中的<context:component-scan>,用于批量采集标注了@Component,@Repository等bean到Spring的IoC容器中
  • Spring默认会从声明@ComponentScan所在类的package进行扫描,可使用basePackages属性进行定制
  • 如果当前应用如果没有任何bean定义需要通过@ComponentScan加载,可以除去@ComponentScan

@PropertySource @PropertySources

  • 用于从某些地方加载*.properties文件内容,并将其中的属性加载到IoC容器中
// >=Java8
@Configuration
@PropertySource("classpath:1.properties")
@PropertySource("classpath:2.properties")
@PropertySource("...")
public class XConfiguration{

    //这种方式不推荐了
    @Value("${mongodb.db}")
    private String defaultDb;

    //推荐这种方式
    @Autowired  
    Environment env;

    private void demo(){
    String mongodbUrl = env.getProperty("mongodb.url");  
    String defaultDb = env.getProperty("mongodb.db");
    }

    //如果properties中有${}占位符,需要加以下这段,才能让spring正确解析出${}中的值
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
    return new PropertySourcesPlaceholderConfigurer();
  }
}

//<Java8
@PropertySources({
    @PropertySource("classpath:1.properties"),
    @PropertySource("classpath:2.properties"),
    ...
})
public class XConfiguration{...}

@Import @ImportResource

<import resource="XXX.xml/>将多个分开的容器配置合到一个配置中

@Configuration
//@Import负责引入JavaConfig形式的配置
@Import(MockConfiguration.class)
//@ImportResource负责引入XML形式的配置
@ImportResource("classpath:spring-dubbo.xml")
public class XConfiguration{...}

SpringBoot启动过程

  • SpringApplication将Spring应用启动的流程"模版化",同时在合适的流程节点开放了一系列不同类型的扩展点,用于特殊定制化需求.
  • 启动过程即执行SpringApplication.run(DemoApplication.class, args); 该语句等同于 new SpringApplication().run()
    SpringBoot启动过程

@SpringApplicationRunListener

  • SpringBoot应用main方法执行过程中,监听不同执行时点时间通知
public interface SpringApplicationRunListener {
    void started();
    void environmentPrepared(ConfigurableEnvironment environment);
    void contextPrepared(ConfigurableApplicationContext context);
    void contextLoaded(ConfigurableApplicationContext context);
    void finished(ConfigurableApplicationContext context, Throwable exception);

}
  • 基本没什么常见场景需要自己实现SpringApplicationRunListener
  • SpringBoot默认也只有一个EventPublishingRunListener implements SpringApplicationRunListener,用于在SpringBoot启动的不同时点发布不同的应用事件类型(ApplicationEvent),如果有哪些ApplicationListener对这些应用事件感兴趣,则可以接收并处理
EventPublishingRunListener
  • 如果要自定义一个SpringApplicationRunListener实现,需要做如下两步

    • 新建一个实现类
    public class DemoApplicationRunListener implements SpringApplicationRunListener
    
    • 在当前SpringBoot应用的classpath下的META-INF/spring.factories文件中进行如下配置
    org.springframework.boot.SpringApplicationRunListener=com.lyf.springboot.demo.DemoApplicationRunListener
    

@ApplicationListener

  • 监听者模式
  • 为SpringBoot添加自定义ApplicationListener有两种方式
  1. 经验证,最新SpringBoot版本没有以下静态方法

    SpringApplication.addListeners(...) 或者 SpringApplication.setListeners(...)
    
  2. 在当前SpringBoot应用的classpath下的META-INF/spring.factories文件中进行如下配置

    org.springframework.context.=com.lyf.springboot.demo.DemoApplicationListener
    

@ApplicationContextInitializer

  • 该类主要目的就是在ConfigurableApplicationContext类型(或子类型)的SpringApplication做refresh之前,允许我们对ConfigurableApplicationContext实例做进一步设置处理
  • 自定义ApplicationContextInitializer方法为
public class DemoApplicationContextInitializer implements ApplicationContextInitializer{
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // do whatever you want with applicationContext,
        // e.g. applicationContext.registerShutdownHook();
    }
}
  • 注册自定义方法也是在当前SpringBoot应用的classpath下的META-INF/spring.factories文件中进行配置

CommandLineRunner

  • 它不是Spring框架原有的,属于SpringBoot应用特定的回调扩展接口
public interface CommandLineRunner {
    void run(String... args) throws Exception;
}
  • 它的执行点在SpringBoot应用的ApplicationContext完全初始化开始工作之后(可认为是main执行完成之前最后一步)
  • 当前SpringBoot应用的ApplicationContext中的任何CommandLineRunner,都会被加载执行
  • 实现方式
标注@org.springframework.core.annotation.Order
或
实现org.springframework.core.annotation.Order接口

spring-boot-starter

spring-boot-starter在Spring Boot生态中被称为Starter POMs。Starter POMs是一系列轻便的依赖包,是一套一站式的Spring相关技术解决方案。开发者在使用和整合模块时,不必再去搜寻样例代码中的依赖配置来复制使用,只需要引入对应的模块包即可,比如,开发Web应用时,就引入spring-boot-starter-web, 希望应用具备数据库访问能力的时候,那就引入spring-boot-starter-jdbc

  • SpringBoot两个重要特性:
    • 约定优于配置(COC)
    • 开箱即用. SpringBoot提供的开箱即用模块都约定以spring-boot-start-作为命名前缀
  • 对SpringBoot行为干预的配置方式有(优先级由高到低,优先级高的覆盖低的)
    • 命令行参数
    • 系统环境变量
    • 文件系统中的配置文件
    • classpath中的配置文件
    • 固化到代码中的配置项
  • SpringBoot应用默认的配置文件位置/application.properties/config/application.properties

spring-boot-starter-logging

为SpringBoot引入应用日志框架,以下选择一种,注意一定不要将这些完成同一目的的spring-boog-starter都引入

/application.properties
logging.level.root=debug
  • logback
    引入依赖后开箱即用

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
    </dependency>
    

配置方式有两种
* 遵循logback约定,在classpath中使用自定义的logback.xml配置文件
* application.properties中使用logging.config配置项指向logback.xml配置文件
logging.config=/{some.path.you.defined}/logback.xml

  • log4j

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j</artifactId>
    </dependency>
    
  • log4j2

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
    

spring-boot-starter-web

  • 用于使用SpringMVC开发web应用(打包形式为jar)

  • 非Web应用使用spring-boot-starter

  • 引入

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
  • 项目结构约定

默认为jar包形式打包 传统war包形式
src/main/resources src/main/webapp
静态资源(css,js等): src/main/resources/static
模版文件(*.vm): src/main/resources/templates
  • SpringMVC层面的约定和定制
默认为我们自动配置如下SpringMVC必要组件 定制方法
1.必要的ViewResolver, 比如ContentNegotiatingViewResolver,和BeanNameViewResolver
2. 将必要的Converter,GenericConverter和Formatter等bean注册到IoC容器
3. 添加一系列的HttpMessageConverter以便支持对Web请求和相应的类型转换
4.自动配置和注册MesasageCodesResolver
5.其他
1.在IoC容器中注册新的同类型的bean定义来替换
2. 直接提供一个基于WebMccConfigurerAdapter类型的bean定义来定制
3.甚至直接提供一个标注了@EnableWebMvc的@Configuration配置类来完全接管所有SpringMVC的相关配置,自己完全重新配置
  • 嵌入式Web容器层面约定和定制

    • spring-boot-starter-web默认使用嵌入式tomcat,端口8080
    • 如果不想使用默认的嵌入式tomcat(spring-boot-starter-tomcat), 可以引入spring-boot-starter-jetty或spring-boot-starter-undertow替代
    • 修改Web容器配置项
      jar包启动指定端口号可以增加参数 -Dserver.port=8080
    //application.properties
    server.port = 9000
    server.address =
    server.ssl.*
    server.tomcat.*
    
    • 以上配置项仍无法满足需求,可向IoC容器注册一个EmbeddedServletContainerCustomizer类型的组件对嵌入式Web容器进行定制
    @Configuration
    public class DemoEmbeddedServletContainerCustomizer implements EmbeddedServletContainerCustomizer {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            container.setPort(9999);
            container.setContextPath("/demo-project");
            //...
        }
    }
    
    • 再深入定制则需要针对特定的嵌入式Web容器,使用实现对应的Factory并注册到IoC容器

      • TomcatEmbeddedServletContainerFactory
      • JettyEmbeddedServletContainerFactory
      • UndertowEmbeddedServletContainerFactory
    • JSP支持(需要打包成war,不能为jar)

      • 引入依赖
      //注意版本,最新的tomcat-embed-jasper版本可能会启动报错
      compile("org.apache.tomcat.embed:tomcat-embed-jasper:8.5.8")
      compile("javax.servlet:jstl:1.2")
      
      • application.properties
      spring.mvc.view.prefix=/WEB-INF/views/
      

spring.mvc.view.suffix=.jsp
```

    * 目录结构,由于tomcat硬编码的原因, 对目录结构有要求,webapp还是需要的

      ![目录结构](http://upload-images.jianshu.io/upload_images/5748528-832609f7cd383a5e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

打包成可执行war

  • URL
  • 引入springboot gradle插件
apply plugin: 'org.springframework.boot'
buildscript {
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.2.RELEASE")
    }
}
buildscript {
    repositories {
        maven {
            name 'Aliyun Maven Repository'
            url 'http://maven.aliyun.com/nexus/content/groups/public'
        }
    }
}
  • 使用gradle bootRepackage进行打包
  • 运行java -jar /Users/luyunfei/Documents/dev/workspace/zxd-oa/build/libs/zxd-oa.war

spring-boot-starter-jdbc

  • 更多的数据库访问模块:spring-boot-starter-mongodb

  • 默认使用tomcat JDBC连接池,Tomcat7之前,Tomcat本质应用了DBCP连接池技术来实现的JDBC数据源,但在Tomcat7之后,Tomcat提供了新的JDBC连接池方案,作为DBCP的替换或备选方案,解决了许多之前使用DBCP的不利之处,并提高了性能.其它连接池还有c3p0,Druid(淘宝开源)

  • 默认情况,如果没有配置任何DataSource,SpringBoot会自动配置一个基于嵌入式数据库的DataSource, 该行为很适合测试场景

  • 如果只依赖一个数据库,可使用如下配置

    //application.properties
    spring.datasource.url = jdbc:mysql://{database host}:3306/{databaseName}
    spring.datasource.username = {database username}
    spring.datasource.password = {database password}
    
  • 除了DataSource会自动配置,SpringBoot还会自动配置相应的JdbcTemplate,DataSourceTransactionManager等关联设施,使用时按如下注入即可

    class SomeDao{
        JdbcTemplate jdbcTemplate;
        public <T> List<T> queryForList(String sql){
            //...
        }
    }
    
  • 如果依赖多个数据库,使用如下配置在启动时会抛出异常

    //异常信息:No qualifying bean of type {javax.sql.DataSource} is defined: expected single matching bean bug found 2
    @Bean
    //解决方案: 在这里添加@Primary,告诉Spring在出现多个时,优先选择这个
    public DataSource dataSource1() throws Throwable{
        /*数据库连接池,类似的还有:
        *dbcp(有时候会自动断掉,必须重启才能有效)
        *C3P0(偶尔断掉,无须重启)
        *Druid性能较dbcp,c3p0优越很多(淘宝开源)
        *默认的tomcat 连接池
        */
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(...);
        dataSource.setUsername(...);
        dataSource.setPassword(...);
        return dataSource;
    }
    @Bean
    public DataSource dataSource2() throws Throwable{
        ...
    }
    

    还有一种方案时排除掉SpringBoot默认提供的DataSource相关自动配置

    @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    
  • 数据库版本化管理

    • 作用: 针对数据库的变更进行版本化管理(注意不要跟mybatis,hibernate等持久化框架搞混).即多个人接触数据库,当对表,字段或数据修改后(DDL,DML),又怎么来同步呢?解决各环境的数据库不一致问题(即将DDL,DML放到项目的sql文件中,由migrations框架自动提交到数据库中,类似于hibernate map文件增加字段后,在程序启动时,自动将增加的字段修改到DB中而无须对DB执行DML操作)
    • 实践方案
      • Ruby On Rails的migration支持
      • Java 的MyBatis Migrations(非MyBatis)
      • Flyway
      • Liquibase
    • SpringBoot提供针对Flyway,Liquibase的自动配置功能(org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration)
    • 两种版本化管理方式(注意不能说哪方式绝对的好,各有有缺点,应该按实际情况进行取舍)
    版本化管理方式
    • 对比
传统方式 外部化方式
SQL分布在各项目中 SQL集中到一处管理,有利于DBA进行SQL审查
多个应用使用同一个数据库时,容易相互干扰,且数据库连接过多 统一调度
需要完整的软件交付链路支撑平台

spring-boot-starter-aop

  • AOP(Aspect Oriented Programming)

  • 自动配置行为由两部分组成

    • spring-boot-autoconfigure的org.springframework.boot.autoconfigure.aop.AopAutoConfiguration提供@Configuration配置类和相应配置项,如下

      //application.properties
      spring.aop.auto = false(关闭自动aop配置)
      spring.aop.proxy-target-class=true(启用class而非interface级别的aop代理)
      
    • spring-boot-starter-aop 模块自身提供针对spring-aop,aspectjrt和aspectjweaver的依赖

  • step-step: 定义Aop 手动搭建metrics-spring(未调试成功,略),直接可用方案

    • 引入依赖compile("org.springframework.boot:spring-boot-starter-aop:1.4.0.RELEASE")
    • 定义aop类
    @Component
    @Aspect
    public class AutoMetricsAspect {
    
        //切点
        @Pointcut(value = "execution(public * *(..))")
        public void publicMethods() {
    
        }
        //各切面的实现逻辑,函数名称任意
        @Before(" publicMethods() && @annotation(countedAnnotation) ")
        public void instrumentCounted(JoinPoint jp, Counted countedAnnotation) {...}
    
        @Before(" publicMethods() && @annotation(meteredAnnotation) ")
        public void instrumentMetered(JoinPoint jp, Metered meteredAnnotation) {...}
    
        @AfterThrowing(pointcut = " publicMethods() && @annotation(exMeteredAnnotation)", throwing = "ex")
        public void instrumentExceptionMetered(JoinPoint jp, Throwable ex, ExceptionMetered exMeteredAnnotation) {...}
    
        @Around(" publicMethods() && @annotation(timedAnnotation) ")
        public Object instrumentTimed(ProceedingJoinPoint pjp, Timed timedAnnotation) throws Throwable {...}
    }
    
    • 以上, 写一个方法进行测试即可

spring-boot-starter-security

  • 引用 compile("org.springframework.boot:spring-boot-starter-security:1.4.0.RELEASE")
  • SpringSecurity核心概念示意图
SpringSecurity核心概念示意图
  • Spring Security的Web安全方案基于Java的Servlet API规范构建,因此使用javax.servlet.Filter实现"关卡",制作关卡过程如下:

    • 实现GenericFilterBean,并注册到IoC容器
    public class SignCheckFilter extends GenericFilterBean {...}
    
    • 启用:在web.xml或JavaConfig配置中声明一个DelegatingFilterProxy,使其filter-name与自定义关卡挂钩
        <filter>
            <filter-name>signCheckFilter</filter-name>
            <filter-class>com.lyf.demo.filter.SignCheckFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>signCheckFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
  • Spring Security 的Web方案也是如上原理,过程如下(源码)

    • 实现GenericFilterBean,并注册到IoC容器
    public class DelegatingFilterProxy extends GenericFilterBean{...}
    
    • 启用(类似如下方式)
        <filter>
            <filter-name>springSecurityFilterChain(默认名称)</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    FilterSecurityInterceptor相关组件关系示意图
    • Spring内置Filter
    /*
    三类:
        1.信道与状态管理
        2. Web安全防护
        3. 认证和授权
    */
    FilterComparator() {
        int order = 100;
        put(ChannelProcessingFilter.class, order);//用于处理http或https之间的切换(信道与状态管理)
        order += STEP;
        put(ConcurrentSessionFilter.class, order);
        order += STEP;
        put(WebAsyncManagerIntegrationFilter.class, order);
        order += STEP;
        put(SecurityContextPersistenceFilter.class, order);//用于重建或者销毁必要的SecurityContext状态(信道与状态管理)
        order += STEP;
        put(HeaderWriterFilter.class, order);
        order += STEP;
        put(CorsFilter.class, order);
        order += STEP;
        put(CsrfFilter.class, order);//Web安全防护
        order += STEP;
        put(LogoutFilter.class, order);
        order += STEP;
        put(X509AuthenticationFilter.class, order);
        order += STEP;
        put(AbstractPreAuthenticatedProcessingFilter.class, order);
        order += STEP;
        filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter",
                order);//认证和授权
        order += STEP;
        put(UsernamePasswordAuthenticationFilter.class, order);
        order += STEP;
        put(ConcurrentSessionFilter.class, order);
        order += STEP;
        filterToOrder.put(
                "org.springframework.security.openid.OpenIDAuthenticationFilter", order);
        order += STEP;
        put(DefaultLoginPageGeneratingFilter.class, order);
        order += STEP;
        put(ConcurrentSessionFilter.class, order);
        order += STEP;
        put(DigestAuthenticationFilter.class, order);
        order += STEP;
        put(BasicAuthenticationFilter.class, order);//认证和授权
        order += STEP;
        put(RequestCacheAwareFilter.class, order);
        order += STEP;
        put(SecurityContextHolderAwareRequestFilter.class, order);
        order += STEP;
        put(JaasApiIntegrationFilter.class, order);
        order += STEP;
        put(RememberMeAuthenticationFilter.class, order);
        order += STEP;
        put(AnonymousAuthenticationFilter.class, order);
        order += STEP;
        put(SessionManagementFilter.class, order);
        order += STEP;
        //ExceptionTranslationFilter负责接待或送客,如果访客来访,对方没有报上名来,则让访客去找AuthenticationManager登记认证;如果对方报上名却认证失败了,则请重新认证或者走人.它拒绝访客的方式是抛出相应的Exception
        put(ExceptionTranslationFilter.class, order);
        order += STEP;
        put(FilterSecurityInterceptor.class, order);//即前面说到的securedObject(Filter
        Invocation)的关卡
        order += STEP;
        put(SwitchUserFilter.class, order);
    }
    

HOLD进程

try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

推荐阅读更多精彩内容