当前位置: 首页 > news >正文

Spring注解驱动开发

一、组件注册

1、@Configuration & @Bean

@Configuration:声明这个类是一个配置类,加入ioc容器中。
@Bean:注册组件。默认的beanId是函数名,可以用value属性进行指定。

@Configuration
public class MyConfig {@Beanpublic Person person() {return new Person("ZhangSan", 10);}
}

测试类:

@Test
public void testIoc() {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);Person person = applicationContext.getBean(Person.class);System.out.println(person);String[] names = applicationContext.getBeanNamesForType(Person.class);Arrays.asList(names).forEach(System.out::println);
}

2、@ComponentScan & @ComponentScans

包扫描,扫描包下面的@Controller、@Service等组件类
等同于配置文件的 <context:component-scan >

@ComponentScan

  • value

要扫描的包,等同于basePackages

  • basePackages

同value

  • includeFilters

指定只包含的组件
属性值是一个@Filter数组

  • excludeFilters

指定排除的组件。
属性值是一个@Filter数组

示例1:扫描com.linwillen包下的组件,排除@Controller、@Service注解的类

@Configuration
@ComponentScan(value = "com.linwillen", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
public class MyConfig {@Beanpublic Person person() {return new Person("ZhangSan", 10);}
}

示例2:只包含@Controller、@Service注解的类。(需要先禁用默认的过滤规则useDefaultFilters=false,因为默认的过滤规则是全部扫描)

@Configuration
@ComponentScan(value = "com.linwillen",useDefaultFilters = false,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
public class MyConfig {@Beanpublic Person person() {return new Person("ZhangSan", 10);}
}

@ComponentScan.Filter

配置包扫描的过滤规则

@Filter

  • type

要排除的方式:FilterType。

  • Annotation:按照注解
  • Assignable_type:按照给定的类
  • AspectJ:使用AspectJ表达式
  • Regex:使用正则表达式
  • Custom:使用自定义规则,该规则必须是TypeFilter的实现类
  • value

要排除的类型,同classes

  • classes

同value

  • pattern

正则表达式

自定义TypeFilter规则:

MetadataReader:读取到的当前正在扫描的类的信息
MetadataReaderFactory:可以获取到其他任何类的信息

public class MyTypeFilter implements TypeFilter {@Overridepublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {// 获取当前正在扫描类的注解信息AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();// 获取当前正在扫描的类的类信息ClassMetadata classMetadata = metadataReader.getClassMetadata();// 获取当前的资源信息metadataReader.getResource();String className = classMetadata.getClassName();return "com.linwillen.dao.UserDao".equals(className);}
}

3、@Scope

调整作用域。

  • value

取值:

  • ConfigurableBeanFactory.SCOPE_SINGLETON : “singleton”,单实例(默认值),ioc容器启动就会调用方法创建对象到ioc容器中。
  • ConfigurableBeanFactory.SCOPE_PROTOTYPE : “prototype”,多实例,ioc容器启动时并不会调用方法创建对象,每次获取时才会调用方法创建对象。
  • WebApplicationContext.SCOPE_REQUEST:“request”,同一个请求创建一个实例
  • WebApplicationContext.SCOPE_SESSION:“session”,同一个session创建一个实例
  • scopeName

同’value’

例如:

@Bean
@Scope
public Person person() {return new Person("WangWu", 30);
}

4、@Lazy

针对单实例的Bean。
单实例Bean默认在容器启动时创建对象。懒加载在第一次使用Bean时才创建对象并初始化。

例如:

@Bean
@Lazy
public Person person02() {return new Person("WangWu", 30);
}

5、@Conditional

按照条件进行判断,满足条件才给容器中注册Bean。
该注解在Spring、SpringBoot底层中经常使用。

value属性需要传入一个判断条件,该判断条件是一个实现了Condition接口的类。

自定义判断条件类:

public class MyCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) {// 获取类加载器ClassLoader classLoader = context.getClassLoader();// 获取ioc使用的beanFactoryConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 获取到bean定义的注册类BeanDefinitionRegistry registry = context.getRegistry();ResourceLoader resourceLoader = context.getResourceLoader();// 获取当前环境信息Environment environment = context.getEnvironment();String osName = environment.getProperty("os.name");return osName.startsWith("Windows");}
}

在bean上加上判断条件:

@Conditional(MyCondition.class)
@Bean(name = "person01")
public Person person01() {return new Person("Lisi", 22);
}

该注解也可以用在类上,对类中所有bean统一设置:

@Configuration
@Conditional(MyCondition.class)
public class MyConfig {@Bean("person")public Person person() {return new Person("ZhangSan", 10);}@Bean("person01")    public Person person01() {return new Person("lisi", 18);}
}

6、@Import

给容器中注册组件:

  • 包扫描+组件标注注解(@Controller、@Service、@Repository、@Component)[自己写的类]
  • @Bean [导入的第三方包里面的组件]
  • @Import[快速的给容器中导入一个组件]
  • 使用Spring提供的FactoryBean(工厂bean)

使用方式:

三种使用方法可以混合使用。

  1. @Import(要导入的组件类数组):容器中就会自动注册这个组件,id默认是类的全限定名。
  2. @Import(ImportSelector):ImportSelector会返回要导入的类的全限定名的数组
  3. @Import(ImportBeanDefinitionRegistrar):手动注册bean

自定义ImportSelector:

AnnotationMetadata:当前标注@Import注解的类的所有注解信息。
返回值不能是null,否则会报空指针异常。如果需要返回的内容,则需使用:return new String[0]。

public class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {return new String[]{"com.linwillen.bean.Yellow", "com.linwillen.bean.Blue"};}
}

自定义ImportBeanDefinitionRegistrar:

AnnotationMetadata:当前类的注解信息
BeanDefinitionRegistry:BeanDefinition注册类。需要添加到容器中的Bean,可以通过BeanDefinitionRegistry.registerBeanDefinition手工注册进来。

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {String[] beanDefinitionNames = registry.getBeanDefinitionNames();// Arrays.asList(beanDefinitionNames).forEach(System.out::println);// 判断ioc容器中是否注册了指定id的Beanboolean redDefinition = registry.containsBeanDefinition("com.linwillen.bean.Red");boolean blueDefinition = registry.containsBeanDefinition("com.linwillen.bean.Blue");if(redDefinition && blueDefinition) {// 调用registry的registerBeanDefinition方法手工注册Bean// 使用RootBeanDefinition指定要注册的Bean的类型RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);// 指定注册进容器的bean的idregistry.registerBeanDefinition("rainBow", beanDefinition);}}
}
@Configuration
@Conditional(MyCondition.class)
@Import({Color.class, Red.class, MyImportSelector.class})  // 可以同时配置要导入的类名、ImportSelector、ImportBeanDefinitionRegistrar
public class MyConfig {@Bean("person")public Person person() {return new Person("ZhangSan", 10);}
}

7、FactoryBean

Spring提供的 工厂Bean接口

自定义FactoryBean,用来生成Color的Bean:

public class ColorFactoryBean implements FactoryBean<Color> {// 返回一个color对象,这个对象会添加进容器中@Overridepublic Color getObject() throws Exception {return new Color();}// 返回的对象的类型@Overridepublic Class<?> getObjectType() {return Color.class;}// 是否为单例:true代表这个bean是单实例的,false代表每次获取都会创建一个新的bean@Overridepublic boolean isSingleton() {return true;}
}

添加该FactoryBean为Bean:

@Configuration
@Conditional(MyCondition.class)
public class MyConfig {@Bean("person")public Person person() {return new Person("ZhangSan", 10);}@Bean("person01")public Person person01() {return new Person("lisi", 18);}@Bean("colorTest")public ColorFactoryBean colorFactoryBean() {return new ColorFactoryBean();}
}

在获取colorTest这个Bean时,实际获取到的bean对象的类型是ColorFactoryBean::getObjectType()返回的类型,即Color类型。获取到的Bean对象是ColorFactoryBean::getObject()创建的对象。

如果想要获取ColorFactoryBean类型的bean对象,需要在BeanID前添加前缀&,即&colorTest。这个前缀是在BeanFactory.FACTORY_BEAN_PREFIX中定义的。

二、生命周期

1、@Bean中配置生命周期

使用@Bean注解的initMethod、destroyMethod两个属性配置bean的初始化和销毁方法。

public class Car {public Car() {        System.out.println("Car constructor...");    }    public void init() {        System.out.println("car .... init ...");    }public void destroy() {        System.out.println("car...destroy");    }
}

配置类编写:

@Configuration
public class MyLifeCycleConfig {@Bean(initMethod = "init", destroyMethod = "destroy")public Car car() {return new Car();}
}

2、实现InitializingBean和DisposableBean接口

InitializingBean接口的afterPropertiesSet()实现初始化逻辑;

DispoableBean接口的destroy()实现销毁逻辑;

public class Car implements InitializingBean, DisposableBean {public Car() {System.out.println("Car constructor...");}public void init() {System.out.println("car .... init ...");}@Overridepublic void destroy() {System.out.println("car...destroy");}@Overridepublic void afterPropertiesSet() throws Exception {init();}
}

3、@PostConstruct & @PreDestroy

JSR250注解:

  • @PostConstrct,标注在方法上,对象执行构造行数,创建并赋值之后执行
  • @PreDestroy,标注在方法上,在容器移除对象之前执行
public class Car{public Car() {System.out.println("Car constructor...");}@PostConstructpublic void init() {System.out.println("car .... init ...");}@PreDestroypublic void destroy() {System.out.println("car...destroy");}
}

4、BeanPostProcessor接口

Bean的后置处理器,在bean的初始化前后进行处理。

  • postProcessBeforeInitialization:Bean构造方法执行之后、初始化方法执行之前 处理
  • postProcessAfterInitialization:Bean初始化之后处理

自定义BeanPostProcessor

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("before init..." + beanName);return bean;  // 返回传入的原始bean,或者进行了包装之后的bean}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("after init ..." + beanName);return bean;// 返回传入的原始bean,或者进行了包装之后的bean}
}

