Spring注解开发

Spring注解开发

容器

组件添加

注册方式

  • 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component):局限于自己写的类
  • @Bean:导入的第三方包里的组件
  • @Import:快速给容器中导入一个组件
    • @Import(要导入到容器中的组件),容器中就会自动注册这个组件,id默认是全类名
      • ImportSelector:返回需要导入的组件的全类名数组
      • ImportBeanDefinitionRegistrar:手动注册bean到容器中
    • 使用Spring提供的FactoryBean(工厂Bean)
      •     默认获取到的是工厂bean调用getObject创建的对象
        
      •     要获取工厂Bean本身,需要给id前面加一个&
        
        •     &colorFactoryBean
          

@Configuration

  • 写在配置类上,告诉Spring这是一个配置类

@Bean

  • 写在配置类中的方法上,为容器中注册一个Bean
  • 类型为返回值类型
  • 方法名默认作为id
  • 参数
    • value:默认,指定容器名
生命周期
  • 由容器管理bean的创建,初始化,销毁,我们可以自定义初始化和销毁方法
  • 指定初始化和销毁方法:
@Bean指定方法
  • initMethod和destroyMethod
  • 单实例:容器启动时创建对象,关闭容器时销毁
  • 多实例:每次获取时创建对象,不进行销毁
1
2
3
4
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
return new Car();
}
Bean实现接口
  • 实现InitializingBean定义初始化
  • 实现DisposableBean定义销毁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Cat implements InitializingBean, DisposableBean {

public Cat() {
System.out.println("cat:constructor");
}

@Override
public void destroy() throws Exception {
System.out.println("cat:destroy");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("cat:afterPropertiesSet");
}
}
使用JSR250
  •     写在方法上
    
  •     @PostConstruct:在bean创建完成并且属性赋值完成来执行初始化方法
    
  •     @PreDestroy:在容器销毁bean之前通知我们进行清理工作
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Dog {

public Dog() {
System.out.println("dog:constructor");
}

// 对象创建并赋值之后调用
@PostConstruct
public void init() {
System.out.println("dog:@PostConstruct");
}

// 容器移除对象之前调用
@PreDestroy
public void destroy() {
System.out.println("dog:@PreDestroy");
}

}
BeanPostProcessor
  • bean的后置处理器,在bean初始化前后进行一些处理工作
  • postProcessBeforeInitialization:在初始化之前工作
  • postProcessAfterInitialization:在初始化之后工作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyBeanPostProcessor implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization:" + bean + ":" + beanName);
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization:" + bean + ":" + beanName);
return bean;
}

}
1
2
3
4
5
6
7
8
9
10
11
* 遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
* 一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
*
* BeanPostProcessor原理
* populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
* initializeBean
* {
* applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
* invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
* applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
*}
  • Spring底层对BeanPostProcessor的使用:
    • bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx

@ComponentScan

  • 写在配置类上,开启组件扫描,可重复添加

  • 参数

    • value:指定扫描的包

    • excludeFilters/includeFilters

      • excludeFilters:指定排除的注解类

        1
        2
        3
        4
        @ComponentScan(
        value = "cc.mousse",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})}
        )
      • includeFilters:指定包含的注解类,需要关闭默认过滤规则useDefaultFilters

        1
        2
        3
        4
        5
        @ComponentScan(
        value = "cc.mousse",
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})},
        useDefaultFilters = false
        )
      • @ComponentScan.Filter.type:

        • FilterType.ANNOTATION:按照注解

        • FilterType. ASSIGNABLE_TYPE:按照给定的类

        • FilterType. REGEX:按照正则表达式

        • FilterType. CUSTOM:按照自定义规则

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          public class MyTypeFilter implements TypeFilter {

          /**
          * @param metadataReader 读取到当前正在扫描类的信息
          * @param metadataReaderFactory 可以其它任何类的信息
          */
          @Override
          public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
          // 获取当前类的注解信息
          AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
          // 获取当前扫描的类信息
          ClassMetadata classMetadata = metadataReader.getClassMetadata();
          // 获取当前类的资源(类的路径)
          Resource resource = metadataReader.getResource();
          String className = classMetadata.getClassName();
          System.out.println("className: " + className);
          // 判断演示
          return className.contains("er");
          }

          }
          1
          2
          3
          4
          5
          6
          7
          @ComponentScan(
          value = "cc.mousse",
          includeFilters = {
          @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
          },
          useDefaultFilters = false
          )

@Scope

  • 写在配置类中的方法上,调整作用域
  • 参数
    • prototype:多实例
      • 每次获取时才会调用方法创建对象
    • singleton:单实例,默认值
      • IOC容器启动时就会调用方法把对象放到容器中,每次获取直接从容器中拿

@Lazy

  • 写在配置类中的方法上,懒加载,使容器加载时不创建对象,第一次获取时才创建(针对单实例)

*@Conditional

  • 写在配置类或类中的方法上,按照一定条件进行判断,满足条件给容器中注册bean

  • 参数

    • {Conditional}
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Conditional({MacOSCondition.class})
    @Bean("macOS")
    public Person person1() {
    return new Person("macOS", 2021);
    }

    @Conditional({WindowsCondition.class})
    @Bean("windows")
    public Person person2() {
    return new Person("windows", 2021);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // 判断是否是MacOS系统
    public class MacOSCondition implements Condition {

    /**
    * @param conditionContext 判断条件能使用的上下文环境
    * @param annotatedTypeMetadata 注释信息
    */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    // 判断是否为MacOS系统
    // 能获取到IOC使用的beanFactory
    ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
    // 获取类加载器
    ClassLoader classLoader = conditionContext.getClassLoader();
    // 获取bean定义的注册类
    BeanDefinitionRegistry registry = conditionContext.getRegistry();
    // 获取当前环境信息
    String property = conditionContext.getEnvironment().getProperty("os.name");
    assert property != null;
    return property.contains("MAC");
    }

    }

