1、导入依赖 spring-context
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.5.RELEASEversion>
dependency>
2、编写Spring配置文件 beans.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
beans>
3、编写一个实体类 Person
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Person {
private String name;
private int age;
4、在Spring配置文件中配置Bean
<context:component-scan base-package="com.hh">context:component-scan>
<bean id="person" class="com.hh.bean.Person">
<property name="name" value="haohao">property>
<property name="age" value="18">property>
bean>
5、编写测试类
public class MainTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = context.getBean("person", Person.class);
System.out.println(person);
}
}
6、测试
Person{name='haohao', age=18}
在方法上面加上@Bean注解后,Spring会以方法返回类型作为组件的类型,方法名作为组件的 id
当向@Bean中添加参数时,默认添加的第一个参数是value,强制给组件赋值id
//配置类==配置文件beans.xml
@Configuration //告诉Spring这是一个配置类
@ComponentScan(value = "com.hh",includeFilters={
// @ComponentScan.Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
// @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),
@ComponentScan.Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
},useDefaultFilters=false)
//Filter[] excludeFilters() 指定扫描的时候按照什么规则排除那些组件
//ComponentScan.Filter[] includeFilters() default {}; 指定扫描的时候只需要包含那些组件
//FilterType.ANNOTATION 按照注解 常用
//FilterType.ASSIGNABLE_TYPE 按照类型 常用
//FilterType.ASPECTJ 按照ASPECTJ表达式,不太常用
//FilterType.REGEX 按照正则指定
//FilterType.CUSTOM 使用自定义规则 常用
public class MainConfig {
//给容器中注册一个Bean,类型就是返回值的类型,id默认方法名
@Bean
public Person person(){
return new Person("haohao",5);
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person bean = applicationContext.getBean(Person.class);
System.out.println(bean);
}
结果:
Person{name='haohao', age=5}
只要标注了@Controller、@Service、@Repository、@Component
的,都会被扫描加入到容器里
注意:配置类自身也会被扫描到容器中,如果存在多个配置类,则多个配置类里的所有bean对象都会被扫描进容器中
<context:component-scan base-package="com.hh">context:component-scan>
在配置类上添加注解@ComponentScan(value="")
//配置类==配置文件
@Configuration //告诉Spring这是一个配置类
@ComponentScan(value = "com.hh",includeFilters={
@ComponentScan.Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),
@ComponentScan.Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
},useDefaultFilters=false)
//Filter[] excludeFilters() 指定扫描的时候按照什么规则排除那些组件
//ComponentScan.Filter[] includeFilters() default {}; 指定扫描的时候只需要包含那些组件
//FilterType.ANNOTATION 按照注解
//FilterType.ASSIGNABLE_TYPE 按照类型
//FilterType.ASPECTJ 按照ASPECTJ表达式,不太常用
//FilterType.REGEX 按照正则指定
//FilterType.CUSTOM 使用自定义规则
public class MainConfig {
//...
}
注解排除excludeFilters的返回类型为Filter[]
Filter 的排除类型 FilterType 有以下几种:
下面以ANNOTATION按注解排除来示例:
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
public class MainConfig {
// ...
}
ComponentScan.Filter[] includeFilters() default {}; 指定扫描的时候只需要包含那些组件
注意要关闭默认的扫描过滤器
Filter 的指定类型 FilterType 同上
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
}, useDefaultFilters = false)
public class MainConfig {
// ...
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.xjhqre", includeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookController.class})
}, useDefaultFilters = false)
public class MainConfig {
// ...
}
public class MyTypeFilter implements TypeFilter {
/**
*
* @param metadataReader :读取到的当前正在扫描的类的信息
* @param metadataReaderFactory:可以获取到其他任何类的信息
* @return
* @throws IOException
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解的信息
ClassMetadata classMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的类信息
ClassMetadata classMetadata1 = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
if(className.contains("er")){
return true;
}
return false;
}
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh", includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
}, useDefaultFilters = false)
public class MainConfig {
// ...
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh")
public class MainConfig2 {
@Bean("person")
public Person person(){
System.out.println("给容器中添加Person--");
return new Person("吉吉", 3);
}
}
@Test
public void Test2(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
System.out.println("ioc容器创建完成......");
Object person1 = applicationContext.getBean("person");
Object person2 = applicationContext.getBean("person");
System.out.println(person1==person2);//true 默认是单实例 要是Scope改为prototype 则是false
}
ConfigurableBeanFactory#SCOPE_PROTOTYPE prototype
单实例
ConfigurableBeanFactory#SCOPE_SINGLETON singleton
多实例
org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST request
org.springframework.web.context.WebApplicationContext#SCOPE_SESSION session
后两个需要导入 Spring web 的jar包,且基本不用,只讨论前两个
在ConfigurableBeanFactory中有两个常量:
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = “prototype”;
WebApplicationContext中的两个常量
String SCOPE_REQUEST = “request”;
String SCOPE_SESSION = “session”;
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh")
public class MainConfig2 {
@Bean("person")
@Scope("prototype")
public Person person() {
return new Person("haohao", 5);
}
}
@Test
public void Test2(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
System.out.println("ioc容器创建完成......");
Object person1 = applicationContext.getBean("person");
Object person2 = applicationContext.getBean("person");
System.out.println(person1==person2);//false 默认是单实例 要是Scope改为prototype 则是false
}
懒加载:
只需要在方法上添加注解 @Lazy
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh")
public class MainConfig2 {
@Lazy
@Bean("person")
public Person person(){
System.out.println("给容器中添加Person--");
return new Person("吉吉", 3);
}
}
@Conditional 源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* All {@link Condition Conditions} that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
Condition接口源码:
@FunctionalInterface
public interface Condition {
/**
* ConditionContext:判断条件能使用的上下文环境
* AnnotatedTypeMetadata:注释信息
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
编写windows条件,需要实现接口Condition,重写matches方法
public class WindowsConditional implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();//获取环境
String property = environment.getProperty("os.name");//获取属性
if(property.contains("Windows")){
return true;
}
return false;
}
}
/**
* 判断是否是Linux系统
*/
public class LinuxConditional implements Condition {
/**
*
* @param context :判断条件能使用的上下文环境
* @param metadata :注释信息
* @return
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//是否Linux环境
//1、能获取到ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2.获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3、获取当前环境信息
Environment environment = context.getEnvironment();
//4.获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
//5.可以判断容器中的bean注册情况,也可以给容器中注册bean
registry.containsBeanDefinition("person");
String property = environment.getProperty("os.name");
if(property.contains("Linux")){
return true;
}
return false;
}
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh")
public class MainConfig3 {
@Conditional({WindowsConditional.class})
@Bean("jiji")
public Person person1(){
return new Person("吉吉国王",5);
}
@Conditional(LinuxConditional.class)
@Bean("haohao")
public Person person2(){
return new Person("好好",3);
}
}
@Test
public void Test3(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig3.class);
Environment environment = applicationContext.getEnvironment();
//动态获取环境变量的值 : Windows 10
String property = environment.getProperty("os.name");
System.out.println(property);// Windows 10
Map<String, Person> person = applicationContext.getBeansOfType(Person.class);
System.out.println(person);
}
结果:
{jiji=Person{name='吉吉国王', age=5}}
当@Conditional配置在类上时,表示只有满足条件时,这个配置类配置的所有bean才会生效
给容器中注册组件:
包扫描+组件标注注解(@controller/@Service/@Repository/@Component
):自己写的类
@Bean:导入的第三方包
@Import:快速的给容器中导入一个组件
@Import(要导入到容器中的组件):容器就会自动注册这个组件,id 默认是全类名
ImportSelector 接口: 实现类返回需要导入的组件的全类名数组
ImportBeanDefinitionRegistrar实现类,会调用接口的方法,使用BeanDefinitionRegistry注册bean
使用Spring提供的FactoryBean(工厂Bean)
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh")
//@Import导入组件,id默认是全类名 com.hh.bean.Color
@Import({Color.class, Red.class})
public class MainConfig3 {
}
@Test
public void test4() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig3.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
测试:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig3
com.hh.bean.Color
com.hh.bean.Red
/**
* 自定义逻辑返回需要导入的组件
*/
public class MyImportSelector implements ImportSelector {
/**
* AnnotationMetadata 当前标注@Import注解的类的所有注解信息
* @param importingClassMetadata
* @return 返回值 就是导入到容器中的组件全类名
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.hh.bean.Blue","com.hh.bean.Yellow"};
}
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh")
@Import({Color.class, Red.class, MyImportSelector.class}) // 导入组件,id默认是组件的全类名
public class MainConfig3 {}
@Test
public void test4() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig3.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig3
com.hh.bean.Color
com.hh.bean.Red
com.hh.bean.Blue
com.hh.bean.Yellow
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param importingClassMetadata
* @param registry
* @param importBeanNameGenerator
* AnnotationMetadata 当前类的注解信息
* BeanDefinitionRegistry BeanDefinition注册类
* 把所有需要添加到容器中的bean:调用
* BeanDefinitionRegistry.registerBeanDefinition 手工注册进来
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
boolean definition1 = registry.containsBeanDefinition("com.hh.bean.Red");
boolean definition2 = registry.containsBeanDefinition("com.hh.bean.Blue");
if(definition1&&definition2){
//指定bean的定义信息,bean的类型
RootBeanDefinition beanDefinition = new RootBeanDefinition(Rainbow.class);
//注册一个bean
registry.registerBeanDefinition("rainBow",beanDefinition);
}
}
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh")
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig3 {}
@Test
public void test4() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig3.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
测试结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig3
com.xjhqre.pojo.Color
com.xjhqre.pojo.Red
com.xjhqre.pojo.Blue
com.xjhqre.pojo.Yellow
rainBow
FactoryBean是一个接口,我们需要自己实现
/**
* 创建一个Spring定义的FactoryBean
*/
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean...");
return new Color();
}
public Class<?> getObjectType() {
return Color.class;
}
/**
* 控制是单例吗?
* true :这个bean是单实例,在容器中保存一份
* false: 多实例 , 每次获取都会创建一个新的bean
*/
public boolean isSingleton() {
return false;
}
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh")
public class MainConfig4 {
@Bean
public ColorFactoryBean colorFactoryBean() {
return new ColorFactoryBean();
}
}
@Test
public void test5() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig4.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
// 工厂bean获取的是调用getObject创建的对象
Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
System.out.println(colorFactoryBean.getClass());
// 如果想要拿到colorFactoryBean对象,则需要在传入的id前加一个&标识
Object colorFactoryBean2 = applicationContext.getBean("&colorFactoryBean");
System.out.println(colorFactoryBean2.getClass());
}
测试结果:
class com.hh.pojo.Color
class com.hh.pojo.ColorFactoryBean
bean从创建 ----> 初始化 -----> 销毁的过程
容器管理bean的生命周期
我们可以自定义初始化和销毁方法:容器在bean进行到当前生命周期的时候调用我们自定义的初始化和销毁方法
构造(对象创建)
初始化
销毁
初始化和销毁方法:
postProcessBeforeInitialization :在初始化之前工作
postProcessAfterInitialization :在初始化之后工作
Spring底层对 BeanPostProcessor 的使用
bean赋值,注入其他组件,@AutoWired ,生命周期注解功能,@Async ,xxx 都用到BeanPostProcessor
通过@Bean注解指定init-method和destroy-method
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...");
}
}
@ComponentScan("com.hh.bean")
@Configuration
public class MainConfigOfLifeCycle {
@Bean(initMethod = "init",destroyMethod = "destroy")
public Car car(){
return new Car();
}
}
public class IOCTest_LifeCycle {
@Test
public void test1() throws InterruptedException {
//1.创建ioc容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
//关闭容器
applicationContext.close();
}
}
测试结果:
car构造方法
car初始化方法
car销毁方法
通过让bean实现InitializingBean接口来定义初始化逻辑
通过让bean实现DisposableBean接口来定义销毁逻辑
在InitializingBean中有一个方法afterPropertiesSet,该方法在bean创建并赋值后调用
@Component
public class Cat implements InitializingBean, DisposableBean {
public Cat() {
System.out.println("创建猫对象");
}
@Override
public void destroy() throws Exception {
System.out.println("销毁猫对象");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化猫对象");
}
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh.bean")
public class MainConfig6 {
@Bean
public Cat cat() {
return new Cat();
}
}
@Test
public void test7() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig6.class);
applicationContext.close();
}
测试结果:
创建猫对象
初始化猫对象
销毁猫对象
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}
public class Dog {
public Dog() {
System.out.println("创建狗对象");
}
//对象创建并赋值之后调用
@PostConstruct
public void init() {
System.out.println("初始化狗对象");
}
//容器移除对象之前
@PreDestroy
public void destroy() {
System.out.println("销毁狗对象");
}
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh.bean")
public class MainConfig7 {
@Bean
public Dog dog() {
return new Dog();
}
}
@Test
public void test8() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig7.class);
applicationContext.close();
}
测试结果:
创建狗对象
初始化狗对象
销毁狗对象
BeanPostProcessor接口中有两个方法:
/**
* 后置处理器:初始化前后进行处理
* 将后置处理器加入到容器中
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* @param bean 刚创建好的实例
* @param beanName 实例的id
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("id为" + beanName + "的bean对象:" + bean + "执行postProcessBeforeInitialization");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("id为" + beanName + "的bean对象:" + bean + "postProcessAfterInitialization");
return bean;
}
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh.bean")
public class MainConfig7 {
@Bean
public Dog dog() {
return new Dog();
}
}
@Test
public void test8() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig7.class);
applicationContext.close();
}
测试结果:
id为mainConfig7的bean对象:com.hh.config.MainConfig7$$EnhancerBySpringCGLIB$$aef15d18@7c469c48执行postProcessBeforeInitialization
id为mainConfig7的bean对象:com.hh.config.MainConfig7$$EnhancerBySpringCGLIB$$aef15d18@7c469c48postProcessAfterInitialization
创建狗对象
id为dog的bean对象:com.hh.bean.Dog@1534f01b执行postProcessBeforeInitialization
初始化狗对象
id为dog的bean对象:com.hh.bean.Dog@1534f01bpostProcessAfterInitialization
销毁狗对象
BeanPostProcessor 原理:
initializeBean{ applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);
invokeInitMethod(beanName,wrappedBean,mbd);执行自定义初始化 applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);
}
使用@Value赋值,赋值方法:
基本数值
#{}
${}
:取出配置文件中的值(在运行环境变量里的值)public class Person {
@Value("hh")
private String name;
@Value("#{20-2}")
private Integer age;
@Value("${person.email}")
private String email;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", email='" + email + '\'' +
'}';
}
}
配置文件 person.properties
person.email =2066@qq.com
//用@PropertySource读取外部配置文件中的k/v 保存到运行的环境变量中;加载完外部的配置文件之后使用${}取出配置文件的值
@PropertySource(value = {"classpath:/person.properties"})
@Configuration
public class MainConfig9 {
@Bean
public Person person() {
return new Person();
}
}
@Test
public void test9() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig9.class);
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
// 也可以使用环境变量取出(牛逼牛逼)
ConfigurableEnvironment environment = applicationContext.getEnvironment();
String property = environment.getProperty("person.email");
System.out.println(property);
}
测试结果:
Person{name='hh', age=18, email='[email protected]'}
[email protected]
Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
给属性自动注入值
默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class),找到就赋值。
如果该类型的组件有多个,再将属性名作为组件的id去容器中查找applicationContext.getBean(“bookDao”)
@AutoWired可以在构造器、参数、方法、属性上标注
自动装配默认一定要将属性赋值
好,没有就会报错
可以使用@Autowired(required=false);
源码:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
@AutoWired可以给required属性赋值,类型为boolean,默认为true。表示该组件是否必须。
当required=false时,表示这个组件不是必须的,在调用getBean方法时如果找不到对应的组件时不会直接抛出异常,而是返回一个null
标注在方法上,Spring容器创建当前对象,就会调用方法,完成赋值
方法使用的参数,自定义类型的值从IOC容器中获取
@Autowired
public void setCar(Car car) {
this.car = car;
}
默认加在IOC容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
我们可以在有参构造函数上标注@Autowired,让IOC容器创建组件时调用该类的有参构造方法
如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以从容器中获取
@Autowired
public Boss(Car car) {
this.car = car;
}
public Boss(@Autowired Car car) {
this.car = car;
}
@Bean标注的方法创建对象的时候,方法参数的值从容器中获取
// 参数car会从IOC容器中获取,可以省略Car前的@Autowired
@Bean
public Color color(Car car) {
return new Color();
}
使用@Qualifier指定需要装配的组件的id
,而不是用属性名 如:@Qualifier(“bookDao”)
@Qualifier需要和@AutoWired一起使用
该注解可以让Spring进行自动装配的时候,默认使用首选
的bean
也可以继续使用@Qualifier指定需要装配的bean的名字
无论是否有依赖注入,@Primary标注的bean都会被容器创建
源码:
/**
* 指示当多个候选者有资格自动装配单值依赖项时,应优先考虑 bean。如果候选中恰好存在一个“主”bean,则它将是自动装配的值。
* 这个注解在语义上等同于 Spring XML 中元素的primary属性。
* 可用于任何直接或间接使用@Component注释的类或使用Bean注释的方法。
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Primary {
}
可以和@Autowired一样实现自动装配功能,但默认是按组件名称进行装配
可以给属性name赋值,自定义组件名称
@Resource(name="bookDao2")
private BookDao bookDao;
但该注解没有支持@Primary、@Autowired(require=false)的功能
需要导入javax.inject依赖
和@Autowired功能一样,但没有required=false的功能
@Inject
private BookDao bookDao;
@Resource和@Inject都是java的规范
自定义组件想要使用Spring容器底层的一些组件(ApplicationContext、BeanFactory),需要自定义组件实现xxxAware接口
在创建对象的时候,会调用接口规定的方法,注入相关的组件
Aware的子接口
定义一个类使用Spring底层的组件
@Component
public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
private ApplicationContext applicationContext;
// 获取IOC容器
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("IOC容器:" + applicationContext);
this .applicationContext = applicationContext;
}
// 获取当前bean对象的名称
@Override
public void setBeanName(String name) {
System.out.println("当前bean的名字:" + name);
}
// 解析String语句中的占位符 $ 或 #
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
String s = resolver.resolveStringValue("你好${os.name}, 我是#{20*18}");
System.out.println("解析的字符串:" + s);
}
}
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.hh.bean")
public class MainConfig10 {
}
@Test
public void test10() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig10.class);
}
测试结果:
当前bean的名字:red
解析的字符串:你好Windows 10, 我是360
IOC容器:org.springframework.context.annotation.AnnotationConfigApplicationContext@77468bd9, started on Sun Feb 27 18:53:21 CST 2022
每一个xxxAware都有一个对应的xxxAwareProcessor,用来处理相关逻辑
以ApplicationContextAwareProcessor为例
@Profile注解是Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能
例子:在不同环境下使用不同的数据源,在开发环境下使用A数据源,在测试环境下使用B数据源,在生产环境下使用C数据源
需要导入c3p0依赖C3p0:JDBC DataSources/Resource Pools和数据库驱动依赖MySQL Connector
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=123456
@Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定的话在任何环境下都能注册这个组件
加了环境标识的bean,只有在这个环境被激活的时候才能注册到容器中,默认环境为default,即@Profile("default")
@Profile注解写在类上时,只有当指定的环境被激活时,整个类才会被注册
@Configuration
@PropertySource("classpath:/db.properties")
public class MainConfigOfProfile implements EmbeddedValueResolverAware {
@Value("${jdbc.username}")
private String user;
private StringValueResolver valueResolver;
// 测试数据库
@Profile("test")
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${jdbc.password}")String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true");
String driverClass = valueResolver.resolveStringValue("${jdbc.driverClassName}");
dataSource.setDriverClass(driverClass);
return dataSource;
}
// 开发数据库
@Profile("dev")
@Bean("devDataSource")
public DataSource dataSourceDev(@Value("${jdbc.password}")String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/atguigu?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true");
String driverClass = valueResolver.resolveStringValue("${jdbc.driverClassName}");
dataSource.setDriverClass(driverClass);
return dataSource;
}
// 生产数据库
@Profile("prod")
@Bean("prodDataSource")
public DataSource dataSourceProd(@Value("${jdbc.password}")String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true");
String driverClass = valueResolver.resolveStringValue("${jdbc.driverClassName}");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.valueResolver = resolver;
}
}
激活运行环境方式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yd7OJT2w-1657193423611)(C:\Users\小曾\Desktop\博客图片\image-20220706102314163.png)]
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.getEnvironment().setActiveProfiles("test", "dev");
applicationContext.register(MainConfig11.class);
applicationContext.refresh();
测试中使用代码方式激活环境
@Test
public void test11() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.getEnvironment().setActiveProfiles("test", "dev");
applicationContext.register(MainConfig11.class);
applicationContext.refresh();
String[] dataSources = applicationContext.getBeanNamesForType(DataSource.class);
for (String dataSource : dataSources) {
System.out.println(dataSource);
}
}
测试结果:
testDataSource
devDataSource
AOP:底层【动态代理】,指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;
AOP使用步骤:
通知方法说明:
*
表示所有方法,…表示任意类型的形参
public class MathCalculator {
public int div(int i, int j) {
System.out.println("MathCalculator...div...");
return i / j;
}
}
切面表达式 "execution(public int com.hh.aop.MathCalculator.*(..))"
中 *表示所有方法,…表示任意类型的形参。
JoinPoint joinPoint必须写在形参的第一位。
joinPoint可以获取被增强方法的签名,如方法名、参数列表、方法的返回值、方法抛出的异常等等
@Aspect //告诉Spring哪个类是切面类
public class LogAspects {
//抽取公共的切入点表达式
//1、本类引用
//2、若其他的切面引用,引用方法的全类名:"com.hh.aop.LogAspects.pointCut()"
@Pointcut("execution(public int com.hh.aop.MathCalculator.*(..))")
public void pointCut() {
}
//@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
@Before("pointCut()")
public void logStart(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
System.out.println("" + joinPoint.getSignature().getName() + "运行。。。@Before:参数列表是:{" + Arrays.asList(args) + "}");
}
@After("pointCut()")
public void logEnd(JoinPoint joinPoint) {
System.out.println("" + joinPoint.getSignature().getName() + "结束。。。@After");
}
//JoinPoint一定要出现在参数表的第一位
@AfterReturning(value = "pointCut()", returning = "result")
public void logReturn(JoinPoint joinPoint, Object result) {
System.out.println("" + joinPoint.getSignature().getName() + "正常返回。。。@AfterReturning:运行结果:{" + result + "}");
}
@AfterThrowing(value = "pointCut()", throwing = "exception")
public void logException(JoinPoint joinPoint, Exception exception) {
System.out.println("" + joinPoint.getSignature().getName() + "异常。。。异常信息:{" + exception + "}");
}
}
@EnableAspectJAutoProxy //开启基于注解的aop模式
@Configuration
public class MainConfigOfAop {
//业务逻辑类加入容器中
@Bean
public MathCalculator calculator() {
return new MathCalculator();
}
//切面类加入到容器中
@Bean
public LogAspects logAspects() {
return new LogAspects();
}
}
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAop.class);
MathCalculator bean = applicationContext.getBean(MathCalculator.class);
bean.div(1, 1);
}
测试结果:
div运行。。。@Before:参数列表是:{[1, 1]}
MathCalculator...div...
div正常返回。。。@AfterReturning:运行结果:{1}
div结束。。。@After
AOP使用的三个步骤:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 引入AspectJAutoProxyRegister.class对象
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
// true——使用CGLIB基于类创建代理;false——使用java接口创建代理
boolean proxyTargetClass() default false;
// 是否通过aop框架暴露该代理对象,aopContext能够访问.
boolean exposeProxy() default false;
}
@EnableAspectJAutoProxy是什么?
在AspectJAutoProxyRegistrar
中有一个registerBeanDefinitions
方法,在该方法中使用AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
语句注册了一个名为internalAutoProxyCreator
的组件,该组件的类型为AnnotationAwareAspectJAutoProxyCreator
以下是AnnotationAwareAspectJAutoProxyCreator
的层次结构:
这里主要关注后置处理器和自动装备BeanFactory相关的方法:SmartInstantiationAwareBeanPostProcessor
(后置处理器), BeanFactoryAware
(自动装配BeanFactory).
接下来去AnnotationAwareAspectJAutoProxyCreator
及其父类中寻找有关后置处理器和BeanFactory相关的方法
AbstractAutoProxyCreator:
AbstractAdvisorAutoProxyCreator:
AnnotationAwareAspectJAutoProxyCreator:
断点测试程序执行流程:
注册AnnotationAwareAspectJAutoProxyCreator
的后置处理器的方法registerBeanPostProcessors(beanFactory)
在IOC创建的refresh()
方法中
registerBeanPostProcessors(beanFactory):注册bean的后置处理器来方便拦截bean的创建;
先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
给容器中加别的BeanPostProcessor
优先注册实现了PriorityOrdered接口的BeanPostProcessor
再给容器中注册实现了Ordered接口的BeanPostProcessor
注册没实现优先级接口的BeanPostProcessor;
注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;下面以创建internalAutoProxyCreator(
类型为AnnotationAwareAspectJAutoProxyCreator
)的后置处理器BeanPostProcessor步骤为例:
把BeanPostProcessor注册到BeanFactory中:beanFactory.addBeanPostProcessor(postProcessor)
注册AnnotationAwareAspectJAutoProxyCreator的后置处理器流程图:
我们来分析IOC创建方法refresh()
中的finishBeanFactoryInitialization(beanFactory);
方法
finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;创建剩下的单实例bean
遍历获取容器中所有的Bean,依次创建对象getBean(beanName);getBean->doGetBean()->getSingleton()->
创建bean
先从缓存中获取当前bean:Object sharedInstance = getSingleton(beanName);
,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;只要创建好的Bean都会被缓存起来
createBean();创建bean;
resolveBeforeInstantiation(beanName, mbdToUse);
解析BeforeInstantiation
希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续
后置处理器先尝试返回对象;
bean = applyBeanPostProcessorsBeforeInstantiation();
拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor
,就执行postProcessBeforeInstantiation
如果不是则执行bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
若后置处理器返回对象失败,则会真正的去创建一个bean实例:doCreateBean(beanName, mbdToUse, args);
AnnotationAwareAspectJAutoProxyCreator执行时机流程图:
总结:
AnnotationAwareAspectJAutoProxyCreator
在所有bean创建之前会有一个拦截,它继承了InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation()
方法AnnotationAwareAspectJAutoProxyCreator
会在任何bean创建之前先尝试返回bean的实例,BeanPostProcessor
是在Bean对象创建完成初始化前后调用的InstantiationAwareBeanPostProcessor
是在创建Bean实例之前先尝试用后置处理器返回对象AnnotationAwareAspectJAutoProxyCreator
的类型是InstantiationAwareBeanPostProcessor
每一个bean创建之前,调用
postProcessBeforeInstantiation()
advisedBeans
中(里面保存了所有需要增强bean, 如MathCalculator)List candidateAdvisors
集合中,判断每一个增强器是否是 AspectJPointcutAdvisor
类型的,如果是则返回true,但我们的增强器是InstantiationModelAwarePointcutAdvisor
类型,所以返回false创建对象后,调用
postProcessAfterInitialization
,该方法返回一个包装bean,
return wrapIfNecessary(bean, beanName, cacheKey)
包装如果需要的情况下
调用
getAdvicesAndAdvisorsForBean
方法获取当前bean的所有增强器(通知方法),封装在集合
Object[] specificInterceptors
中
保存当前bean在advisedBeans中
如果当前bean需要增强,调用
createProxy
创建当前bean的代理对象;
proxyFactory.getProxy
创建代理对象:Spring自动决定,创建JdkDynamicAopProxy(config)
jdk动态代理或ObjenesisCglibAopProxy(config)
cglib的动态代理;给容器中返回当前组件使用cglib增强了的代理对象;
以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
AnnotationAwareAspectJAutoProxyCreator配置代理流程图:
容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
CglibAopProxy.intercept();
拦截目标方法的执行
根据ProxyFactory对象获取将要执行的目标方法拦截器链;
List
;
List
保存所有拦截器 长度为5,里面有一个默认的ExposeInvocationInterceptor
和 4个增强器;registry.getInterceptors(advisor);
List
,如果是MethodInterceptor
,直接加入到集合中;如果不是,使用AdvisorAdapter
将增强器转为MethodInterceptor
;转换完成返回MethodInterceptor
数组;如果没有拦截器链,直接执行目标方法,拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor
机制)
如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入,创建一个 CglibMethodInvocation
对象,并调用 Object retVal = mi.proceed();
拦截器链的触发过程;
执行目标方法到获取拦截器链的流程图:
@EnableAspectJAutoProxy
开启AOP功能
@EnableAspectJAutoProxy
会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator
是一个后置处理器
容器的创建流程:
registerBeanPostProcessors
注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator
对象
finishBeanFactoryInitialization
初始化剩下的单实例bean
AnnotationAwareAspectJAutoProxyCreator
拦截组件的创建过程执行目标方法:
CglibAopProxy.intercept()
DROP TABLE IF EXISTS `tbl_user`;
CREATE TABLE `tbl_user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`age` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert() {
String sql = "INSERT INTO `tbl_user`(username,age) VALUES(?,?)";
String username = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql, username, 19);
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void insertUser() {
userDao.insert();
System.out.println("插入完成...");
}
}
@Configuration
@ComponentScan("com.hh.tx")
@PropertySource("classpath:/db.properties")
public class TxConfig implements EmbeddedValueResolverAware {
private StringValueResolver valueResolver;
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(valueResolver.resolveStringValue("${jdbc.username}"));
dataSource.setPassword(valueResolver.resolveStringValue("${jdbc.password}"));
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/springtx?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true");
dataSource.setDriverClass(valueResolver.resolveStringValue("${jdbc.driverClassName}"));
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws Exception{
//Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.valueResolver = resolver;
}
}
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.insertUser();
}
给方法上标注@Transactional
表示当前方法是一个事务方法;并在方法中设置异常
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void insertUser() {
userDao.insert();
int i = 1 / 0;
System.out.println("插入完成...");
}
}
在配置类标注@EnableTransactionManagement
开启基于注解的事务管理功能;
@Configuration // 告诉Spring这是一个配置类
@EnableTransactionManagement
@ComponentScan("com.hh.tx")
@PropertySource("classpath:/db.properties")
public class TxConfig implements EmbeddedValueResolverAware {
// ...
}
在配置类中加入事务管理器bean
//注册事务管理器在容器中
@Bean
public PlatformTransactionManager transactionManager() throws Exception{
return new DataSourceTransactionManager(dataSource());
}
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.insertUser();
}
测试结果:
控制台打印 除数 0 异常,数据库未增加新记录
事务执行原理:
标注@EnableTransactionManagement
,spring利用TransactionManagementConfigurationSelector
给容器中会导入两个组件:AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
AutoProxyRegistrar
功能:
InfrastructureAdvisorAutoProxyCreator
组件;ProxyTransactionManagementConfiguration
功能:
AnnotationTransactionAttributeSource
解析事务注解TransactionInterceptor
;保存了事务属性信息,事务管理器;他是一个 MethodInterceptor
,在目标方法执行的时候执行拦截器链:
PlatformTransactionManager
,如果事先没有添加指定任何transactionmanger
,最终会从容器中按照类型获取一个PlatformTransactionManager
;BeanPostProcessor:
bean后置处理器,bean创建对象初始化前后进行拦截工作的
BeanFactoryPostProcessor:beanFactory的后置处理器:
BeanFactoryPostProcessor原理:
refresh()
方法中的invokeBeanFactoryPostProcessors(beanFactory);
public class Dog {
public Dog() {
System.out.println("创建狗对象");
}
@PostConstruct
public void init() {
System.out.println("初始化狗对象");
}
@PreDestroy
public void destroy() {
System.out.println("销毁狗对象");
}
}
编写MyBeanFactoryPostProcessor方法,实现接口BeanFactoryPostProcessor,重写postProcessBeanFactory方法
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("执行postProcessBeanFactory");
int count = beanFactory.getBeanDefinitionCount();
System.out.println("当前BeanFactory中有" + count + " 个Bean");
String[] names = beanFactory.getBeanDefinitionNames();
System.out.println(Arrays.asList(names));
}
}
@ComponentScan("com.hh.ext")
@Configuration
public class ExtConfig {
@Bean
public Dog dog() {
return new Dog();
}
}
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
applicationContext.close();
}
测试结果:
执行postProcessBeanFactory
当前BeanFactory中有8 个Bean
创建狗对象
初始化狗对象
销毁狗对象
BeanDefinitionRegistryPostProcessor
继承自BeanFactoryPostProcessor
其优先于BeanFactoryPostProcessor执行;在所有bean定义信息将要被加载,bean实例还未创建的时候执行
利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件
BeanDefinitionRegistryPostProcessor执行流程:
refresh()
--> invokeBeanFactoryPostProcessors(beanFactory)
;BeanDefinitionRegistryPostProcessor
组件
postProcessBeanDefinitionRegistry()
方法postProcessBeanFactory()
方法;BeanFactoryPostProcessor
组件;然后依次触发postProcessBeanFactory()方法其他配置类和测试类同上
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("执行MyBeanDefinitionRegistryPostProcessor...bean的数量:" + beanFactory.getBeanDefinitionCount());
}
//BeanDefinitionRegistry Bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建bean实例;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("执行postProcessBeanDefinitionRegistry...bean的数量:" + registry.getBeanDefinitionCount());
// 手动注册bean对象
// 方法一:RootBeanDefinition beanDefinition = new RootBeanDefinition(Cat.class);
// 方法二:
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Cat.class).getBeanDefinition();
registry.registerBeanDefinition("car", beanDefinition);
}
}
public class Cat implements InitializingBean, DisposableBean {
public Cat() {
System.out.println("创建猫对象");
}
@Override
public void destroy() throws Exception {
System.out.println("销毁猫对象");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化猫对象");
}
}
测试结果:
执行postProcessBeanDefinitionRegistry...bean的数量:9
执行MyBeanDefinitionRegistryPostProcessor...bean的数量:10
执行postProcessBeanFactory
当前BeanFactory中有10 个Bean
创建狗对象
初始化狗对象
创建猫对象
初始化猫对象
销毁猫对象
销毁狗对象
结果分析:
MyBeanDefinitionRegistryPostProcessor
里的postProcessBeanDefinitionRegistry
,在输出bean对象的数量后又创建了一个Cat类的beanMyBeanDefinitionRegistryPostProcessor
里的postProcessBeanFactory
方法。输出的bean数量加1MyBeanFactoryPostProcessor
里的postProcessBeanFactory
方法ApplicationListener
:监听容器中发布的事件。事件驱动模型开发;
我们需要自己写一个监听器,该监听器必须实现ApplicationListener
接口,用于监听ApplicationEvent
及其下面的子事件;
步骤:
applicationContext.publishEvent()
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
//当容器中发布此事件以后,方法触发
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("收到事件:" + event);
}
}
@Test
public void test14() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
applicationContext.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
});
applicationContext.close();
}
测试结果:
收到事件:org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@6bc168e5, started on Wed Mar 02 15:04:16 CST 2022]
收到事件:SpringTest$1[source=我发布的事件]
收到事件:org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@6bc168e5, started on Wed Mar 02 15:04:16 CST 2022]
事件发布顺序:
refresh()
;finishRefresh()
;容器刷新完成会发布ContextRefreshedEvent
事件事件发布流程:
容器创建对象:refresh();
finishRefresh();
publishEvent(new ContextRefreshedEvent(this))
;
获取事件的多播器(派发器):getApplicationEventMulticaster()
multicastEvent
派发事件:
获取到所有的ApplicationListener
;
for (final ApplicationListener> listener : getApplicationListeners(event, type))
Executor
,可以支持使用Executor进行异步派发;invokeListener(listener, event);
拿到 listener 回调 onApplicationEvent
方法;事件多播器(派发器)创建流程:
refresh()
;initApplicationEventMulticaster()
;初始化ApplicationEventMulticaster
;
id=“applicationEventMulticaster”
的组件;this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
并且加入到容器中,我们就可以在其他组件要派发事件,自动注入到派发器 applicationEventMulticaster
中;监听器创建流程:
容器创建对象:refresh();
registerListeners();
从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中;
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
将监听器listener注册到派发器ApplicationEventMulticaster中:getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
通过@EventListener
注解,我们也可以用来监听事件
@Service
public class UserService {
@EventListener(classes = {ApplicationEvent.class})
public void listen(ApplicationEvent event) {
System.out.println("UserService。。监听到的事件:" + event);
}
}
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
applicationContext.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
});
applicationContext.close();
}
测试结果:
UserService监听到的事件:org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@6bc168e5, started on Wed Mar 02 15:37:36 CST 2022]
UserService监听到的事件:SpringTest$1[source=我发布的事件]
UserService监听到的事件:org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@6bc168e5, started on Wed Mar 02 15:37:36 CST 2022]
spring使用EventListenerMethodProcessor
处理器来解析方法上的@EventListener
;其实现了SmartInitializingSingleton
接口
SmartInitializingSingleton原理:
finishBeanFactoryInitialization(beanFactory)
; 初始化剩下的单实例bean;
getBean();
SmartInitializingSingleton
类型的;如果是就调用afterSingletonsInstantiated();
Spring容器的refresh()
创建刷新:
prepareRefresh()
:刷新前的预处理;
initPropertySources()
初始化一些属性设置;子类自定义个性化的属性设置方法;
getEnvironment().validateRequiredProperties();
检验属性的合法等
earlyApplicationEvents= new LinkedHashSet
保存容器中的一些早期的事件;
obtainFreshBeanFactory()
; 获取BeanFactory;
refreshBeanFactory();
刷新创建BeanFactory,设置序列化ID;
getBeanFactory();
返回刚才GenericApplicationContext
创建的BeanFactory
对象;
将创建的BeanFactory(DefaultListableBeanFactory)
返回;
prepareBeanFactory(beanFactory)
; BeanFactory的预准备工作,对BeanFactory进行一些设置;
设置BeanFactory的类加载器、支持表达式解析器…
添加部分BeanPostProcessor【ApplicationContextAwareProcessor】
设置忽略的自动装配的接口:EnvironmentAware
、EmbeddedValueResolverAware
…
注册可以解析的自动装配;我们能直接在任何组件中自动注入:BeanFactory
、ResourceLoader
、ApplicationEventPublisher
、ApplicationContext
添加BeanPostProcessor【ApplicationListenerDetector】
添加编译时的AspectJ;
给BeanFactory中注册一些能用的组件:environment【ConfigurableEnvironment】
、systemProperties【Map
、systemEnvironment【Map
postProcessBeanFactory(beanFactory)
; BeanFactory准备工作完成后进行的后置处理工作;
BeanFactory的创建及预准备工作流程图:
invokeBeanFactoryPostProcessors(beanFactory)
; 执行BeanFactoryPostProcessor;
BeanFactoryPostProcessor
:BeanFactory的后置处理器。在BeanFactory标准初始化之后执行的;
BeanDefinitionRegistryPostProcessor
PriorityOrdered
优先级接口的BeanDefinitionRegistryPostProcessor
,将其存入currentRegistryProcessors数组中sortPostProcessors(currentRegistryProcessors, beanFactory);
对所有BeanDefinitionRegistryPostProcessor
进行排序registryProcessors.addAll(currentRegistryProcessors);
注册所有`BeanDefinitionRegistryPostProcessor``invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
执行所有BeanDefinitionRegistryPostProcessor
Ordered
优先级接口的BeanDefinitionRegistryPostProcessor
,之后的步骤同上面的 3 ~ 5BeanDefinitionRegistryPostProcessor
,之后的步骤同上面的 3 ~ 5BeanDefinitionRegistryPostProcessor
之后才会处理BeanFactoryPostProcessor
,处理过程和BeanDefinitionRegistryPostProcessor
相同registerBeanPostProcessors(beanFactory)
; 注册BeanPostProcessor,Bean的后置处理器
不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的
beanFactory.addBeanPostProcessor(postProcessor);
MergedBeanDefinitionPostProcessor
;ApplicationListenerDetector
;来在Bean创建完成后检查是否是ApplicationListener,如果是则调用applicationContext.addApplicationListener((ApplicationListener>) bean);
方法将其添加进容器中initMessageSource()
;
初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
MessageSource.getMessage(String code, Object[] args, String defaultMessage, Locale locale);
initApplicationEventMulticaster()
; 初始化事件派发器;
ApplicationEventMulticaster
的applicationEventMulticaster
;SimpleApplicationEventMulticaster
ApplicationEventMulticaster
添加到BeanFactory中,以后其他组件直接自动注入onRefresh()
; 留给子容器(子类)
registerListeners()
; 给容器中将所有项目里面的ApplicationListener注册进来;
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
finishBeanFactoryInitialization(beanFactory)
; 初始化所有剩下的单实例bean;beanFactory.preInstantiateSingletons()
; 初始化后剩下的单实例bean获取容器中的所有Bean,依次进行初始化和创建对象
获取Bean的定义信息;RootBeanDefinition
如果Bean不是抽象的,是单实例的,不是是懒加载:
判断是否是FactoryBean;是否是实现FactoryBean接口的Bean,FactoryBean是创建对象的模板;
如果不是工厂Bean。则利用getBean(beanName)
; 创建对象
getBean(beanName) —> doGetBean(name, null, null, false);
先获取缓存中保存的单实例Bean。如果能获取到说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存起来),从private final Map
获取的
缓存中获取不到,开始Bean的创建对象流程;
标记当前bean已经被创建
获取Bean的定义信息;
获取当前Bean依赖的其他Bean,如果有按照getBean()把依赖的Bean先创建出来;
启动单实例Bean的创建流程;
createBean(beanName, mbd, args);
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
让BeanPostProcessor先拦截返回代理对象;
如果前面的InstantiationAwareBeanPostProcessor
没有返回代理对象;调用4)
Object beanInstance = doCreateBean(beanName, mbdToUse, args)
; 创建Bean
【创建Bean实例】;createBeanInstance(beanName, mbd, args);
利用工厂方法或者对象的构造器创建出Bean实例
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
调用MergedBeanDefinitionPostProcessor
的postProcessMergedBeanDefinition(mbd, beanType, beanName);
【Bean属性赋值】populateBean(beanName, mbd, instanceWrapper)
;
赋值之前
InstantiationAwareBeanPostProcessor
后置处理器:postProcessAfterInstantiation();
InstantiationAwareBeanPostProcessor
后置处理器:postProcessPropertyValues()
【Bean初始化】initializeBean(beanName, exposedObject, mbd)
;
invokeAwareMethods(beanName, bean);
执行xxxAware接口的方法applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd)
;
applyBeanPostProcessorsAfterInitialization
注册Bean的销毁方法;
将创建的Bean添加到缓存中singletonObjects;
所有Bean都利用getBean创建完成以后;检查所有的Bean是否是SmartInitializingSingleton接口的;如果是;就执行afterSingletonsInstantiated();
finishRefresh()
; 完成BeanFactory的初始化创建工作;IOC容器就创建完成;
initLifecycleProcessor();
初始化和生命周期有关的后置处理器;默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new DefaultLifecycleProcessor();
加入到容器;
getLifecycleProcessor().onRefresh();
拿到前面定义的生命周期处理器(BeanFactory),回调onRefresh()方法;
publishEvent(new ContextRefreshedEvent(this));
发布最终事件
liveBeansView.registerApplicationContext(this);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OZAOKCip-1657800719983)(C:\Users\小曾\Desktop\博客图片\af05b51213fec0c7192b9038150a8d09.png)]
Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息;
xml注册bean
注解注册Bean;@Controller 、@Service、@Repository、 @Component、@Bean、@Import
Spring容器会合适的时机创建这些Bean
用到这个bean的时候;利用getBean创建bean;创建好以后保存在容器中;
统一创建剩下所有的bean的时候;finishBeanFactoryInitialization();
后置处理器;BeanPostProcessor
事件驱动模型
ApplicationListener:事件监听;
ApplicationEventMulticaster:事件派发:
以前使用web.xml
配置文件来 配置 servlet
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
现在使用注解方式就可以搞定,对比学习
jsp页面:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
DOCTYPE html>
<html>
<head>
<title>JSP - Hello Worldtitle>
head>
<body>
<h1><%= "Hello World!" %>
h1>
<br/>
<a href="HelloServlet">Hello Servleta>
body>
html>
编写一个类:
@WebServlet(name = "HelloServlet", value = "/HelloServlet")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("hello hh");
}
}
Shared libraries(共享库) / runtimes pluggability(运行时插件能力)
Servlet容器启动会扫描,当前应用里面每一个jar包的ServletContainerInitializer的实现
使用方法:
ServletContainerInitializer
的实现类 MyServletContainerInitializer META-INF/services/javax.servlet.ServletContainerInitializer
文件全类名
代码演示:
MyServletContainerInitializer:
//容器启动的时候会将@HandlesTypes指定的这个类型下面的子类(实现类,子接口等)传递过来;
@HandlesTypes(value={HashMap.class})
public class MyServletContainerInitializer implements ServletContainerInitializer {
/**
* 应用启动的时候,会运行onStartup方法;
*
* Set> arg0:感兴趣的类型的所有子类型;
* ServletContext arg1:代表当前Web应用的ServletContext;一个Web应用对应一个ServletContext;
*/
@Override
public void onStartup(Set<Class<?>> arg0, ServletContext sc) throws ServletException {
// TODO Auto-generated method stub
System.out.println("感兴趣的类型:");
for (Class<?> claz : arg0) {
System.out.println(claz);
}
}
}
创建javax.servlet.ServletContainerInitializer文件
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("userServlet响应");
}
}
public class MyListener implements ServletContextListener {
// 监听ServletContext销毁
@Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("监听ServletContext销毁");
}
// 监听ServletContext启动初始化
@Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("监听ServletContext启动初始化");
}
}
public class MyFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
// 过滤请求
System.out.println("过滤请求");
// 放行
arg2.doFilter(arg0, arg1);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
public class MyServletContainerInitializer implements ServletContainerInitializer {
/**
* 1)、使用ServletContext注册Web组件(Servlet、Filter、Listener)
* 2)、使用编码的方式,在项目启动的时候给ServletContext里面添加组件;
* 必须在项目启动的时候来添加;
* 1)、ServletContainerInitializer得到的ServletContext;
* 2)、ServletContextListener得到的ServletContext;
*/
@Override
public void onStartup(Set<Class<?>> arg0, ServletContext sc) throws ServletException {
// 注册组件 ServletRegistration
ServletRegistration.Dynamic servlet = sc.addServlet("userServlet", new MyServlet());
// 配置servlet的映射信息
servlet.addMapping("/user");
// 注册Listener
sc.addListener(MyListener.class);
// 注册Filter FilterRegistration
FilterRegistration.Dynamic filter = sc.addFilter("userFilter", MyFilter.class);
// 配置Filter的映射信息,过滤所有请求
filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
}
}
META-INF/services/javax.servlet.ServletContainerInitializer
SpringServletContainerInitializer
WebApplicationInitializer
接口的下的所有组件;createRootApplicationContext()
方法创建根容器;createServletApplicationContext()
方法创建一个web的ioc容器;DispatcherServlet
;AbstractAnnotationConfigDispatcherServletInitializer
:注解方式配置的DispatcherServlet初始化器
createRootApplicationContext()
创建根容器,调用getRootConfigClasses();
传入一个配置类createServletApplicationContext();
创建web的ioc容器: 调用getServletConfigClasses();
获取配置类;结论:以注解方式来启动SpringMVC的步骤:
AbstractAnnotationConfigDispatcherServletInitializer
;<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.14version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>3.0-alpha-1version>
<scope>providedscope>
dependency>
@Service
public class HelloService {
public String sayHello(String name) {
return "Hello " + name;
}
}
@Controller
public class HelloController {
@Autowired
HelloService helloService;
@ResponseBody
@RequestMapping("/hello")
public String hello() {
String hello = helloService.sayHello("tomcat..");
return hello;
}
}
//Spring的容器不扫描controller;父容器
@ComponentScan(value = "com.hh", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
})
public class RootConfig {
}
//SpringMVC只扫描Controller;子容器
//useDefaultFilters=false 禁用默认的过滤规则;
@ComponentScan(value="com.hh",includeFilters={
@ComponentScan.Filter(type= FilterType.ANNOTATION,classes={Controller.class})
},useDefaultFilters=false)
@EnableWebMvc
public class AppConfig {
}
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
//获取根容器的配置类(Spring的配置文件)父容器;
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}
//获取web容器的配置类(SpringMVC配置文件)子容器;
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{AppConfig.class};
}
//获取DispatcherServlet的映射信息
// /:拦截所有请求(包括静态资源(xx.js,xx.png)),但是不包括*.jsp;
// /*:拦截所有请求;连*.jsp页面都拦截;jsp页面是tomcat的jsp引擎解析的;
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
通过继承WebMvcConfigurerAdapter
类,重写里面的方法来配置springMVC。
例如:配置视图解析器、静态资源访问、拦截器等等
在WEB-INF目录下新建Views目录,在Views目录下创建success.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
success
body>
html>
public class MyInterceptor implements HandlerInterceptor {
// 目标方法运行之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("目标方法运行之前执行");
return true;
}
// 目标方法执行正确以后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
System.out.println("目标方法执行正确以后执行");
}
// 页面响应以后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
System.out.println("页面响应以后执行");
}
}
@Controller
public class HelloController {
@Autowired
HelloService helloService;
@ResponseBody
@RequestMapping("/hello")
public String hello() {
String hello = helloService.sayHello("xjhqre");
return hello;
}
// /WEB-INF/views/success.jsp
@RequestMapping("/suc")
public String success(){
return "success";
}
}
//SpringMVC只扫描Controller;子容器
//useDefaultFilters=false 禁用默认的过滤规则;
@ComponentScan(value="com.example.SpringMVC_Annotation",includeFilters={
@ComponentScan.Filter(type= FilterType.ANNOTATION,classes={Controller.class})
},useDefaultFilters=false)
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter{
//视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//默认所有的页面都从 /WEB-INF/ xxx .jsp
//registry.jsp();
registry.jsp("/WEB-INF/views/", ".jsp");
}
//静态资源访问
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
//拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//super.addInterceptors(registry);
// "/**":任意多的路径
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
}
}
异步请求模型:
编写HelloAsyncServlet
@WebServlet(value="/async",asyncSupported=true)
public class HelloAsyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、支持异步处理asyncSupported=true
//2、开启异步模式
System.out.println("主线程开始。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis());
AsyncContext startAsync = req.startAsync();
//3、业务逻辑进行异步处理;开始异步处理
startAsync.start(new Runnable() {
@Override
public void run() {
try {
System.out.println("副线程开始。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis());
sayHello();
startAsync.complete();
//4、获取响应
ServletResponse response = startAsync.getResponse();
response.getWriter().write("hello async...");
System.out.println("副线程结束。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis());
} catch (Exception e) {
}
}
});
System.out.println("主线程结束。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis());
}
public void sayHello() throws Exception{
System.out.println(Thread.currentThread()+" processing...");
Thread.sleep(3000);
}
}
测试结果:
主线程开始。。。Thread[http-nio-8080-exec-9,5,main]==>1646310054633
主线程结束。。。Thread[http-nio-8080-exec-9,5,main]==>1646310054633
副线程开始。。。Thread[http-nio-8080-exec-5,5,main]==>1646310054633
Thread[http-nio-8080-exec-5,5,main] processing...
副线程结束。。。Thread[http-nio-8080-exec-5,5,main]==>1646310057634
步骤:
编写AsyncController:
@Controller
public class AsyncController {
/**
* 1、控制器返回Callable
* 2、Spring异步处理,将Callable 提交到 TaskExecutor 使用一个隔离的线程进行执行
* 3、DispatcherServlet和所有的Filter退出web容器的线程,但是response 保持打开状态;
* 4、Callable返回结果,SpringMVC将请求重新派发给容器,恢复之前的处理;
* 5、根据Callable返回的结果。SpringMVC继续进行视图渲染流程等(从收请求-视图渲染)。
*/
@ResponseBody
@RequestMapping("/async01")
public Callable<String> async01() {
System.out.println("主线程开始..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("副线程开始..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("副线程开始..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
return "Callable async01()" ;
}
};
System.out.println("主线程结束..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
return callable;
}
}
测试结果:
目标方法运行之前执行
主线程开始...Thread[http-nio-8080-exec-8,5,main]==>1646311553329
主线程结束...Thread[http-nio-8080-exec-8,5,main]==>1646311553329
副线程开始...Thread[MvcAsync2,5,main]==>1646311553329
副线程开始...Thread[MvcAsync2,5,main]==>1646311555330
目标方法运行之前执行
目标方法执行正确以后执行
页面响应以后执行
执行步骤:
编写DeferredResultQueue:
public class DeferredResultQueue {
private static Queue<DeferredResult<Object>> queue = new ConcurrentLinkedQueue<DeferredResult<Object>>();
public static void save(DeferredResult<Object> deferredResult) {
System.out.println("加入队列");
queue.add(deferredResult);
}
public static DeferredResult<Object> get() {
System.out.println("从队列中取出");
return queue.poll();
}
}
编写AsyncController:
@Controller
public class AsyncController {
@ResponseBody
@RequestMapping("/createOrder")
public DeferredResult<Object> createOrder() {
// 设置超时时间
DeferredResult<Object> deferredResult = new DeferredResult<>((long) 3000, "创建订单失败");
DeferredResultQueue.save(deferredResult);
return deferredResult;
}
@ResponseBody
@RequestMapping("/create")
public String create() {
//创建订单
String order = UUID.randomUUID().toString();
DeferredResult<Object> deferredResult = DeferredResultQueue.get();
deferredResult.setResult(order);
return "success ===> " + order;
}
}
编写AsyncController:
@Controller
public class AsyncController {
/**
* 1、控制器返回Callable
* 2、Spring异步处理,将Callable 提交到 TaskExecutor 使用一个隔离的线程进行执行
* 3、DispatcherServlet和所有的Filter退出web容器的线程,但是response 保持打开状态;
* 4、Callable返回结果,SpringMVC将请求重新派发给容器,恢复之前的处理;
* 5、根据Callable返回的结果。SpringMVC继续进行视图渲染流程等(从收请求-视图渲染)。
*/
@ResponseBody
@RequestMapping("/async01")
public Callable<String> async01() {
System.out.println("主线程开始..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("副线程开始..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("副线程开始..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
return "Callable async01()" ;
}
};
System.out.println("主线程结束..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
return callable;
}
}
测试结果:
目标方法运行之前执行
主线程开始...Thread[http-nio-8080-exec-8,5,main]==>1646311553329
主线程结束...Thread[http-nio-8080-exec-8,5,main]==>1646311553329
副线程开始...Thread[MvcAsync2,5,main]==>1646311553329
副线程开始...Thread[MvcAsync2,5,main]==>1646311555330
目标方法运行之前执行
目标方法执行正确以后执行
页面响应以后执行
执行步骤:
编写DeferredResultQueue:
public class DeferredResultQueue {
private static Queue<DeferredResult<Object>> queue = new ConcurrentLinkedQueue<DeferredResult<Object>>();
public static void save(DeferredResult<Object> deferredResult) {
System.out.println("加入队列");
queue.add(deferredResult);
}
public static DeferredResult<Object> get() {
System.out.println("从队列中取出");
return queue.poll();
}
}
编写AsyncController:
@Controller
public class AsyncController {
@ResponseBody
@RequestMapping("/createOrder")
public DeferredResult<Object> createOrder() {
// 设置超时时间
DeferredResult<Object> deferredResult = new DeferredResult<>((long) 3000, "创建订单失败");
DeferredResultQueue.save(deferredResult);
return deferredResult;
}
@ResponseBody
@RequestMapping("/create")
public String create() {
//创建订单
String order = UUID.randomUUID().toString();
DeferredResult<Object> deferredResult = DeferredResultQueue.get();
deferredResult.setResult(order);
return "success ===> " + order;
}
}