输出结果:

before init...myLifeCycleConfig
after init ...myLifeCycleConfig
Car constructor...
before init...car
car .... init ...
after init ...car
car...destroy

执行过程:

  1. AbstractAutowireCapableBeanFactory.doCreateBean中调用popolulateBean为bean填充属性,然后调用initializeBean开始进行bean的初始化以及bean初始化的前后处理。
  2. AbstractAutowireCapableBeanFactory.doCreateBean调用initializeBean方法:
  3. 该方法会先调用applyBeanPostProcessorsBeforeInitialization(warppedBean, beanName);初始化前前置处理
  4. 然后调用invokeInitMethods对bean进行初始化
  5. 最后调用applyBeanPostProcessorsAfterInitialization,初始化后置处理。

在这里插入图片描述
applyBeanPostProcessorsBeforeInitialization会遍历所有的BeanPostProcessor,执行每个BeanPostProcessorpostProcessBeforeInitialization方法,如果某个BeanPostProcessor::postProcessBeforeInitialization返回null,则直接退出循环,不再执行后面的BeanPostProcessor

在这里插入图片描述

源码中使用的BeanPostProcessor

源码中有很多组件通过BeanPostProcessor进行实现。
以ApplicationContextAwareProcessor为例。

ApplicationContextAwareProcessor可以为Bean中注入ioc容器。利用的就是BeanPostProcessorpostProcessBeforeInitialization方法:获取bean实现的接口,然后根据实现的接口不同,调用相应的方法,把ioc容器传入对应的方法参数内。

源码:

public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {AccessControlContext acc = null;if (System.getSecurityManager() != null &&(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {acc = this.applicationContext.getBeanFactory().getAccessControlContext();}// ....invokeAwareInterfaces(bean);return bean;
}
private void invokeAwareInterfaces(Object bean) {if (bean instanceof Aware) {if (bean instanceof EnvironmentAware) {((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());}if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);}if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);}if (bean instanceof MessageSourceAware) {((MessageSourceAware) bean).setMessageSource(this.applicationContext);}if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);}}
}

在Bean中使用示例:

Car类实现ApplicationContextWareProcesser中判断的可以注入ioc容器的接口,然后实现对应的方法

public class Car implements ApplicationContextAware {private ApplicationContext applicationContext;public Car() {System.out.println("Car constructor...");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("为car注入applicationContext");this.applicationContext = applicationContext;}
}

@PostConstruct@PreDestroy注解的解析是在InitDestroyAnnotationBeanPostProcessor类中实现的,该类也是通过BeanPostProcesser进行实现的。

三、属性赋值

1、@Value