*@Import

  • 写在配置类上,快速给容器中导入一个组件,id默认为全类名

  • 参数

    • value:

      • 要导入的类

        1
        2
        @Import({Color.class})
        public class BeanConfig { }
      • ImportSelector:返回需要导入的组件的全类名数组

        1
        2
        @Import({MyImportSelector.class})
        public class BeanConfig { }
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        public class MyImportSelector implements ImportSelector {

        @Override
        public Predicate<String> getExclusionFilter() {
        return ImportSelector.super.getExclusionFilter();
        }

        /**
        * @param annotationMetadata 当前标注@Import注解的类的所有注解信息
        * @return 导入到容器中的组件全类名,可以返回空数组但不能返回null
        */
        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"cc.mousse.bean.Red", "cc.mousse.bean.Orange"};
        }

        }
        • ImportBeanDefinitionRegistrar:手动注册bean到容器中

          1
          @Import({MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

          /**
          *
          * @param importingClassMetadata 当前类的注解信息
          * @param registry BeanDefinition注册类:把所有需要添加到容器中的bean手动注册
          */
          @Override
          public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
          boolean red = registry.containsBeanDefinition("cc.mousse.bean.Red");
          boolean orange = registry.containsBeanDefinition("cc.mousse.bean.Orange");
          if (red && orange) {
          // 创建一个类型定义信息:Bean的类型,Bean的作用域等
          RootBeanDefinition definition = new RootBeanDefinition(RainBow.class);
          // 指定bean名称信息
          registry.registerBeanDefinition("rainBow", definition);
          }
          }
          }

FactoryBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 创建Spring定义的工厂bean
public class ColorFactoryBean implements FactoryBean<Color> {

/**
* 设置是否为单实例
* @return true单实例,false多实例
*/
@Override
public boolean isSingleton() {
return true;
}

/**
* @return 返回一个Color对象,这个对象会添加到容器中
*/
@Override
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean:getObject");
return new Color();
}

//

/**
* @return 返回Color对象的类型
*/
@Override
public Class<?> getObjectType() {
return Color.class;
}

}
1
2
3
4
5
6
7
8
9
10
@Test
public void test4() {
printBeans(applicationContext);
// 工厂Bean获取的是调用getObject创建的对象
Object colorFactoryBean1 = applicationContext.getBean("colorFactoryBean");
System.out.println("colorFactoryBean1的类型:" + colorFactoryBean1.getClass());
// &beanName获取Factory本身
Object colorFactoryBean2 = applicationContext.getBean("&colorFactoryBean");
System.out.println("colorFactoryBean2的类型:" + colorFactoryBean2.getClass());
}

组件赋值

@Value

  • 写在属性上,使用@Value对属性进行赋值

  • 方法

    • 直接写基本数值
    • SpEL(Spring的表达式):#{}
    • ${}:取出配置文件中的值(运行环境变量的值)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Person {

    @Value("张三")
    private String name;
    @Value("#{20-2}")
    private Integer age;
    @Value("${person.nickName}")
    private String nickName;

    }
    1
    person.nickName=\u5c0f\u5f20
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 使用@PropertySource读取外部配置文件中的k/v保存在运行的环境变量中
    @PropertySource({"classpath:person.properties"})
    @Configuration
    public class PropertyValuesConfig {

    @Bean
    public Person person() {
    return new Person();
    }

    }

@PropertySource

  • 读取外部配置文件中的k/v保存在运行的环境变量中

@Autowired

  • Spring利用依赖注入(DI),由Spring定义,完成对IOC容器中中各个组件的依赖关系赋值

  • @Autowired:自动注入

    1. 默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class),找到就赋值

    2. 如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找:applicationContext.getBean(“bookDao”)

    3. @Qualifier(“bookDao”):使用@Qualifier指定需要装配的组件的id,而不是使用属性名

    4. 自动装配默认一定要将属性赋值好,没有就会报错

    5. @Autowired(required=false),没有该bean时则不装配,不会报错

    6. @Primary:让Spring进行自动装配的时候,默认使用首选的bean

      • 也可以继续使用@Qualifier指定需要装配的bean的名字
      1
      2
      3
      4
      5
      6
      7
      @Primary
      @Bean("bookDao2")
      public BookDao bookDao() {
      BookDao bookDao = new BookDao();
      bookDao.setLabel("2");
      return bookDao;
      }
  • @Resource:JSR250,java规范的注解

    • 可以和@Autowired一样实现自动装配功能
    • 默认按照组件名称进行装配
    • 不支持@Primary和@Autowired(reqiured=false)
  • @Inject:JSR330,java规范的注解

    • 需要导入javax.inject的包,和Autowired的功能一样
    • 不支持required=false
  • AutowiredAnnotationBeanPostProcessor:解析完成自动装配功能

@Profile

  • Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能

    • 开发环境、测试环境、生产环境
    • 数据源:(/A)(/B)(/C)
  • @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件

    • 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中,默认是default环境

    • 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效

    • 没有标注环境标识的bean在任何环境下都是加载的

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      // 方式1,2
      @PropertySource("classpath:dbconfig.properties")
      @Configuration
      public class ProfileConfig implements EmbeddedValueResolverAware {

      // 方式3
      private StringValueResolver valueResolver;

      private String driverClassName;

      // 方式1
      @Value("${mysql.username}")
      private String username;

      @Value("${mysql.password}")
      private String password;

      @Profile("dev")
      @Bean("devDataSource")
      // 方式2
      public DataSource dataSourceForDevelop(@Value("${mysql.develop.url}") String url) {
      DruidDataSource dataSource = new DruidDataSource();
      dataSource.setDriverClassName(driverClassName);
      dataSource.setUrl(url);
      dataSource.setUsername(username);
      dataSource.setPassword(password);
      return dataSource;
      }

      @Profile("test")
      @Bean("testDataSource")
      public DataSource dataSourceForTest(@Value("${mysql.test.url}") String url) {
      DruidDataSource dataSource = new DruidDataSource();
      dataSource.setDriverClassName(driverClassName);
      dataSource.setUrl(url);
      dataSource.setUsername(username);
      dataSource.setPassword(password);
      return dataSource;
      }

      @Bean
      public Orange orange() {
      return new Orange();
      }

      @Profile("prod")
      @Bean("prodDataSource")
      public DataSource dataSourceForProduce(@Value("${mysql.produce.url}") String url) {
      DruidDataSource dataSource = new DruidDataSource();
      dataSource.setDriverClassName(driverClassName);
      dataSource.setUrl(url);
      dataSource.setUsername(username);
      dataSource.setPassword(password);
      return dataSource;
      }

      @Override
      // 方式3
      public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
      valueResolver = stringValueResolver;
      driverClassName = valueResolver.resolveStringValue("${mysql.driverClassName}");
      }

      }
    • 使用方法

      • 使用命令行动态参数:-Dspring.profiles=test

      • 使用代码

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        public void test2() {
        // 使用空参创建applicationContext
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 设置需要激活的环境
        applicationContext.getEnvironment().setActiveProfiles("test", "dev");
        // 注册主配置类
        applicationContext.register(ProfileConfig.class);
        // 启动刷新容器
        applicationContext.refresh();
        }
        }