@Value赋值:

  • 基本数值
    @Value(“张三”)
  • SpEL
    @Value(#{1 + 2})
  • 配置文件、环境变量中的值
    @Value(${os.name})

示例:

public class Person {@Value("张三")private String name;@Value("#{ 10 + 8} ")private Integer age;@Value("${person.nickName}")private String nickName;// getter/setter方法
}

2、@PropertySource

使用@PropertySource指定读取的配置文件路径:
@PropertySource是一个可重复使用的注解。
@PropertySource的value属性可以传多个路径。
或者使用@PropertySources指定多个@PropertySource

@Configuration
@PropertySource(value = "classpath:/person.properties", encoding = "utf-8")
public class MyPropertyConfig {@Beanpublic Person person() {return new Person();}
}

四、自动装配

1、@Autowired

作用:自动按照类型注入,只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。如果IoC容器中没有任何bean的类型和要注入的变量的类型匹配,则报错。如果IoC容器中该类型的bean存在多个,则将要注入的变量的变量名作为bean的id进行二次匹配:如果根据变量名可以找到唯一的bean,则进行注入。如果根据变量名匹配不到,则报错。

@Autowired有一个属性required,默认为true。如果设置为false,则该对象可以在获取不到bean时默认为null。

出现位置:可以使属性上,也可以是方法、参数上。
细节:在使用注解进行注入时,变量的setter方法就不是必须的了

(1)标注在属性上

public class Boss {@Autowiredprivate Car car;
}

(2)标注在方法上

Spring容器创建当前对象,就会调用方法,完成赋值。
方法使用的参数,自定义类型的值从ioc容器中获取。

@Autowired
public void setCar(Car car) {this.car = car;
}

(3)标注在有参构造器上

默认加在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作。
给bean移除无参构造器,添加一个有参构造器,为该有参构造器添加@Autowired注解。Spring容器启动时会调用该有参构造器,并从ioc容器中获取参数对应类型的bean对象进行注入。

@Autowired
public Boss(Car car) {this.car = car;
}

(4)标注在构造器参数位置

public Boss(@Autowired Car car) {this.car = car;
}

如果当前类只有一个有参构造器,Spring容器创建该bean只能调用该有参构造器,有参构造器的@Autowired可以省略,参数依然可以从ioc容器中获取:
使用构造函数进行注入时,需要标注final来表示这个注入的变量不能被改变。

private final Car car;public Boss(Car car) {this.car = car;
}

(5) 标注在@Bean注解的方法上

在@Configuration类中通过@Bean将Color加入容器,并使用@Autowired注入Car:
此处的@Autowired也可以省略

@Configuration
public class MyConfig {@Beanpublic Color color(@Autowired Car car) {return new Color();}
}

2、@Qualifier

作用:

在按照类型匹配的基础上,再按照名称匹配注入。它在给类的成员变量注入时,不能单独使用,要和@Autowired配合使用。它在给方法参数进行注入时,可以单独使用。

属性:

value:用于指定要注入的bean的id。

3、@Primary

让Spring自动装配时默认使用首选的Bean。
当某个bean在容器中存在多个同类型bean,且使用@Autowired时没有明确指定@Qualifier,则默认使用@Primary首选转配。也可以继续使用@Qualifier指定装配的Bean的名字。

4、@Resource

JSR250规范。
作用:直接按照bean的id进行注入。它可以独立使用。
属性:

  • name:用于指定bean的id。
  • 不能支持@Primary 以及required=false的功能

5、@Inject

JSR330规范:@Inject
需要导入依赖:
和@Autowired功能类似,但是没有required属性。

<dependency><gourpId>javax.inject</groupId><artifactId>javax.inject</artifactId><version>1</version>
</dependency>

6、Aware接口

自定义组件想要使用Spring容器底层的一些组件(例如ApplicationContext、BeanFactory、BeanName等),实现xxxAware接口,在创建对象的时候,会调用接口规定的方法,注入相应的组件。

xxxAware的总接口为Aware接口。xxxAware的对应的解析为xxxAwarePropressor。

示例:在Bean中注入ioc容器ApplicationContext,实现ApplicationContextAware接口

public class Car implements ApplicationContextAware {private ApplicationContext applicationContext;public Car() {System.out.println("Car constructor...");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("为car注入applicationContext");this.applicationContext = applicationContext;}
}

String值解析器(可以解析String、SpEL表达式、环境变量值、配置文件值):

public class Person implements  EmbeddedValueResolverAware {@Overridepublic void setEmbeddedValueResolver(StringValueResolver resolver) {String str = resolver.resolveStringValue("test: #{ 10 * 2} ==== ${person.nickName} ==== ${os.name} .");System.out.println(str);}
}

7、@Profile

五、AOP使用和原理

1、AOP使用

@Aspect
public class LogAspect {@Pointcut("execution(public int com.linwillen.aop.MathCalculator.*(..))")public void pointCut(){}@Before("pointCut()")public void logStart(JoinPoint joinPoint){String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("@Before The method "+name+" begins with "+ Arrays.toString(args));}@After("pointCut()")public void logEnd(JoinPoint joinPoint){String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("@After The method "+name+" ends with "+ Arrays.toString(args));}@AfterReturning(value = "pointCut()",returning = "result")public void logReturning(JoinPoint joinPoint, Object result){String name = joinPoint.getSignature().getName();System.out.println("@AfterReturning 除法正常返回...返回值:" + result);}@AfterThrowing(value = "pointCut()",throwing = "exception")public void logException(JoinPoint joinPoint, Exception exception){String name = joinPoint.getSignature().getName();System.out.println("@AfterThrowing 除法出现异常...异常信息:" + exception.getMessage());}@Around(value = "pointCut()", argNames = "joinPoint")public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {// 前置处理System.out.println("@Around 方法执行前: " + joinPoint.getSignature().getName());// 执行目标方法Object result = joinPoint.proceed(); // 关键点:调用目标方法// 后置处理System.out.println("@Around 方法执行后: " + joinPoint.getSignature().getName());return result; // 返回结果}}

将切面类和要切入的类都加入ioc容器,并且使用@EnableAspectJAutoProxy在配置类中开启Aspectj自动代理:

@EnableAspectJAutoProxy
@Configuration
public class AopConfig {@Beanpublic LogAspect logAspect() {return new LogAspect();}@Beanpublic MathCalculator mathCalculator() {return new MathCalculator();}}

测试类:

	@Testpublic void testAop() {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);MathCalculator mathCalculator = context.getBean(MathCalculator.class);mathCalculator.div(1, 0);context.close();}

2、@EnableAspectJAutoProxy原理

@EnableAspectJAutoProxy中使用@Import(AspectJAutoProxyRegistrar.class)加入了一个组件
AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar接口,可以手动加载组件(特别注意这里只是加了BeanDefinition(Bean的定义信息),真正的Bean还没有被创建出来)

(1)AspectJAutoProxyRegistrar的执行过程:

  • 先判断是否存在beanID为org.springframework.aop.config.internalAutoProxyCreator的bean,不存在则注册一个AnnotationAwareAspectJAutoProxyCreator类型的bean定义信息
  • 然后获取类上面的@EnableAspectJAutoProxy属性信息,判断proxyTargetClass属性、exposeProxy属性,做一些后续处理

AnnotationAwareAspectJAutoProxyCreator的继承关系如下图:AnnotationAwareAspectJAutoProxyCreator最终实现了BeanFactoryAware、BeanPostProcessor

在这里插入图片描述

注:
BeanPostProcessor接口定义的方法是:
- postProcessBeforeInitialization()
- postProcessAfterInitialization()InstantiationAwareBeanPostProcessor接口继承了BeanPostProcessor,另外又增加了两个方法:
- postProcessBeforeInstantiation()
- postProcessAfterInstantiation()

3、注册AnnotationAwareAspectJAutoProxyCreator

AOP的底层原理就是创建AnnotationAwareAspectJAutoProxyCreator这个Bean的实例,把这个创建过程搞懂了,AOP就能理解了

  1. 传入配置类,创建ioc容器

  2. 注册配置类,调用refresh()刷新容器。以下为refresh()方法内部的执行逻辑:

  3. registerBeanPostProcessor(beanFactory);注册bean的后置处理器
    a. 先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
    b. 给容器中加别的BeanPostProcessor
    c. 优先注册实现了PriorityOrdered接口的BeanProcessor
    d. 再给容器中注册实现了Ordered接口的BeanPostProcessor
    e. 注册没实现优先级接口的BeanPostProcessor
    f. 注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中
    例如:创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectAutoProxyCreator】

    • 创建bean的实例
    • populateBean给bean的各种属性赋值
    • initializeBean初始化bean
      - invokeAwareMethods:处理Aware接口的方法回调
      - applyBeanPostProcessorsBeforeInitialization:应用后置处理器的beforeInitialization方法
      - invokeInitMethods:执行@Bean注解等自定义的Bean初始化方法
      - applyBeanPostProcessorsAfterInitialization:执行后置处理器的afterInitialization方法
    • BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;-> aspectJAdvisorsBuilder

    g. 把BeanPostProcessor注册到BeanFactory中,beanFactoy.addBeanPostProcessor(postProcessor)

  4. finishBeanFactoryInitialization(beanFactory)完成bean初始化工作,创建剩下的单实例bean(此时创建的bean,是那些不属于后置处理器的普通单实例bean。后置处理器本身也是bean,后置处理器的bean在第3.f步进行创建)
    a. 遍历获取容器中所有的bean,依次创建对象:getBean(beanName)。getBean -> doGetBean -> getSingleton
    b. 创建bean;AnnotationAwareAspectJAutoProxyCreator会在所有bean创建之前进行一次拦截,调用实现的InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation()方法。

    • 创建好的bean都会被缓存起来
    • createBean();创建bean
      - resolveBeforeInstantiation(beanName, mdbToUse)解析beforeInstantiation。
      希望后置处理器能在此返回一个代理对象,如果能返回代理对象就使用,如果不能就下一步doCreateBean
      - 后置处理器先尝试返回对象
    • doCreateBean(beanName, mbdToUse, args) ,真正的去创建一个bean实例 ,和第3.f环节中的操作流程一样
// 拿到所有BeanPostProcessor后置处理器,如果该后置处理器属于InstantiationAwareBeanPostProcessor,则执行该后置处理器的postProcessBeforeInstantiation方法。
// (注意postProcessBeforeInstantiation方法 不同于 postProcessBeforeInitialization方法)
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}

BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization是在Bean对象创建完成初始化前后调用的;
InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation和postProcessAfterInstantiation是在创建Bean实例之前先尝试用后置处理器返回对象。
即AnnotationAwareAspectJAutoProxyCreator实现的InstantiationAwareBeanPostProcessor的方法,会在任何bean创建之前先尝试返回bean的实例。

4、InstantiationAwareBeanPostProcessor接口

AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator,实现了InstantiationAwareBeanPostProcessor接口,它的作用是:

  1. 每一个bean创建之前,调用postProcessBeforeInstantiation()
    1.1. 判断当前bean是否在advisedBeans中(advisedBeans保存了所有需要增强的bean)
    1.2. 调用isInfrastructureClass()判断当前Bean是否是基础类型

    • 1.2.1. aop相关基础设施类型的bean不应该被动态代理。
    • 1.2.2. 切面的bean不应该被动态代理:带有@Aspect注解的bean

    1.3. 调用shouldSkip()判断当前bean是否需要跳过

  2. AbstractAutoProxyCreator的postProcessAfterInstantiation()直接返回true

  3. AbstractAutoProxyCreator的postProcessBeforeInitialization()直接返回传入的bean对象

  4. 创建好bean对象后,调用postProcessAfterInitialization()
    调用wrapIfNecessary()方法,如果需要的话对bean进行包装。
    a. 同postProcessBeforeInstantiation()一样进行一些校验:
    ■ 当前bean是否在advisedBeans中
    ■ 当前bean是否是基础类型
    ■ 当前bean是否需要跳过
    b. 调用getAdvicesAndAdvisorsForBean()获取当前bean的所有增强器(通知方法):Object[] specificInterceptors
    ⅰ. 找到候选的所有增强器
    ⅱ. 找到能在当前bean中使用的增强器
    ⅲ. 给增强器排序
    c. 将bean保存到advisedBeans中,表示当前bean已经被增强处理了
    d. 如果当前Bean需要增强,创建当前bean的代理对象;
    ⅰ. 获取所有增强器(通知方法)
    ⅱ. 保存到proxyFactory中
    ⅲ. 创建代理对象
    Spring在DefaultAopProxyFactory::createAopProxy中自动决定使用哪种方式创建代理对象:
    ● JdkDynamicAopProxy
    ● ObjenesisCglibAopProxy

  5. 给容器中返回cglib增强了的代理对象

  6. 以后容器中获取到的就是这个组件的代理对象,执行目标方法时,代理对象就会执行通知方法的流程

5、MethodInterceptor方法拦截器链

目标方法执行:

容器中保存了组件的代理对象(Cglib增强后的对象),这个对象里面保存了详细信息(增强器、目标对象等)。

  1. 进入CglibAopProxy的intercept()方法,拦截目标方法的执行
    a. 根据ProxyFactory类型的advised对象,获取到将要执行的目标方法的拦截器链
    拦截器链:每一个通知方法被包装成MethodInterceptor方法拦截器,后续利用MethodInterceptor机制执行
    List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    ⅰ. List interceptorList保存所有拦截器
    一个默认的ExposeInvocationInterceptor + 自定义的增强通知方法
    ⅱ. 遍历所有的增强器,将其转换为Interceptor:registry.getInterceptors(advisor);
    将Advisor转换为MethodInterceptor(MethodInterceptor继承于Interceptor):
    判断如果Advisor属于MethodInterceptor类型,则直接加入interceptors数组;
    通过遍历AdvisorAdapter适配器(前置通知适配器、返回结果通知适配器、异常通知适配器),尝试将Advisor转换为MethodInterceptor,加入interceptors数组

@AfterThrowing注解的增强器转换为AspectJAfterThrowingAdvice
@AfterReturning注解的增强器转换为AfterReturningAdviceInterceptor
@After注解的增强器转换为AspectJAfterAdvice
@Before注解的增强器转换为MethodBeforeAdviceInterceptor

b. 如果没有拦截器链,直接执行目标方法
c. 如果有拦截器链,把需要执行的目标对象、目标方法、拦截器链等信息传入创建一个CglibMethodInvocation对象,并调用该对象的proceed()方法。

Object retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

拦截器链的调用过程:proceed()的执行过程。

CglibMethodInvocation继承于ReflectiveMethodInvocation,实际执行的是ReflectiveMethodInvocation::proceed()

  1. 如果没有拦截器执行目标方法,或者拦截器的索引和(拦截器数组-1)大小一样(即到了最后一个拦截器),执行目标方法。
    因为拦截器的链式执行是类似入栈操作,是后入先出,所以拦截器链数组中的拦截器顺序与执行顺序相反
  2. 否则获取到拦截器链中(当前索引 += 1)的拦截器,执行其invoke()方法
  3. 拦截器的invoke()方法,会在进行一定操作后,递归链式调用proceed()方法。
    例如@Before增强器对应的MethodBeforeAdviceInterceptor拦截器,其invoke()方法为:
    @AfterReturning增强器对应的AfterReturningAdviceInterceptor拦截器,其invoke()方法为:
@Override
public Object invoke(MethodInvocation mi) throws Throwable {this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );return mi.proceed();  // 链式调用,继续进行后面的链的执行
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {Object retVal = mi.proceed(); // 链式调用,继续进行后面的链的执行this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());return retVal;
}

6、AOP增强器注解执行顺序

根据注解进行排序
spring4顺序依次为:@Around、@Before、@After、@AfterReturning/@AfterThrowing、@Around
spring5顺序依次为:@Around、@Before、@AfterReturning/@AfterThrowing、@After、@Around

AbstractAutoProxyCreator执行postProcessBeforeInstantiation(),其中进行shouldSkip()等判断时,会调用findCandidateAdvisors()获取所有候选的增强器。

AnnotationAwareAspectJAutoProxyCreator中实现了findCandidateAdvisors()方法。AnnotationAwareAspectJAutoProxyCreator通过调用this.aspectJAdvisorsBuilder.buildAspectJAdvisors()获取所有的增强器,aspectJAdvisorsBuilder.buildAspectJAdvisors()通过advisorFactory.getAdvisors(factory)获取增强器。

aspectJAdvisorsBuilder、advisorFactory都是在AnnotationAwareAspectJAutoProxyCreator的initBeanFactory()方法中实例化出来

@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {if (this.aspectJAdvisorFactory == null) {this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);}this.aspectJAdvisorsBuilder =new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}

即最后调用Collections.sort(增强器, METHOD_COMPARATOR)对所有增强器进行排序,排序算法为METHOD_COMPARATOR对象。

METHOD_COMPARATOR对象的定义赋值源码:

private static final Comparator<Method> METHOD_COMPARATOR;static {CompoundComparator<Method> comparator = new CompoundComparator<Method>();// 首选排序方式:根据注解进行排序,顺序依次为:@Around、@Before、@After、@AfterReturning、@AfterThrowingcomparator.addComparator(new ConvertingComparator<Method, Annotation>(new InstanceComparator<Annotation>(Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),new Converter<Method, Annotation>() {@Overridepublic Annotation convert(Method method) {AspectJAnnotation<?> annotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);return (annotation != null ? annotation.getAnnotation() : null);}}));// 当两个增强器的注解相同时,继续用第二种排序方式进行比较:以字符串方式比较增强器的方法名称comparator.addComparator(new ConvertingComparator<Method, String>(new Converter<Method, String>() {@Overridepublic String convert(Method method) {return method.getName();}}));METHOD_COMPARATOR = comparator;
}

所以,如果想自定义一个类似ReflectiveAspectJAdvisorFactory的类MyReflectiveAspectJAdvisorFactory,更改AOP注解排序方式,则需:

  1. 自定义一个类似EnableAspectJAutoProxy的注解MyEnableAspectJAutoProxy,令其@Import注解加载的组件为自定义的组件MyAspectJAutoProxyRegistrar
  2. 修改MyAspectJAutoProxyRegistrar中的AopConfigUtiles为自定义的MyAopConfigUtiles,因为AopConfigUtiles会将AnnotationAwareAspectJAutoProxyCreator加载为beanId为internalAutoProxyCreator的bean。以及修改判断的使能AspectJ注解为MyEnableAspectJAutoProxy
  3. 修改MyAopConfigUtiles中registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法加载的bean类为MyAnnotationAwareAspectJAutoProxyCreator
  4. 修改MyAnnotationAwareAspectJAutoProxyCreator的initBeanFactory()方法中创建的aspectJAdvisorFactory对象为new MyReflectiveAspectJAdvisorFactory(beanFactory)
  5. 在MyReflectiveAspectJAdvisorFactory中的静态代码块中修改成自己需要的排序方式

7、总结

1、Spring 启动,执行invokeBeanFactoryPostProcessors(beanFactory);创建实现了【BeanFactoryProcessor、BeanDefinitionRegistryPostProcessor】接口的Bean。并执行它们的【postProcessBeanFactory()、postProcessBeanDefinitionRegistry()】方法。
2、通过1步骤,向容器中添加了ConfigurationClassPostProcessor【BeanDefinitionRegistryPostProcessor】对象,并调用它的BeanDefinitionRegistryPostProcessor()方法,解析了@Configuration、@EnableAspectJAutoProxy、@Import等注解,又向容器中添加了其他BeanDefinition。比如AnnotationAwareAspectJAutoProxyCreator【SmartInstantiationAwareBeanPostProcessor、BeanFactoryAware】
3、执行registerBeanPostProcessors(beanFactory);创建实现了【BeanPostProcessor、DestructionAwareBeanPostProcessor、InstantiationAwareBeanPostProcessor、SmartInstantiationAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor】接口的Bean。比如就会创建AnnotationAwareAspectJAutoProxyCreator的Bean对象
4、在创建AnnotationAwareAspectJAutoProxyCreator对象的过程中,会调用AbstractAutoProxyCreator.postProcessBeforeInstantiation() ,扫描带有 @Aspect 注解的类,生成 AspectMetadata 对象,并将每个通知方法(@Before、@Around 等)会被封装为 Advisor 对象,包含 Pointcut(切点表达式)和 Advice(通知逻辑)。
5、会在finishBeanFactoryInitialization(beanFactory);方法中通过AbstractAutoProxyCreator.postProcessAfterInitialization()方法,该方法通过 shouldProxyTargetClass 判断是否需要创建代理,如果需要创建代理,根据目标对象实现接口,判断生成JDK代理还是CGLIB代理对象
6、当调用代理对象的方法时,会触发 InvocationHandler.invoke(JDK 代理)或 MethodInterceptor.intercept(CGLIB 代理),进入通知链执行

六、声明式事务使用和原理

1、声明式事务使用