组件注入

标注位置:构造器,参数,方法,属性,都是从容器中获取参数组件的值

标注在方法位置:@Bean+方法参数

  • 参数从容器中获取
  • 默认不写@Autowired效果是一样的,都能自动装配

标在构造器上:如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取

放在参数位置

自定义组件

  • 想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx):
    • 自定义组件实现xxxAware:在创建对象的时候,会调用接口规定的方法注入相关组件,Aware
    • 把Spring底层一些组件注入到自定义的Bean中
    • xxxAware:功能使用xxxProcessor
      • ApplicationContextAware -> ApplicationContextAwareProcessor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {

private ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("传入的IOC容器:" + applicationContext);
this.applicationContext = applicationContext;
}

@Override
public void setBeanName(String s) {
System.out.println("当前Bean的名字:" + s);
}

@Override
public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
String s = stringValueResolver.resolveStringValue("当前系统为:${os.name}");
System.out.println("解析的字符串:" + s);
}

}

AOP

动态代理:指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式

需导入Spring AOP:spring-aspects

通知方法

  •         前置通知:**@Before**,在目标方法运行之前运行
    
  •         后置通知:**@After**,在目标方法运行结束之后运行(无论方法正常结束还是异常结束)
    
  •     返回通知:**@AfterReturning**,在目标方法正常返回之后运行
    
    •         returning:运行返回的结果值
      
  •     异常通知:**@AfterThrowing**,在目标方法出现异常以后运行
    
    •         throwing:运行抛出的异常
      
  •     环绕通知:**@Around**,动态代理,手动推进目标方法运行
    
    •     joinPoint.procced()
      
      •     JoinPoint必须写在参数的第一位,不然Spring无法识别
        

切入点

  • @Pointcut()
  • 本类引用:直接方法名
  • 其它引用:全类名加方法名

步骤

  1. 导入aop模块Spring AOP:spring-aspects
  2. 定义一个业务逻辑类(MathCalculator):在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
  3. 定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行
  4. 给切面类的目标方法标注何时何地运行(通知注解)
  5. 将切面类和业务逻辑类(目标方法所在类)都加入到容器中
  6. 必须告诉Spring哪个类是切面类:给切面类上加一个注解@Aspect
  7. 给配置类中加@EnableAspectJAutoProxy:开启基于注解的aop模式
    • 在Spring中很多的 @EnableXXX:
  •     **主要把握三步**
    
    1. 将业务逻辑组件和切面类都加入到容器中告诉Spring哪个是切面类:@Aspect
    2. 在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行:切入点表达式
    3. 开启基于注解的aop模式:@EnableAspectJAutoProxy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 告诉Spring当前类为切面类
@Aspect
public class LogAspects {

// 抽取公共切入点表达式
@Pointcut("execution(public int cc.mousse.aop.MathCalculator.*(..))")
public void pointCut() {
}

@Before("pointCut()")
public void logStart(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
System.out.println(joinPoint.getSignature().getName() + "运行,参数列表:" + Arrays.toString(args));
}

@After("pointCut()")
public void logEnd(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName() + "结束");
}

@AfterReturning(value = "pointCut()", returning = "result")
// JoinPoint必须写在参数的第一位,不然Spring无法识别
public void logReturn(JoinPoint joinPoint, Object result) {
System.out.println(joinPoint.getSignature().getName() + "正常返回,运行结果:" + result);
}