@EnableTransactionManagement
@Configuration
@ComponentScan({"com.linwillen.dao", "com.linwillen.service"})
public class TxConfig {@Beanpublic DataSource dataSource() throws Exception{ComboPooledDataSource dataSource = new ComboPooledDataSource();dataSource.setUser("root");dataSource.setPassword("root");dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ry-seata");return dataSource;}@Beanpublic JdbcTemplate jdbcTemplate() throws Exception {// @Configuration类中的@Bean方法在Spring中被特殊执行,// 此处虽然传入dataSource(),但是Spring不会执行dataSource()方法重新new一个对象,而是会直接从ioc容器中获取return new JdbcTemplate(dataSource());}@Beanpublic PlatformTransactionManager transactionManager() throws Exception{return new DataSourceTransactionManager(dataSource());}
}
@Repository
public class UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void insert() {String sql = "insert into undo_log (branch_id, xid, context, rollback_info, log_status, log_created, log_modified) values(?, ?, ?, ?, ?, ?, ?)";jdbcTemplate.update(sql, "2", "Ind01", "0001", "张三", 1, new Date(), new Date());}
}
@Service
public class UserService {@Autowiredprivate UserDao userDao;@Transactionalpublic void insert() {userDao.insert();}
}

2、@EnableTransactionManagement

@EnableTransactionManagement使用@Import引入了TransactionManagementConfigurationSelector

在这里插入图片描述
AdivceModelmportSelect中获取@EnableTransactionManagement注解的mode属性,传递给selectImports(adviceMode)方法。

TransactionManagementConfigurationSelector根据传入的mode值,选择引入不同的组件。

@EnableTransactionManagement的mode属性默认值为AdviceMode.PROXY,所以默认注册的组件为:

● AutoProxyRegistrar
● ProxyTransactionManagementConfiguration

3、AutoProxyRegistrar

七、扩展原理

观察者模式

1、ApplicationListener

监听容器中发布的事件,完成事件驱动模型开发。

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E event);
}

接口的泛型为监听的事件类型,即只能监听ApplicationEvent及其下面的子类

开发步骤:

  1. 编写一个监听器(实现ApplicationListener接口),来监听某个事件(ApplicationEvent及其子类)
    例如:
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {@Overridepublic void onApplicationEvent(ApplicationEvent event) {System.out.println("收到事件: " + event);}
}
  1. 把监听器加入到容器中(使用@Compenent)
  2. 只要容器中有相关事件的发布,就能监听到这个事件。
    例如:
    ○ ContextRefreshedEvent:容器刷新完成事件(所有bean都完成创建时,Spring会自动发布这个事件)
    ○ ContextClosedEvent:容器关闭事件(Spring自动发布的事件)
  3. 发布一个事件
    使用ioc容器进行发布:
applicationContext.publishEvent(new ApplicationEvent("我的事件") {});

调用过程:

  1. 容器创建中的refresh()方法;
  2. 在容器刷新方法的最后一步,调用了finishRefresh()方法完成容器刷新
  3. 容器完成刷新的方法内发布容器刷新事件:
publishEvent(new ContextRefreshedEvent(this));

publishEvent()方法的事件发布的流程:
a. 获取事件的多播器/派发器:getApplicationEventMulticaster()
b. multicastEvent()派发事件
c. 派发事件方法中获取到所有支持当前事件类型的ApplicationListener

for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {// 如果有Executor,可以使用多线程异步派发Executor executor = getTaskExecutor();if (executor != null) {executor.execute(new Runnable() {@Overridepublic void run() {invokeListener(listener, event);  // 执行listener里面的onApplicationEvent方法}});}else {  // 否则,同步方式直接执行listener里面的onApplicationEvent方法invokeListener(listener, event);}
}

事件多播器(派发器)的注册:

  1. 容器创建对象:refresh()
  2. refresh()方法中有一步调用initApplicationEventMulticaster():初始化ApplicationEventMulticaster;
    先到容器中尝试获取beanId为applicationEventMulticaster的ApplicationEventMulticaster类型组件。
    如果可以获取到,则直接使用;
    如果获取不到,则new SimpleApplicationEventMulticaster(beanFactory);,然后注册到ioc容器中;

监听器的注册:

  1. 容器创建对象:refresh()
  2. refresh()方法中有一步调用registerListeners():注册监听器
    从ioc容器中拿到所有的ApplicationListener类型监听器bean,把它们注册添加到applicationEventMulticaster派发器中;

2、@EventListener & SmartInitializingSingleton

@EventListener

使用@EventListener注解监听事件。

标记在方法上,使用classes属性声明要监听的事件类型。ApplicationEvent类型的方法参数可以获得到该事件。

示例:

@Service
public class UserService {@EventListener(classes = {ApplicationEvent.class})public void listener(ApplicationEvent event) {System.out.println("得到事件:" + event);}
}

使用EventListenerMethodProcessor处理器来解析方法上的@EventListener注解。

EventListenerMethodProcessor实现了SmartInitializingSingleton接口。

SmartInitializingSingleton

在所有单实例bean都创建完成之后调用,调用的时机类似ContextRefreshedEvent。

接口方法:

● afterSingletonsInstantiated()

调用过程:

  1. ioc创建对象并刷新容器:refresh()
  2. refresh()调用finishBeanFactoryInitialization()
  3. finishBeanFactoryInitialization()初始化剩下的单实例bean
    a. 遍历所有待创建的单实例bean,调用getBean()创建所有的单实例bean
    b. 获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型。
    如果是该类型,就调用其afterSingletonsInstantiated()方法

八、容器创建源码

Spring的refresh()方法进行容器的创建和刷新,进入AbstractApplicationcontext类的refresh()方法中。

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing./*** 做容器刷新前的准备工作* 1、设置容器的启动时间* 2、设置活跃状态为true* 3、设置关闭状态为false* 4、获取Environment对象,并加载当前系统的属性值到Environment对象中* 5、准备监听器和事件的集合对象,默认为空的集合,留给子类做扩展*/prepareRefresh();//1// Tell the subclass to refresh the internal bean factory.// 创建容器对象:DefaultListableBeanFactory// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinitionConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//2// Prepare the bean factory for use in this context.// beanFactory的准备工作,对各种属性进行填充prepareBeanFactory(beanFactory);//3try {// Allows post-processing of the bean factory in context subclasses.// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的postProcessBeanFactory(beanFactory);//4// Invoke factory processors registered as beans in the context.// *****调用各种beanFactory处理器invokeBeanFactoryPostProcessors(beanFactory);//5// Register bean processors that intercept bean creation.// 注册bean处理器,这里只是注册功能,真正调用的是getBean方法registerBeanPostProcessors(beanFactory);//6// Initialize message source for this context.// 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的时候通过国际化的代码重点讲initMessageSource();//7// Initialize event multicaster for this context.// 初始化事件监听多路广播器initApplicationEventMulticaster();//8// Initialize other special beans in specific context subclasses.// 留给子类来初始化其他的beanonRefresh();//9// Check for listener beans and register them.// 在所有注册的bean中查找listener bean,注册到消息广播器中registerListeners();//10// Instantiate all remaining (non-lazy-init) singletons.// 初始化剩下的单实例(非懒加载的)finishBeanFactoryInitialization(beanFactory);//11// Last step: publish corresponding event.// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人finishRefresh();//12}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}

1、prepareRefresh()

调用prepareRefresh() 进行容器的预处理

(1)调用initPropertySources() 初始化属性设置

AbstractApplicationContext 类中的该方法是空的,留给子类进行实现。子类自定义个性化的属性设置方法

(2)如果在(1)步有自定义的属性配置,则调用 getEnvironment().validateRequiredProperties();对属性进行一些必输等校验。
(3)创建List集合,用来保存容器中的一些早期事件

this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();

2、obtainFreshBeanFactory()

调用 obtainFreshBeanFactory() 获取 beanFactory

(1)调用 refreshBeanFactory();刷新beanFactory(修改标志位refreshed为true)。然后设置了序列号ID

(2)进入GenericApplicationContext类中,构造方法中创建了 beanFactory

public GenericApplicationContext() {this.beanFactory = new DefaultListableBeanFactory();
}

3、prepareBeanFactory(beanFactory)

进行beanFactory的预准备工作,对beanFactory进行一些设置

(1)设置beanFactory的类加载器、支持的表达式解析器等等
(2)添加部分的后置处理器

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

(3) 设置要忽略自动装配的接口,很多同学理解不了为什么此处要对这些接口进行忽略,原因非常简单,这些接口的实现是由容器通过set方法进行注入的,所以在使用autowire进行注入的时候需要将这些接口进行忽略

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

(4)注册可以解析的自动装配。我们可以在任何组件中使用 @Autowired等注解自动注入以下组件

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

(5)继续添加后置处理器

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

(6)添加编译时的AspectJ支持