@AfterThrowing(value = "pointCut()", throwing = "exception")
public void logException(JoinPoint joinPoint, Exception exception) {
System.out.println(joinPoint.getSignature().getName() + "异常,异常信息:" + exception);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 开启基于注解的aop模式
@EnableAspectJAutoProxy
@Configuration
public class AopConfig {

// 把业务逻辑类加入容器中
@Bean
public MathCalculator mathCalculator() {
return new MathCalculator();
}

// 把切面类加入容器中
@Bean
public LogAspects logAspects() {
return new LogAspects();
}

}

原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/* 
* AOP:【动态代理】
* 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;
*
* 1、导入aop模块;Spring AOP:(spring-aspects)
* 2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
* 3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;
* 通知方法:
* 前置通知(@Before):logStart:在目标方法(div)运行之前运行
* 后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
* 返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
* 异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
* 环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
* 4、给切面类的目标方法标注何时何地运行(通知注解);
* 5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
* 6、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
* [7]、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
* 在Spring中很多的 @EnableXXX;
*
* 三步:
* 1)、将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)
* 2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
* 3)、开启基于注解的aop模式;@EnableAspectJAutoProxy
*
* AOP原理:【看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?】
* @EnableAspectJAutoProxy;
* 1、@EnableAspectJAutoProxy是什么?
* @Import(AspectJAutoProxyRegistrar.class):给容器中导入AspectJAutoProxyRegistrar
* 利用AspectJAutoProxyRegistrar自定义给容器中注册bean;BeanDefinetion
* internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
*
* 给容器中注册一个AnnotationAwareAspectJAutoProxyCreator;
*
* 2、 AnnotationAwareAspectJAutoProxyCreator:
* AnnotationAwareAspectJAutoProxyCreator
* ->AspectJAwareAdvisorAutoProxyCreator
* ->AbstractAdvisorAutoProxyCreator
* ->AbstractAutoProxyCreator
* implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
* 关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory
*
* AbstractAutoProxyCreator.setBeanFactory()
* AbstractAutoProxyCreator.有后置处理器的逻辑;
*
* AbstractAdvisorAutoProxyCreator.setBeanFactory()-》initBeanFactory()
*
* AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()
*
*
* 流程:
* 1)、传入配置类,创建ioc容器
* 2)、注册配置类,调用refresh()刷新容器;
* 3)、registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建;
* 1)、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
* 2)、给容器中加别的BeanPostProcessor
* 3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
* 4)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
* 5)、注册没实现优先级接口的BeanPostProcessor;
* 6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
* 创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
* 1)、创建Bean的实例
* 2)、populateBean;给bean的各种属性赋值
* 3)、initializeBean:初始化bean;
* 1)、invokeAwareMethods():处理Aware接口的方法回调
* 2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
* 3)、invokeInitMethods();执行自定义的初始化方法
* 4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
* 4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
* 7)、把BeanPostProcessor注册到BeanFactory中;
* beanFactory.addBeanPostProcessor(postProcessor);
* =======以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程========
*
* AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor
* 4)、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;创建剩下的单实例bean
* 1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);
* getBean->doGetBean()->getSingleton()->
* 2)、创建bean
* 【AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation()】
* 1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;
* 只要创建好的Bean都会被缓存起来
* 2)、createBean();创建bean;
* AnnotationAwareAspectJAutoProxyCreator 会在任何bean创建之前先尝试返回bean的实例
* 【BeanPostProcessor是在Bean对象创建完成初始化前后调用的】
* 【InstantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象的】
* 1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation
* 希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续
* 1)、后置处理器先尝试返回对象;
* bean = applyBeanPostProcessorsBeforeInstantiation():
* 拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor;
* 就执行postProcessBeforeInstantiation
* if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
*
* 2)、doCreateBean(beanName, mbdToUse, args);真正的去创建一个bean实例;和3.6流程一样;
* 3)、
*
*
* AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】 的作用:
* 1)、每一个bean创建之前,调用postProcessBeforeInstantiation();
* 关心MathCalculator和LogAspect的创建
* 1)、判断当前bean是否在advisedBeans中(保存了所有需要增强bean)
* 2)、判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,
* 或者是否是切面(@Aspect)
* 3)、是否需要跳过
* 1)、获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】
* 每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;
* 判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true
* 2)、永远返回false
*
* 2)、创建对象
* postProcessAfterInitialization;
* return wrapIfNecessary(bean, beanName, cacheKey);//包装如果需要的情况下
* 1)、获取当前bean的所有增强器(通知方法) Object[] specificInterceptors
* 1、找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)
* 2、获取到能在bean使用的增强器。
* 3、给增强器排序
* 2)、保存当前bean在advisedBeans中;
* 3)、如果当前bean需要增强,创建当前bean的代理对象;
* 1)、获取所有增强器(通知方法)
* 2)、保存到proxyFactory
* 3)、创建代理对象:Spring自动决定
* JdkDynamicAopProxy(config);jdk动态代理;
* ObjenesisCglibAopProxy(config);cglib的动态代理;
* 4)、给容器中返回当前组件使用cglib增强了的代理对象;
* 5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
*
*
* 3)、目标方法执行 ;
* 容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
* 1)、CglibAopProxy.intercept();拦截目标方法的执行
* 2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;
* List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
* 1)、List<Object> interceptorList保存所有拦截器 5
* 一个默认的ExposeInvocationInterceptor 和 4个增强器;
* 2)、遍历所有的增强器,将其转为Interceptor;
* registry.getInterceptors(advisor);
* 3)、将增强器转为List<MethodInterceptor>;
* 如果是MethodInterceptor,直接加入到集合中
* 如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
* 转换完成返回MethodInterceptor数组;
*
* 3)、如果没有拦截器链,直接执行目标方法;
* 拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)
* 4)、如果有拦截器链,把需要执行的目标对象,目标方法,
* 拦截器链等信息传入创建一个 CglibMethodInvocation 对象,
* 并调用 Object retVal = mi.proceed();
* 5)、拦截器链的触发过程;
* 1)、如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;
* 2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
* 拦截器链的机制,保证通知方法与目标方法的执行顺序;
*/

总结

  1. @EnableAspectJAutoProxy开启AOP功能
  2. @EnableAspectJAutoProxy会给容器中注册一个组件:AnnotationAwareAspectJAutoProxyCreator
  3. AnnotationAwareAspectJAutoProxyCreator是一个后置处理器
  4. 容器的创建流程:
    1. registerBeanPostProcessors()注册后置处理器:创建AnnotationAwareAspectJAutoProxyCreator对象
    2. finishBeanFactoryInitialization()初始化剩下的单实例bean
      1. 创建业务逻辑组件和切面组件
      2. AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
      3. 组件创建完之后,判断组件是否需要增强
        • 是:切面的通知方法,包装成增强器(Advisor),给业务逻辑组件创建一个代理对象(cglib)
  5. 执行目标方法:
    1. 代理对象执行目标方法
    2. CglibAopProxy.intercept():
      1. 得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
      2. 利用拦截器的链式机制,依次进入每一个拦截器进行执行
      3. 效果:
        • 正常执行:前置通知 -> 目标方法 -> 后置通知 -> 返回通知
        • 出现异常:前置通知 -> 目标方法 -> 后置通知 -> 异常通知

声明式事务

环境搭建

  1. 导入相关依赖:数据源、数据库驱动、Spring-jdbc模块
  2. 配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
  3. 给方法上标注@Transactional表示当前方法是一个事务方法
  4. @EnableTransactionManagement开启基于注解的事务管理功能:@EnableXXX
  5. 配置事务管理器来控制事务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@EnableTransactionManagement
@ComponentScan("cc.mousse.tx")
@PropertySource("classpath:dbconfig.properties")
@Configuration
public class TxConfig {

@Value("${mysql.driverClassName}")
String driverClassName;

@Value("${mysql.url}")
String url;

@Value("${mysql.username}")
String username;

@Value("${mysql.password}")
String password;

@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}

@Bean
public JdbcTemplate jdbcTemplate() {
// Spring对@Configuration类会特殊处理,容器中加组件时多次调用只是从容器中找组件而已
return new JdbcTemplate(dataSource());
}

@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}

}
1
2
3
4
5
6
7
8
@Transactional
public void insertRandomUser() {
String username = UUID.randomUUID().toString().substring(0, 5);
Integer age = new Random().nextInt(50);
userDao.insert(new User(null, username, age));
System.out.println("insertRandomUser successfully");
int i = 0 / 0;
}