在java中织入分为三种方式,分为编译器织入,类加载器织入,运行期织入。

  1. 编译器织入是指在java编译器,采用特殊的编译器,将切面织入到java类中
  2. 类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面
  3. 运行期织入则是采用cglib和jdk进行切面的织入

aspectj提供了两种织入方式

  1. 第一种是通过特殊编译器,在编译器,将aspectj语言编写的切面类织入到java类中
  2. 第二种是类加载期织入,就是下面的load time weaving
if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));// Set a temporary ClassLoader for type matching.beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

(7)给beanFactory中注册一些环境组件

// 注册默认的系统环境bean到一级缓存中
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
}

4、postProcessBeanFactory(beanFactory)

AbstractApplicationContext中这个方法为空方法,子类可以重写这个方法,在beanFactory创建并预准备完成之后的后置处理工作。比如:可以查看web中的代码,是有具体实现的

1~4是BeanFactory的创建以及预准备工作

5、invokeBeanFactoryPostProcessors(beanFactory)

执行 BeanFactoryPostProcessors。BeanFactoryPostProcessor 是 bean工厂的后置处理器。在BeanFactory标准初始化之后执行的。
它有两大接口:

  • BeanFactoryProcessor
  • BeanFactoryProcessor下的BeanDefinitionRegistryPostProcessor
// 此处传入的 AbstractApplicationContext的 getBeanFactoryPostProcessors() 默认是空的
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

(1) 定义 regularPostProcessors 集合用来存放普通的 BeanFactoryProcessors
(2)定义 registryProcessors 集合用来存放 BeanDefinitionRegistryPostProcessor 类型的 BeanFactoryProcessors
(3)如果传入的 AbstractApplicationContext.getBeanFactoryPostProcessors() 有内容,则先执行其中的 BeanDefinitionRegistryPostProcessor类型后置处理器的 postProcessBeanDefinitionRegistry 方法。并把 beanFactoryPostProcessors 存入对应的集合中
(4)获取ioc容器中的 BeanDefinitionRegistryPostProcessors 并执行:

  1. 获取所有 PriorityOrdered类型的后置处理器,执行其 postProcessBeanDefinitionRegistry方法,并加入 registryProcessors 数组
  2. 获取所有 Ordered 类型的后置处理器,执行其 postProcessBeanDefinitionRegistry方法,并加入 registryProcessors 数组
  3. 获取所有无排序的后置处理器,执行其 postProcessBeanDefinitionRegistry方法,并加入 registryProcessors 数组
此处使用了循环获取,在获取一遍后会接着再获取下一遍,直到获取不到。
猜测可能有些后置处理器的postProcessBeanDefinitionRegistry方法会再向容器添加BeanDefinitionRegistryPostProcessors
  1. 执行 registryProcessors 集合中的所有后置处理器的 postProcessBeanFactory方法
  2. 执行 regularPostProcessors 集合中的所有BeanFactoryPostProcessors 的 postProcessBeanFactory方法

(5)获取 ioc 容器中的普通BeanFactoryPostProcessors并执行

  1. 获取容器中所有 BeanFactoryPostProcessors,并按照是否属于PriorityOrdered、是否属于Ordered、是否是无排序进行归类
  2. 执行所有PriorityOrdered类型的BeanFactoryPostProcessors 的postProcessBeanFactory方法
  3. 执行所有Ordered类型的BeanFactoryPostProcessors 的postProcessBeanFactory方法
  4. 执行所有无排序的BeanFactoryPostProcessors 的postProcessBeanFactory方法

6、registerBeanPostProcessors(beanFactory)

调用registerBeanPostProcessors(beanFactory) ,注册 Bean后置处理器,拦截bean的创建过程
BeanPostProcessor接口的子接口:

  • BeanPostProcessor
  • DestructionAwareBeanPostProcessor
  • InstantiationAwareBeanPostProcessor
  • SmartInstantiationAwareBeanPostProcessor
  • MergedBeanDefinitionPostProcessor

(1)获取所有的BeanPostProcessor。后置处理器也可以通过 PriorityOrdered、Ordered接口设置优先级
(2)注册PriorityOrdered优先级接口的后置处理器,把后置处理器添加进BeanFactory中
(3)再注册Ordered接口的后置处理器
(4)再注册没有实现优先级接口的后置处理器
(5)注册MergedBeanDefinitionPostProcessor
(6)注册ApplicationListenerDetector

ApplicationListenerDetector用来在Bean创建完成后检查是否为ApplicationListener,如果是则添加进容器的监听器中

7、initMessageSource()

初始化MessageSource组件(做国际化功能,消息绑定,消息解析)

(1)获取BeanFactory
(2)判断容器中是否存在beanID为messageSource、类型为MessageSource的bean
如果存在,则赋值给容器的messageSource属性;
如果没有,则创建一个DelegatingMessageSource对象,注册到容器中。

可以通过MessageSource对象的getMessage方法获取到国际化资源文件中对应的key值

8、initApplicationEventMulticaster()

初始化事件派发器

(1) 获取BeanFactory
(2) 从BeanFactory中获取beanID为applicationEventMulticaster、ApplicationEventMulticaster类型的事件派发器,如果从容器中获取不到,就会创建一个SimpleApplicationEventMulticaster类型的事件派发器,并添加进容器中

9、onRefresh()

初始化其他的一些特殊Bean,默认为空实现,留给子类进行自定义重写

10、registerListener()

给容器中注册所有的ApplicationListener

(1)从容器中获取所有的ApplicationListener
(2)将每个监听器添加进事件派发器中

getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

(3)派发之前步骤产生的事件

11、finishBeanFactoryInitialization(beanFactory)

初始化所有剩下的单实例bean

beanFactory.preInstantiateSingletons();初始化剩下的单实例bean
(1)获取容器中的所有Bean,依次进行初始化和创建对象
(2)获取Bean的定义信息:RootBeanDefinition
(3)Bean不是抽象的,是单实例的,不是懒加载的
3.1 判断如果是FactoryBean(是否是实现FactoryBean接口的工厂Bean),利用工厂方法创建对象
3.2 如果不是工厂Bean,调用getBean(beanName)创建对象
3.3 getBean(beanName)调用doGetBean()创建对象
3.3.1 先从缓存中保存的单实例bean尝试获取,如果能获取到说明这个Bean之前被创建过(所有创建过的单实例bean都会被缓存起来)

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

3.3.2 缓存中获取不到时,准备开始Bean的创建对象流程
3.3.3 markBeanAsCreated()标记当前Bean已经被创建,防止多线程运行时同一个单实例bean被多次创建
3.3.4 获取bean的定义信息RootBeanDefinition
3.3.5 getDependsOn()获取当前bean依赖的其他bean,如果有,按照getBean()的方式把依赖的bean创建出来
3.3.6 启动单实例bean的创建流程

sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {@Overridepublic Object getObject() throws BeansException {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

3.3.7 createBean()的内部实现
3.3.8 在创建Bean对象之前,提前执行InstantiationAwareBeanPostProcessor类型的BeanPostProcessor,给后置处理器一个机会返回一个代理对象

// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

调用applyBeanPostProcessorsBeforeInstantiation()触发InstantiationAwareBeanPostPRocessor的postProcessBeforeInstantiation()方法;
如果前一步有返回值(即要返回代理对象,不继续后面的bean创建和初始化),则继续调用applyBeanPostProcessorAfterInitialization()触发postProcessAfterInitialization()方法
3.3.9 如果上一步没有返回代理对象,则调用doCreateBean()创建bean
3.3.9.1 创建bean实例:createBeanInstance();利用工厂方法或者对象的构造器创建出Bean实例,此时的bean对象被构造出来,但是还未进行属性的赋值
3.3.9.2 调用applyMergedBeanDefinitionPostProcessors(),执行MergedBeanDefinitionPostProcessors的postProcessMergedBeanDefinition()方法
3.3.9.3 调用populateBean()为bean的属性进行赋值
3.3.9.3.1 获取InstantiationAwareBeanPostProcessor后置处理器,执行后置处理器的postProcessAfterInstantiation()方法
3.3.9.3.2 执行InstantiationAwareBeanPostProcessor后置处理器的postProcessPropertyValue()方法
3.3.9.3.3 调用applyPropertyValues(),反射bean的setter方法进行赋值
3.3.9.4 调用initializeBean()进行bean的初始化
3.3.9.4.1 调用invokeAwareMethods()执行xxxxAware接口的方法:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
3.3.9.4.2 调用applyBeanPostProcessorsBeforeInitialization(),执行BeanPostProcessor的postProcessBeforeInitialization()方法

12、finishRefresh()

完成BeanFactory的创建工作,IOC容器创建完成

(1)initLifecycleProcessor();初始化和生命周期有关的后置处理器;LifecycleProcessor

默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new DefaultLifecycleProcessor()
加入到容器;

写一个LifecycleProcessor的实现类, 可以在BeanFactory

void onRefresh();

void onclose();
(2)getLifecycleProcessor().onRefresh();
拿到前面定义的生命周期处理器(BeanFactory);回调onRefresh();

(3)publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件

总结

1、在spring容器启动后,向容器中添加配置类的BeanDefinition,此时这个配置类加了什么注解也会被记录
2、invokeBeanFactoryPostProcessors(beanFactory)
2.1 处理BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor接口,优先处理BeanDefinitionRegistryPostProcessor,如果都是BeanDefinitionRegistryPostProcessor接口会根据是否有PriorityOrdered、Ordered接口进行排序处理
2.2 ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry 向容器中注入配置类里声明的BeanDefinition信息。比如会解析@Configuration、@Component、@Bean、@ComponentScan、@Import、@ImportResource、@Order等等注解,调用BeanDefinitionRegistry.registerBeanDefinition向容器中注入Bean定义信息,同时也会调用@Import注解实现了ImportBeanDefinitionRegistrar接口的方法向容器中注入Bean定义信息
3、registerBeanPostProcessors(beanFactory):创建实现了BeanPostProcessor接口的类,调用getBean()方法获取对象并加入到容器中,注意这里只是注册,真正调用BeanPostProcessor是在getBean方法
4、finishBeanFactoryInitialization(beanFactory);实例化并初始化剩下的Bean

九、Servlet3.0

1、Servlet3.0概述

JSR 315规范。不再需要 web.xml,可以直接通过 @WebServlet等相关注解配置Servlet

@WebServlet("/hello")
public class HelloServlet extends HttpServlet{@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("hello");resp.getWriter().write("hello...");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}}

2、共享库/运行时插件能力

ServletContainerInitializer

Servlet容器启动会扫描当前应用里面每一个jar包的 ServletContainerInitializer接口 的实现类。

该实现类必须绑定在 META-INF/services/javax.servlet.ServletContainerInitializer文件中,该文件的内容就是ServletContainerInitializer实现类的全类名。

总结:Servlet容器启动时,会扫描当前应用每一个jar包(或者类路径下)的 META-INF/services/javax.servlet.ServletContainerInitializer文件中指定的实现类,启动并运行这个实现类的方法

示例:
编写ServletContainerInitializer的实现类,实现其onStartup()方法

public class MyServletInitializer implements ServletContainerInitializer{@Overridepublic void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {System.out.println("MyServletContainerInitializer启动了......");}
}

在src下创建文件夹:META-INF/services,在该文件夹下创建javax.servlet.ServletContainerInitializer文件,并写入ServletContainerInitializer接口实现类的全类名:

com.study.servlet.init.MyServletInitializer

启动tomcat,MyServletInitializer的onStartup()方法也会自动跟着启动

@HandlesTypes

ServletContainerInitializer实现类可以添加@HandlesTypes注解,并传入注解指定的类型数组。onStartup()方法会接收到@HandlesTypes指定的类型的所有子类/子接口/实现类/子类的子类等,但是不接收指定的类型本身

示例:
编写接口HelloService
编写接口HelloServiceSub,继承与HelloService
编写抽象类AbstractHelloService,实现HelloService接口
编写类HelloServiceImpl,实现HelloService接口
编写类AbstractHelloServiceImpl,实现抽象类AbstractHelloService

@HandlesTypes({HelloService.class})
public class MyServletInitializer implements ServletContainerInitializer{@Override/*** 应用启动的时候,会运行onStartup方法* @param c 接收HandlesType指定的类型下面的子类/实现类/子接口(HandleTypes指定的类型本身接收不到)* @param ctx 代表当前Web应用的ServletContext,一个Web应用对应一个ServletContext*/public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {c.forEach(handleClass -> System.out.println(handleClass.getSimpleName()));System.out.println("MyServletContainerInitializer启动了......");}
}

tomcat启动后,控制台输出结果:

AbstractHelloServiceImpl
HelloServiceSub
HelloServiceImpl
AbstractHelloService
MyServletContainerInitializer启动了......

ServletContext

有时候引入的第三方的jar包会包含一些Filter、Servlet,但是无法修改jar包内容为其添加@WebServlet注解,此时可以通过onStartup()方法的ServletContext参数为Servlet容器添加组件

示例:
编写Servlet类:

public class HelloServlet extends HttpServlet{@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("hello");resp.getWriter().write("hello...");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

在ServletContainerInitializer实现类的onStartup()方法中,将该Servlet添加进Servlet容器:

public class MyServletInitializer implements ServletContainerInitializer{@Overridepublic void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {Dynamic helloServlet = ctx.addServlet("helloServlet", new HelloServlet());helloServlet.addMapping("/hello");System.out.println("MyServletContainerInitializer启动了......");}
}

注意:
使用编码的方式,在项目启动的时候给ServletContext里面添加组件:

  • 并非所有获取到的ServletContext都能添加组件,必须在项目启动的时候才能添加
  • 可以在ServletContainerInitializer实现类的onStartup()方法里得到的ServletContext进行添加
  • 可以在监听器ServletContextListener的contextInitialized(ServletContextEvent arg)方法的ServletContextEvent进行获取添加
@Override
public void contextInitialized(ServletContextEvent arg) {ServletContext sc = arg.getServletContext();// TODO 添加组件
}

3、Spring中使用Servlet3.0

SpringMVC中的ServletContainerInitializer

SpringMVC的 spring-web-xxxx.jar 包中带有 META-INF/services/javax.servlet.ServletContainerInitializer文件,文件内容 为:

org.springframework.web.SpringServletContainerInitializer

SpringServletContainerInitializer类实现了ServletContainerInitializer接口,并使用@HandlesTypes注解引入了WebApplicationInitializer接口
源码如下:

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {@Overridepublic void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)throws ServletException {List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();// 遍历WebApplicationInitializer接口的实现类,添加进initializers数组if (webAppInitializerClasses != null) {for (Class<?> waiClass : webAppInitializerClasses) {if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&WebApplicationInitializer.class.isAssignableFrom(waiClass)) {// ....initializers.add((WebApplicationInitializer) waiClass.newInstance());}}}// ......// 遍历执行每个WebApplicationInitializer实现类的onStartup()方法AnnotationAwareOrderComparator.sort(initializers);for (WebApplicationInitializer initializer : initializers) {initializer.onStartup(servletContext);}}
}

WebApplicationInitializer接口源码如下:

public interface WebApplicationInitializer {void onStartup(ServletContext servletContext) throws ServletException;
}

SpringMVC默认的WebApplicationInitializer抽象实现

WebApplicationInitializer接口的抽象实现类:

  • AbstractContextLoaderInitializer
  • AbstractDispatcherServletInitializer
  • AbstractAnnotationConfigDispatcherServletInitializer
  • AbstractReactiveWebInitializer

(1)AbstractContextLoaderInitializer
创建根容器
(2)AbstractDispatcherServletInitializer
创建一个Web的IOC容器:createServletApplicationContext()
创建前端控制器:createDispatcherServlet(servletAppContext)
将创建的DispatcherServlet添加进ServletContext中,并通过实现getServletMapping()设置Mapping等配置:

FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());

(3)AbstractAnnotationConfigDispatcherServletInitializer
注解方式配置的初始化器。
创建根容器:createRootApplicationContext()方法中,通过实现getRootConfigClasses()传入配置类,根据配置类注册根容器
创建web的ioc容器:createServletApplicationContext()方法中,通过实现getServletConfigClasses()传入配置类,根据配置类创建web的ioc容器

如果以注解方式启动SpringMVC,继承AbstractAnnotationConfigDispatcherServletInitializer,实现对应的抽象方法指定DispatcherServlet的配置信息。
根容器(Root WebApplicationContext)用来扫描Services、Repositories。
Web的ioc容器(Servlet WebApplicationContext)用来扫描 Controllers、ViewResolver、HandlerMapping。

示例配置

编写根容器配置类:根容器不扫描 Controller

@ComponentScan(value="com.study", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = { Controller.class })
})
public class RootConfig {
}

编写Web的ioc容器配置类:web的ioc容器只扫描Controller

// 必须使用 userDefaultFilters=false 禁用默认的过滤规则,否则includeFilters不能生效
@ComponentScan(value = "com.study", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = false)
public class AppConfig {
}