原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
* 1)、@EnableTransactionManagement
* 利用TransactionManagementConfigurationSelector给容器中会导入组件
* 导入两个组件
* AutoProxyRegistrar
* ProxyTransactionManagementConfiguration
* 2)、AutoProxyRegistrar:
* 给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;
* InfrastructureAdvisorAutoProxyCreator:?
* 利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;
*
* 3)、ProxyTransactionManagementConfiguration 做了什么?
* 1、给容器中注册事务增强器;
* 1)、事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解
* 2)、事务拦截器:
* TransactionInterceptor;保存了事务属性信息,事务管理器;
* 他是一个 MethodInterceptor;
* 在目标方法执行的时候;
* 执行拦截器链;
* 事务拦截器:
* 1)、先获取事务相关的属性
* 2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger
* 最终会从容器中按照类型获取一个PlatformTransactionManager;
* 3)、执行目标方法
* 如果异常,获取到事务管理器,利用事务管理回滚操作;
* 如果正常,利用事务管理器,提交事务
*/

扩展原理

BeanFactoryPostProcessor

  • BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的
  • BeanFactoryPostProcessor:beanFactory的后置处理器
    • 在BeanFactory标准初始化之后调用,来定制和修改BeanFactory的内容
    • 所有的bean定义已经保存加载到beanFactory,但是bean的实例还未创建
1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("MyBeanFactoryPostProcessor.postProcessBeanFactory()");
int count = configurableListableBeanFactory.getBeanDefinitionCount();
String[] names = configurableListableBeanFactory.getBeanDefinitionNames();
System.out.println("当前BeanFactory中Bean的数量:" + count);
System.out.println("当前BeanFactory中Bean的名字:" + Arrays.asList(names));
}

}

原理

  1. ioc容器创建对象
  2. invokeBeanFactoryPostProcessors(beanFactory)
    1. 直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法
    2. 在初始化创建其他组件前面执行

BeanDefinitionRegistryPostProcessor

  • BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
  • postProcessBeanDefinitionRegistry():在所有bean定义信息将要被加载,bean实例还未创建的
  • 优先于BeanFactoryPostProcessor执行
  • 利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

// bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里保存的每个定义信息创建bean实例
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry().当前BeanFactory中Bean的数量:" + beanDefinitionRegistry.getBeanDefinitionCount());
// RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Orange.class);
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Orange.class).getBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition("hello", beanDefinition);
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessor.postProcessBeanFactory().当前BeanFactory中Bean的数量:" + configurableListableBeanFactory.getBeanDefinitionCount());
}

}

原理

  1. ioc创建对象
  2. refresh() -> invokeBeanFactoryPostProcessors(beanFactory)
  3. 从容器中获取到所有的BeanDefinitionRegistryPostProcessor组件
    1. 依次触发所有的postProcessBeanDefinitionRegistry()方法
    2. 再来触发postProcessBeanFactory()方法BeanFactoryPostProcessor
  4. 再来从容器中找到BeanFactoryPostProcessor组件;然后依次触发postProcessBeanFactory()方法

ApplicationListener

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

1
public interface ApplicationListener<E extends ApplicationEvent>
  • 监听ApplicationEvent及其下面的子事件
1
2
3
4
5
6
7
8
9
10
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {

// 当容器中发布此事件后,方法触发
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println("收到事件:" + applicationEvent);
}

}

步骤

  1. 写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类)

    • @EventListener

      • 原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener
      1
      2
      3
      4
      5
      6
      7
      8
      9
      @Service
      public class UserService {

      @EventListener(classes = ApplicationEvent.class)
      public void listen(ApplicationEvent applicationEvent) {
      System.out.println("UserService监听到的事件:" + applicationEvent);
      }

      }
  2. 把监听器加入到容器

  3. 只要容器中有相关事件的发布,我们就能监听到这个事件

    • ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件
    • ContextClosedEvent:关闭容器会发布这个事件
  4. 发布一个事件:applicationContext.publishEvent()

    1
    2
    annotationConfigApplicationContext.publishEvent(new ApplicationEvent("我发布的事件") {
    });

原理

ContextRefreshedEvent、IOCTest_Ext$1[source=我发布的时间]、ContextClosedEvent

  1. ContextRefreshedEvent事件
    1. 容器创建对象:refresh()
    2. inishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
  2. 自己发布事件
  3. 容器关闭会发布ContextClosedEvent

事件发布流程

publishEvent(new ContextRefreshedEvent(this))

  1. 获取事件的多播器(派发器):getApplicationEventMulticaster()

  2. multicastEvent派发事件:

  3. 获取到所有的ApplicationListener

    1
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { }
    1. 如果有Executor,可以支持使用Executor进行异步派发:Executor executor = getTaskExecutor()
    2. 否则同步的方式直接执行listener方法:invokeListener(listener, event);
  4. 拿到listener回调onApplicationEvent方法

事件多播器(派发器)

  1. 容器创建对象:refresh()
  2. initApplicationEventMulticaster()初始化ApplicationEventMulticaster
    1. 先去容器中找有没有id=“applicationEventMulticaster”的组件
      • 如果没有:this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory),并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster

容器中的监听器

  1. 容器创建对象:refresh()

  2. registerListeners():从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中

    1
    2
    3
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    //将listener注册到ApplicationEventMulticaster中
    getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

SmartInitializingSingleton原理:afterSingletonsInstantiated()

  1. ioc容器创建对象并refresh()
  2. finishBeanFactoryInitialization(beanFactory):初始化剩下的单实例bean
    1. 先创建所有的单实例bean:getBean()
    2. 获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的
      • 如果是就调用afterSingletonsInstantiated()

Spring容器创建过程

Spring容器的refresh():创建刷新

  1. prepareRefresh()刷新前的预处理

    1. initPropertySources()初始化一些属性设置:子类自定义个性化的属性设置方法
    2. getEnvironment().validateRequiredProperties():检验属性的合法等
    3. earlyApplicationEvents= new LinkedHashSet<ApplicationEvent>():保存容器中的一些早期的事件
  2. obtainFreshBeanFactory():获取BeanFactory

    1. refreshBeanFactory():刷新(创建)BeanFactory
      1. 创建了一个this.beanFactory = new DefaultListableBeanFactory()
      2. 设置id;
    2. getBeanFactory():返回刚才GenericApplicationContext创建的BeanFactory对象
    3. 将创建的BeanFactory(DefaultListableBeanFactory)返回
  3. prepareBeanFactory(beanFactory):BeanFactory的预准备工作(BeanFactory进行一些设置)

    1. 设置BeanFactory的类加载器、支持表达式解析器…
    2. 添加部分BeanPostProcessor:ApplicationContextAwareProcessor
    3. 设置忽略的自动装配的接口:EnvironmentAware、EmbeddedValueResolverAware、xxx
    4. 注册可以解析的自动装配,我们能直接在任何组件中自动注入:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
    5. 添加BeanPostProcessor:ApplicationListenerDetector
    6. 添加编译时的AspectJ
    7. 给BeanFactory中注册一些能用的组件:
      • environment(ConfigurableEnvironment)
      • systemProperties(Map<String, Object>)
      • systemEnvironment(Map<String, Object>)
  4. postProcessBeanFactory(beanFactory):BeanFactory准备工作完成后进行的后置处理工作

    1. 子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置

    以上是BeanFactory的创建及预准备工作

  5. invokeBeanFactoryPostProcessors(beanFactory):执行BeanFactoryPostProcessor的方法:

    • BeanFactoryPostProcessor:BeanFactory的后置处理器。在BeanFactory标准初始化之后执行的
    • 两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
      1. 执行BeanFactoryPostProcessor的方法:
        1. 先执行BeanDefinitionRegistryPostProcessor
          1. 获取所有的BeanDefinitionRegistryPostProcessor
          2. 看先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、
            postProcessor.postProcessBeanDefinitionRegistry(registry)
          3. 在执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor;
            postProcessor.postProcessBeanDefinitionRegistry(registry)
          4. 最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors;
            postProcessor.postProcessBeanDefinitionRegistry(registry)
        2. 再执行BeanFactoryPostProcessor的方法
          1. 获取所有的BeanFactoryPostProcessor
          2. 看先执行实现了PriorityOrdered优先级接口的BeanFactoryPostProcessor、
            postProcessor.postProcessBeanFactory()
          3. 在执行实现了Ordered顺序接口的BeanFactoryPostProcessor;
            postProcessor.postProcessBeanFactory()
          4. 最后执行没有实现任何优先级或者是顺序接口的BeanFactoryPostProcessor;
            postProcessor.postProcessBeanFactory()
  6. registerBeanPostProcessors(beanFactory):注册BeanPostProcessor(Bean的后置处理器)intercept bean creation

    • 不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的:BeanPostProcessor、DestructionAwareBeanPostProcessor、InstantiationAwareBeanPostProcessor、SmartInstantiationAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor、internalPostProcessors

    1. 获取所有的 BeanPostProcessor:后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
    2. 先注册PriorityOrdered优先级接口的BeanPostProcessor;把每一个BeanPostProcessor添加到BeanFactory中
      beanFactory.addBeanPostProcessor(postProcessor)
    3. 再注册Ordered接口的
    4. 最后注册没有实现任何优先级接口的
    5. 最终注册MergedBeanDefinitionPostProcessor;
    6. 注册一个ApplicationListenerDetector;来在Bean创建完成后检查是否是ApplicationListener,如果是applicationContext.addApplicationListener((ApplicationListener<?>) bean)
  7. initMessageSource():初始化MessageSource组件(做国际化功能;消息绑定,消息解析)

    1. 获取BeanFactory

    2. 看容器中是否有id为messageSource的,类型是MessageSource的组件如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource;

      • MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取;
    3. 把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource

      1
      2
      beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);	
      MessageSource.getMessage(String code, Object[] args, String defaultMessage, Locale locale)
  8. initApplicationEventMulticaster():初始化事件派发器

    1. 获取BeanFactory
    2. 从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster;
    3. 如果上一步没有配置;创建一个SimpleApplicationEventMulticaster
    4. 将创建的ApplicationEventMulticaster添加到BeanFactory中,以后其他组件直接自动注入
  9. onRefresh():留给子容器(子类)

    1. 子类重写这个方法,在容器刷新的时候可以自定义逻辑
  10. registerListeners():给容器中将所有项目里面的ApplicationListener注册进来

    1. 从容器中拿到所有的ApplicationListener
    2. 将每个监听器添加到事件派发器中:
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    3. 派发之前步骤产生的事件;
  11. finishBeanFactoryInitialization(beanFactory):初始化所有剩下的单实例bean;

    1. beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean

      1. 获取容器中的所有Bean,依次进行初始化和创建对象

      2. 获取Bean的定义信息;RootBeanDefinition

      3. Bean不是抽象的,是单实例的,是懒加载;

        1. 判断是否是FactoryBean;是否是实现FactoryBean接口的Bean;

        2. 不是工厂Bean。利用getBean(beanName);创建对象

          1. getBean(beanName); ioc.getBean();

          2. doGetBean(name, null, null, false);

          3. 先获取缓存中保存的单实例Bean。如果能获取到说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存起来)

            • 从private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);获取的
          4. 缓存中获取不到,开始Bean的创建对象流程;

          5. 标记当前bean已经被创建

          6. 获取Bean的定义信息;

          7. 【获取当前Bean依赖的其他Bean;如果有按照getBean()把依赖的Bean先创建出来;】

          8. 启动单实例Bean的创建流程

            1. createBean(beanName, mbd, args);

            2. Object bean = resolveBeforeInstantiation(beanName, mbdToUse):让BeanPostProcessor先拦截返回代理对象 【InstantiationAwareBeanPostProcessor】:提前执行

              1. 先触发:postProcessBeforeInstantiation()
              2. 如果有返回值:触发postProcessAfterInitialization()
            3. 如果前面的InstantiationAwareBeanPostProcessor没有返回代理对象;调用4

            4. Object beanInstance = doCreateBean(beanName, mbdToUse, args);创建Bean

              1. 创建Bean实例:createBeanInstance(beanName, mbd, args)

                • 利用工厂方法或者对象的构造器创建出Bean实例
              2. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

                • 调用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition(mbd, beanType, beanName);
              3. Bean属性赋值:populateBean(beanName, mbd, instanceWrapper),赋值之前:

                1. 拿到InstantiationAwareBeanPostProcessor后置处理器: postProcessAfterInstantiation();

                2. 拿到InstantiationAwareBeanPostProcessor后置处理器: postProcessPropertyValues()

                  赋值之前

                3. 应用Bean属性的值;为属性利用setter方法等进行赋值:applyPropertyValues(beanName, mbd, bw, pvs);

                4. Bean初始化:initializeBean(beanName, exposedObject, mbd);

                  1. 执行Aware接口方法:invokeAwareMethods(beanName, bean);执行xxxAware接口的方法

                    • BeanNameAware\BeanClassLoaderAware\BeanFactoryAware
                  2. 执行后置处理器初始化之前:applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName) BeanPostProcessor.postProcessBeforeInitialization();

                  3. 执行初始化方法invokeInitMethods(beanName, wrappedBean, mbd)

                    1. 是否是InitializingBean接口的实现;执行接口规定的初始化
                    2. 是否自定义初始化方法;
                  4. 执行后置处理器初始化之后:applyBeanPostProcessorsAfterInitialization BeanPostProcessor.postProcessAfterInitialization();

                  5. 注册Bean的销毁方法

                5. 将创建的Bean添加到缓存中singletonObjects

                  • ioc容器就是这些Map;很多的Map里面保存了单实例Bean,环境信息。。。。
                  • 所有Bean都利用getBean创建完成以后;
                  • 检查所有的Bean是否是SmartInitializingSingleton接口的;如果是;就执行afterSingletonsInstantiated();
  12. finishRefresh();完成BeanFactory的初始化创建工作;IOC容器就创建完成;

    1. initLifecycleProcessor():初始化和生命周期有关的后置处理器;LifecycleProcessor
      1. 默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】:
        • 如果没有new DefaultLifecycleProcessor();加入到容器;写一个LifecycleProcessor的实现类,可以在BeanFactory
          • void onRefresh();
          • void onClose();

    2. getLifecycleProcessor().onRefresh();
      拿到前面定义的生命周期处理器(BeanFactory);回调onRefresh();
    3. publishEvent(new ContextRefreshedEvent(this)):发布容器刷新完成事件
    4. liveBeansView.registerApplicationContext(this)