编写启动类:AbstractAnnotationConfigDispatcherServletInitializer实现了 WebApplicationInitializer,只需继承该类即可。

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {@Override/*** 获取根容器的配置类:(对应以前的Spring的配置文件)*/protected Class<?>[] getRootConfigClasses() {return new Class[] { RootConfig.class };}@Override/*** 获取Web容器的配置类:(对应以前的SpringMVC配置文件)*/protected Class<?>[] getServletConfigClasses() {return new Class[] { AppConfig.class };}@Override/*** 获取DispatcherServlet的映射信息*/protected String[] getServletMappings() {/*"/" : 拦截所有请求(包括静态资源 *.js、*.png等),但是不拦截 *.jsp"/*" : 拦截所有请求,会拦截 *.jsp*/return new String[] {"/"};}
}

定制SpringMVC

  1. 使用@EnableMVC注解开启SpringMVC的定制配置功能
    等同于xml配置中的 mvc:annotation-driven/
  2. 实现WebMvcConfigrer接口,或者继承WebMvcConfigrerAdapter,重写想要配置的方法即可
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {@Override/*** 配置视图解析器*/public void configureViewResolvers(ViewResolverRegistry registry) {registry.jsp("/WEB-INF/views/", ".jsp");}@Override/*** 配置静态资源访问*/public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();}
}

4、异步请求处理

  1. 在 Servlet3.0之前,Servlet采用Thread-Per-Request的方式处理请求,即每一次Http请求都由某一个线程从头到尾负责处理。
  2. 如果一个请求需要进行IO操作,比如访问数据库、调用第三方服务接口等,那么其所对应的线程将同步地等待IO操作完成,而IO操作是非常慢的,所以此时的线程并不能及时地释放回收线程池以供后续使用,在并发量越来越大的情况下,这将带来严重的性能问题。即便是像Spring、Structs这样的高层框架也脱离不了这样的桎梏,因为他们都是建立在Servlet之上的。为了解决这样的问题,Servlet3.0引入了异步处理,然后在 Servlet 3.1 中又引入了非阻塞IO来进一步增强异步处理的性能。

Servlet3.0原生异步处理

  1. 在@WebServlet注解中设置asyncSupported=true
  2. 在doGet()/doPost()方法中,通过req.startAsync()获取到AsyncContext对象
  3. 调用AsyncContext对象的start()方法,传入一个Thread线程对象
  4. 在线程的run()方法中,使用AsyncContext对象的complete()方法完成操作
  5. AsyncContext对象可以获取request、response进行后续操作

示例程序:

@WebServlet(value = "/helloAsync", asyncSupported = true)
public class HelloAsyncServlet extends HttpServlet{@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("主线程开始: " + Thread.currentThread());AsyncContext startAsync = req.startAsync();startAsync.start(() -> {try {System.out.println("子线程开始:" + Thread.currentThread());sayHello();startAsync.complete();
//				AsyncContext asyncContext = req.getAsyncContext();ServletResponse response = startAsync.getResponse();response.getWriter().write("hello Async");System.out.println("子线程结束开始:" + Thread.currentThread());} catch (Exception e) {e.printStackTrace();}});System.out.println("主线程结束: " + Thread.currentThread());}public void sayHello() throws Exception {Thread.sleep(3000);}}

SpringMVC的Callable

返回一个Callable类型的返回值。

示例程序:

@Controller
public class AsyncController {@RequestMapping("/asyncTest01")public Callable<String> asyncTest01() {/*Callable<String> callable = new Callable<String>() {@Overridepublic String call() throws Exception {Thread.sleep(2000);return "asyncTest01 exec......";}};return callable;*/return () -> {Thread.sleep(2000);return "success";};}
}

如果加了拦截器,拦截在这里插入代码片器的preHandle()方法会执行两次,SpringMVC执行过程如下:

拦截器preHandle.......
主线程开始....
主线程结束....
-----------至此,DispatcherServlet及所有Filter退出线程------------------Callable开始执行----------
Callable子线程开始....
Callable子线程结束....
----------Callable执行结束---------------------SpringMVC将请求重新派发给容器--------------
拦截器preHandle...
拦截器posthandle.....Callable的返回值就是目标方法返回值,此时不再执行目标方法)
拦截器afterCompletion.....

原理:

  1. 控制器返回Callable
  2. Spring异步处理:将Callable提交到TaskExecutor,使用一个隔离的线程进行执行
  3. DispatcherServlet和所有的Filter退出Web容器的线程,但是Response保持打开状态
  4. Callable返回结果,SpringMVC将请求重新派发给容器,恢复之前的处理
  5. 根据Callable返回的结果,SpringMVC继续进行视图渲染等(从收请求-视图渲染 重新进行)

SpringMVC的异步拦截器

SpringMVC的普通拦截器并不能拦截到真正的Callable请求。如果需要拦截异步请求,则需要使用异步拦截器:

  • 使用原生API的AsyncListener
  • 使用SpringMVC的AsyncHandlerInterceptor接口

SpringMVC的DeferredResult

使用步骤:

  1. 在Controller中创建一个DeferredResult对象,并保存进消息队列或其他位置中
  2. 将该DeferredResult对象进行返回
  3. 编写一个监听,消费消息队列里面的DeferredResult对象
  4. 将结果通过DeferredResult对象的setResult()方法设置给DeferredResult对象

示例程序:

@Controller
public class AsyncController {/*** 创建订单请求*/@RequestMapping("/createOrder")@ResponseBodypublic DeferredResult<Object> createOrder() {// 创建一个deferredResult对象,保存进消息队列中// 并不直接进行订单的创建。等其他线程消费该消息队列的deferredResult对象,并通过setResult()给deferredResult对象设置结果之后,将结果响应给浏览器DeferredResult<Object> deferredResult = new DeferredResult<>(3000L, "create failed ...");DeferredResultQueue.save(deferredResult);return deferredResult;}/*** 模拟监听器,执行消息队列中的DeferredResult对象*/@RequestMapping("/create")@ResponseBodypublic String create() {// 从消息队列中取出deferredResult对象,进行订单的创建String orderNo = UUID.randomUUID().toString();DeferredResult<Object> deferredResult = DeferredResultQueue.get();// 设置要响应给浏览器的内容deferredResult.setResult("orderNo=" + orderNo);return "success: " + orderNo;}
}

模拟消息队列的程序:

// 模拟消息队列
public class DeferredResultQueue {private static Queue<DeferredResult<Object>> queue = new ConcurrentLinkedDeque<>();// 向队列中添加内容public static void save(DeferredResult<Object> deferredResult) {queue.add(deferredResult);}// 消费队列中的对象public static DeferredResult<Object> get() {return queue.poll();}
}
http://www.dtcms.com/a/269634.html

相关文章:

  • Rust 的 Copy 语义:深入浅出指南
  • 广度优先与深度优先遍历核心逻辑理解及实践
  • Java零基础笔记07(Java编程核心:面向对象编程 {类,static关键字})
  • CompareFace人脸识别算法环境部署
  • 项目进度受外包团队影响,如何管控交付节奏
  • 原生屏幕旋转算法(AccelSensor)
  • C++STL详解(一):string类
  • 分布式理论:CAP、Base理论
  • 【机器学习深度学习】为什么分类任务中类别比例应接近 1:1?
  • gloo 多卡训练
  • MiniMind:3小时训练26MB微型语言模型,开源项目助力AI初学者快速入门
  • CANDENCE 17.4 进行元器件缓存更新
  • Python爬虫实战:研究phonenumbers工具相关技术
  • Git 提交规范-备忘
  • 【STM32】ADC模数转换基本原理
  • EtherCAT与Profinet协议转换在工业自动化中的应用:以汇川伺服驱动器为例
  • 【FR801xH】富芮坤FR801xH之全功能按键案例
  • JVM系列六:JVM性能调优实战指南
  • Java基础回顾(1)
  • 7 种简单方法将三星文件传输到电脑
  • 瞄准Win10难民,苹果正推出塑料外壳、手机CPU的MacBook
  • 用户生命周期与改进型RFM模型
  • C#读取modbus值,C#读写modbus,支持读写uint32值,Modbus TCP工具类
  • HTTPS工作原理
  • java获取文件的消息摘要APP进行文件完整性校验
  • JavaScript基础篇——第二章 类型转换与常见错误解析
  • 二分查找篇——搜索二维矩阵【LeetCode】遍历法
  • qt-C++笔记之setCentralWidget的使用
  • Visual Studio Code 中统一配置文件在团队协作中的应用
  • 论文略读:Prefix-Tuning: Optimizing Continuous Prompts for Generation