总结

  1. Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息
    • xml注册bean:<bean>
    • 注解注册Bean:@Service、@Component、@Bean、xxx
  2. Spring容器会合适的时机创建这些Bean
    1. 用到这个bean的时候利用getBean创建bean,创建好以后保存在容器中
    2. 统一创建剩下所有的bean的时候:finishBeanFactoryInitialization()
  3. 后置处理器:BeanPostProcessor
    • 每一个bean创建完成,都会使用各种后置处理器进行处理来增强bean的功能
      • AutowiredAnnotationBeanPostProcessor:处理自动注入
      • AnnotationAwareAspectJAutoProxyCreator:来做AOP功能
      • xxx….
      • 增强的功能注解:
        AsyncAnnotationBeanPostProcessor….
  4. 事件驱动模型:
    • ApplicationListener:事件监听
    • ApplicationEventMulticaster:事件派发

Web

Servlet3.0

1
2
3
4
5
6
7
8
9
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello");
}

}

Shared libraries(共享库) / runtimes pluggability(运行时插件能力)

  • Servlet容器启动会扫描,当前应用里面每一个jar包的
    ServletContainerInitializer的实现
  • 提供ServletContainerInitializer的实现类
    • 必须绑定在META-INF/services/javax.servlet.ServletContainerInitializer
    • 文件的内容就是ServletContainerInitializer实现类的全类名

总结:容器在启动应用的时候,会扫描当前应用每一个jar包里面
META-INF/services/javax.servlet.ServletContainerInitializer
指定的实现类,启动并运行这个实现类的方法;传入感兴趣的类型

@HandlesTypes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 容器启动时会将@HandlesTypes指定类下的子类/实现类/子接口传递过来
// 传入感兴趣的类
@HandlesTypes(value = {HelloService.class})
public class MyServletContainerInitializer implements ServletContainerInitializer {

/**
* 应用启动时会运行此方法
*
* @param set 感兴趣的类的所有子类
* @param servletContext 代表当前Web应用的ServletContext对象(一个Web应用对应一个ServletContext对象)
*
*
* 1)、使用ServletContext注册Web组件(Servlet、Filter、Listener)
* 2)、使用编码的方式,在项目启动的时候给ServletContext里面添加组件;
* 必须在项目启动的时候来添加;
* 1)、ServletContainerInitializer得到的ServletContext;
* 2)、ServletContextListener得到的ServletContext;
*/
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
System.out.println("感兴趣的类型:");
set.forEach(System.out::println);

// 注册组件
ServletRegistration.Dynamic userServlet = servletContext.addServlet("userServlet", UserServlet.class);
// 配置Servlet注册信息
userServlet.addMapping("/user");

FilterRegistration.Dynamic userFilter = servletContext.addFilter("userFilter", UserFilter.class);
// 添加Filter的映射信息
userFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");

servletContext.addListener(UserListener.class);
}

}

SpringMVC

依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>

Servlet-SpringMVC整合分析

  1. web容器在启动的时候,会扫描每个jar包下的META-INF/services/javax.servlet.ServletContainerInitializer
  2. 加载这个文件指定的类SpringServletContainerInitializer
  3. spring的应用一启动会加载感兴趣的WebApplicationInitializer接口的下的所有组件;
  4. 并且为WebApplicationInitializer组件创建对象(组件不是接口,不是抽象类)
    1. AbstractContextLoaderInitializer:创建根容器createRootApplicationContext()
    2. AbstractDispatcherServletInitializer:
      1. 创建一个web的ioc容器
      2. createServletApplicationContext():创建了DispatcherServlet
      3. createDispatcherServlet():将创建的DispatcherServlet添加到ServletContext中getServletMappings()
    3. AbstractAnnotationConfigDispatcherServletInitializer:注解方式配置的DispatcherServlet初始化器
      1. 创建根容器:
        1. createRootApplicationContext()
        2. getRootConfigClasses():传入一个配置类
      2. 创建web的ioc容器: createServletApplicationContext()
      3. 获取配置类:getServletConfigClasses()

总结

  • 以注解方式来启动SpringMVC:继承AbstractAnnotationConfigDispatcherServletInitializer
    实现抽象方法指定DispatcherServlet的配置信息

定制SpringMVC

  1. @EnableWebMvc:开启SpringMVC定制配置功能:<mvc:annotation-driven/>
  2. 配置组件(视图解析器、视图映射、静态资源映射、拦截器。。。):extends WebMvcConfigurerAdapter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Web容器启动时创建对象,调用方法初始化容器和前端控制器
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected WebApplicationContext createRootApplicationContext() {
return super.createRootApplicationContext();
}

@Override
protected WebApplicationContext createServletApplicationContext() {
return super.createServletApplicationContext();
}

// 获取前端控制器的映射信息
@Override
protected String[] getServletMappings() {
// /:拦截所有请求,包括静态资源(js/png),不包括jsp
// /*:拦截所有请求,包括jsp,jsp页面是Tomcat的jsp引擎解析的
return new String[]{"/"};
}

// 获取根容器的配置类(Spring配置文件)父容器
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}

// 获取Web容器的配置类(SpringMVC配置文件)子容器
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{AppConfig.class};
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// SpringMVC容器只扫描@Controller:子容器
@ComponentScan(
value = "cc.mousse",
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}
)
// 开启SpringMVC定制功能
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {

// 配置视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
// 默认所有页面都为/WEB-INF/ .jsp
registry.jsp("/WEB-INF/views/", "jsp");
}

// 配置静态资源访问
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}

// 添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyFirstInterceptor()).addPathPatterns("/**");
}

}

异步请求

Servlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 设置支持异步处理
@WebServlet(value = "/async", asyncSupported = true)
public class HelloAsyncServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 开启异步处理
System.out.println("主线程开始: " + Thread.currentThread());
AsyncContext asyncContext = req.startAsync();
// 业务处理进行异步响应
// 开始异步处理
asyncContext.start(() -> {
try {
System.out.println("副线程开始: " + Thread.currentThread());
sayHello(resp);
// 获取到异步上下文
AsyncContext reqAsyncContext = req.getAsyncContext();
// 获取响应
ServletResponse response = reqAsyncContext.getResponse();
response.getWriter().write(" ASYNC");
// 异步结束
asyncContext.complete();
System.out.println("副线程结束: " + Thread.currentThread());
} catch (Exception e) {
e.printStackTrace();
}
});
System.out.println("主线程结束: " + Thread.currentThread());
}

private void sayHello(HttpServletResponse resp) throws Exception {
resp.getWriter().write("Hello");
Thread.sleep(3000);
}

}

SpringMVC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
@Controller
public class AsyncController {
/**
* 1、控制器返回Callable
* 2、Spring异步处理,将Callable 提交到 TaskExecutor 使用一个隔离的线程进行执行
* 3、DispatcherServlet和所有的Filter退出web容器的线程,但是response 保持打开状态;
* 4、Callable返回结果,SpringMVC将请求重新派发给容器,恢复之前的处理;
* 5、根据Callable返回的结果。SpringMVC继续进行视图渲染流程等(从收请求-视图渲染)。
*
* preHandle.../springmvc-annotation/async01
主线程开始...Thread[http-bio-8081-exec-3,5,main]==>1513932494700
主线程结束...Thread[http-bio-8081-exec-3,5,main]==>1513932494700
=========DispatcherServlet及所有的Filter退出线程============================

================等待Callable执行==========
副线程开始...Thread[MvcAsync1,5,main]==>1513932494707
副线程开始...Thread[MvcAsync1,5,main]==>1513932496708
================Callable执行完成==========

================再次收到之前重发过来的请求========
preHandle.../springmvc-annotation/async01
postHandle...(Callable的之前的返回值就是目标方法的返回值)
afterCompletion...

异步的拦截器:
1)、原生API的AsyncListener
2)、SpringMVC:实现AsyncHandlerInterceptor;
*/
@RequestMapping("/async")
@ResponseBody
public Callable<String> asynchronous () {
System.out.println("主线程开始: " + Thread.currentThread() + "\t" + System.currentTimeMillis());
Callable<String> stringCallable = () -> {
System.out.println("副线程开始: " + Thread.currentThread() + "\t" + System.currentTimeMillis());
Thread.sleep(3000);
System.out.println("副线程结束: " + Thread.currentThread() + "\t" + System.currentTimeMillis());
return "Callable<String> asynchronous";
};
System.out.println("主线程结束: " + Thread.currentThread() + "\t" + System.currentTimeMillis());
return stringCallable;
}


/**
* 模拟消息队列
*/
@RequestMapping("/createOrder")
@ResponseBody
public DeferredResult<Object> createOrder() {
DeferredResult<Object> objectDeferredResult = new DeferredResult<>((long) 3000, "Create failed");
DeferredResultQueue.save(objectDeferredResult);
return objectDeferredResult;
}

@RequestMapping("/create")
@ResponseBody
private String create() {
// 创建订单
String order = UUID.randomUUID().toString();
DeferredResult<Object> objectDeferredResult = DeferredResultQueue.get();
objectDeferredResult.setResult(order);
return "success-" + order;
}
}