Spring注解开发
Spring注解开发
容器
组件添加
注册方式
- 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component):局限于自己写的类
- @Bean:导入的第三方包里的组件
- @Import:快速给容器中导入一个组件
- @Import(要导入到容器中的组件),容器中就会自动注册这个组件,id默认是全类名
- ImportSelector:返回需要导入的组件的全类名数组
- ImportBeanDefinitionRegistrar:手动注册bean到容器中
- 使用Spring提供的FactoryBean(工厂Bean)
默认获取到的是工厂bean调用getObject创建的对象
要获取工厂Bean本身,需要给id前面加一个&
&colorFactoryBean
- @Import(要导入到容器中的组件),容器中就会自动注册这个组件,id默认是全类名
@Configuration
- 写在配置类上,告诉Spring这是一个配置类
@Bean
- 写在配置类中的方法上,为容器中注册一个Bean
- 类型为返回值类型
- 方法名默认作为id
- 参数
- value:默认,指定容器名
生命周期
- 由容器管理bean的创建,初始化,销毁,我们可以自定义初始化和销毁方法
- 指定初始化和销毁方法:
@Bean指定方法
- initMethod和destroyMethod
- 单实例:容器启动时创建对象,关闭容器时销毁
- 多实例:每次获取时创建对象,不进行销毁
1 |
|
Bean实现接口
- 实现InitializingBean定义初始化
- 实现DisposableBean定义销毁
1 |
|
使用JSR250
写在方法上
@PostConstruct:在bean创建完成并且属性赋值完成来执行初始化方法
@PreDestroy:在容器销毁bean之前通知我们进行清理工作
1 |
|
BeanPostProcessor
- bean的后置处理器,在bean初始化前后进行一些处理工作
- postProcessBeforeInitialization:在初始化之前工作
- postProcessAfterInitialization:在初始化之后工作
1 |
|
1 |
|
- 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
21public 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容器启动时就会调用方法把对象放到容器中,每次获取直接从容器中拿
- prototype:多实例
@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
17public 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
19public 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 |
|
1 |
|
组件赋值
@Value
写在属性上,使用@Value对属性进行赋值
方法
- 直接写基本数值
- SpEL(Spring的表达式):#{}
- ${}:取出配置文件中的值(运行环境变量的值)
1
2
3
4
5
6
7
8
9
10public 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:自动注入
默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class),找到就赋值
如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找:applicationContext.getBean(“bookDao”)
@Qualifier(“bookDao”):使用@Qualifier指定需要装配的组件的id,而不是使用属性名
自动装配默认一定要将属性赋值好,没有就会报错
@Autowired(required=false),没有该bean时则不装配,不会报错
@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
11public 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 |
|
AOP
动态代理:指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式
需导入Spring AOP:spring-aspects
通知方法
前置通知:**@Before**,在目标方法运行之前运行
后置通知:**@After**,在目标方法运行结束之后运行(无论方法正常结束还是异常结束)
返回通知:**@AfterReturning**,在目标方法正常返回之后运行
returning:运行返回的结果值
异常通知:**@AfterThrowing**,在目标方法出现异常以后运行
throwing:运行抛出的异常
环绕通知:**@Around**,动态代理,手动推进目标方法运行
joinPoint.procced()
JoinPoint必须写在参数的第一位,不然Spring无法识别
切入点
- @Pointcut()
- 本类引用:直接方法名
- 其它引用:全类名加方法名
步骤
- 导入aop模块Spring AOP:spring-aspects
- 定义一个业务逻辑类(MathCalculator):在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
- 定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行
- 给切面类的目标方法标注何时何地运行(通知注解)
- 将切面类和业务逻辑类(目标方法所在类)都加入到容器中
- 必须告诉Spring哪个类是切面类:给切面类上加一个注解@Aspect
- 给配置类中加@EnableAspectJAutoProxy:开启基于注解的aop模式
- 在Spring中很多的 @EnableXXX:
**主要把握三步**
- 将业务逻辑组件和切面类都加入到容器中告诉Spring哪个是切面类:@Aspect
- 在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行:切入点表达式
- 开启基于注解的aop模式:@EnableAspectJAutoProxy
1 |
|
1 |
|
原理
1 |
|
总结
- @EnableAspectJAutoProxy开启AOP功能
- @EnableAspectJAutoProxy会给容器中注册一个组件:AnnotationAwareAspectJAutoProxyCreator
- AnnotationAwareAspectJAutoProxyCreator是一个后置处理器
- 容器的创建流程:
- registerBeanPostProcessors()注册后置处理器:创建AnnotationAwareAspectJAutoProxyCreator对象
- finishBeanFactoryInitialization()初始化剩下的单实例bean
- 创建业务逻辑组件和切面组件
- AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
- 组件创建完之后,判断组件是否需要增强
- 是:切面的通知方法,包装成增强器(Advisor),给业务逻辑组件创建一个代理对象(cglib)
- 执行目标方法:
- 代理对象执行目标方法
- CglibAopProxy.intercept():
- 得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
- 利用拦截器的链式机制,依次进入每一个拦截器进行执行
- 效果:
- 正常执行:前置通知 -> 目标方法 -> 后置通知 -> 返回通知
- 出现异常:前置通知 -> 目标方法 -> 后置通知 -> 异常通知
声明式事务
环境搭建
- 导入相关依赖:数据源、数据库驱动、Spring-jdbc模块
- 配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
- 给方法上标注@Transactional表示当前方法是一个事务方法
- @EnableTransactionManagement开启基于注解的事务管理功能:@EnableXXX
- 配置事务管理器来控制事务
1 |
|
1 |
|
原理
1 |
|
扩展原理
BeanFactoryPostProcessor
- BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的
- BeanFactoryPostProcessor:beanFactory的后置处理器
- 在BeanFactory标准初始化之后调用,来定制和修改BeanFactory的内容
- 所有的bean定义已经保存加载到beanFactory,但是bean的实例还未创建
1 |
|
原理
- ioc容器创建对象
- invokeBeanFactoryPostProcessors(beanFactory)
- 直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法
- 在初始化创建其他组件前面执行
BeanDefinitionRegistryPostProcessor
- BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
- postProcessBeanDefinitionRegistry():在所有bean定义信息将要被加载,bean实例还未创建的
- 优先于BeanFactoryPostProcessor执行
- 利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件
1 |
|
原理
- ioc创建对象
- refresh() -> invokeBeanFactoryPostProcessors(beanFactory)
- 从容器中获取到所有的BeanDefinitionRegistryPostProcessor组件
- 依次触发所有的postProcessBeanDefinitionRegistry()方法
- 再来触发postProcessBeanFactory()方法BeanFactoryPostProcessor
- 再来从容器中找到BeanFactoryPostProcessor组件;然后依次触发postProcessBeanFactory()方法
ApplicationListener
监听容器中发布的事件。事件驱动模型开发
1 |
|
- 监听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);
}
}
把监听器加入到容器
只要容器中有相关事件的发布,我们就能监听到这个事件
- ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件
- ContextClosedEvent:关闭容器会发布这个事件
发布一个事件:applicationContext.publishEvent()
1
2annotationConfigApplicationContext.publishEvent(new ApplicationEvent("我发布的事件") {
});
原理
ContextRefreshedEvent、IOCTest_Ext$1[source=我发布的时间]、ContextClosedEvent
- ContextRefreshedEvent事件
- 容器创建对象:refresh()
- inishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
- 自己发布事件
- 容器关闭会发布ContextClosedEvent
事件发布流程
publishEvent(new ContextRefreshedEvent(this))
获取事件的多播器(派发器):getApplicationEventMulticaster()
multicastEvent派发事件:
获取到所有的ApplicationListener
1
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { }
- 如果有Executor,可以支持使用Executor进行异步派发:Executor executor = getTaskExecutor()
- 否则同步的方式直接执行listener方法:invokeListener(listener, event);
拿到listener回调onApplicationEvent方法
事件多播器(派发器)
- 容器创建对象:refresh()
- initApplicationEventMulticaster()初始化ApplicationEventMulticaster
- 先去容器中找有没有id=“applicationEventMulticaster”的组件
- 如果没有:this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory),并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster
- 先去容器中找有没有id=“applicationEventMulticaster”的组件
容器中的监听器
容器创建对象:refresh()
registerListeners():从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中
1
2
3String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
//将listener注册到ApplicationEventMulticaster中
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
SmartInitializingSingleton原理:afterSingletonsInstantiated()
- ioc容器创建对象并refresh()
- finishBeanFactoryInitialization(beanFactory):初始化剩下的单实例bean
- 先创建所有的单实例bean:getBean()
- 获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的
- 如果是就调用afterSingletonsInstantiated()
Spring容器创建过程
Spring容器的refresh():创建刷新
prepareRefresh()刷新前的预处理
- initPropertySources()初始化一些属性设置:子类自定义个性化的属性设置方法
- getEnvironment().validateRequiredProperties():检验属性的合法等
- earlyApplicationEvents= new LinkedHashSet<ApplicationEvent>():保存容器中的一些早期的事件
obtainFreshBeanFactory():获取BeanFactory
- refreshBeanFactory():刷新(创建)BeanFactory
- 创建了一个this.beanFactory = new DefaultListableBeanFactory()
- 设置id;
- getBeanFactory():返回刚才GenericApplicationContext创建的BeanFactory对象
- 将创建的BeanFactory(DefaultListableBeanFactory)返回
- refreshBeanFactory():刷新(创建)BeanFactory
prepareBeanFactory(beanFactory):BeanFactory的预准备工作(BeanFactory进行一些设置)
- 设置BeanFactory的类加载器、支持表达式解析器…
- 添加部分BeanPostProcessor:ApplicationContextAwareProcessor
- 设置忽略的自动装配的接口:EnvironmentAware、EmbeddedValueResolverAware、xxx
- 注册可以解析的自动装配,我们能直接在任何组件中自动注入:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
- 添加BeanPostProcessor:ApplicationListenerDetector
- 添加编译时的AspectJ
- 给BeanFactory中注册一些能用的组件:
- environment(ConfigurableEnvironment)
- systemProperties(Map<String, Object>)
- systemEnvironment(Map<String, Object>)
postProcessBeanFactory(beanFactory):BeanFactory准备工作完成后进行的后置处理工作
- 子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置
以上是BeanFactory的创建及预准备工作
invokeBeanFactoryPostProcessors(beanFactory):执行BeanFactoryPostProcessor的方法:
- BeanFactoryPostProcessor:BeanFactory的后置处理器。在BeanFactory标准初始化之后执行的
- 两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
- 执行BeanFactoryPostProcessor的方法:
- 先执行BeanDefinitionRegistryPostProcessor
- 获取所有的BeanDefinitionRegistryPostProcessor
- 看先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、
postProcessor.postProcessBeanDefinitionRegistry(registry) - 在执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor;
postProcessor.postProcessBeanDefinitionRegistry(registry) - 最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors;
postProcessor.postProcessBeanDefinitionRegistry(registry)
- 再执行BeanFactoryPostProcessor的方法
- 获取所有的BeanFactoryPostProcessor
- 看先执行实现了PriorityOrdered优先级接口的BeanFactoryPostProcessor、
postProcessor.postProcessBeanFactory() - 在执行实现了Ordered顺序接口的BeanFactoryPostProcessor;
postProcessor.postProcessBeanFactory() - 最后执行没有实现任何优先级或者是顺序接口的BeanFactoryPostProcessor;
postProcessor.postProcessBeanFactory()
- 先执行BeanDefinitionRegistryPostProcessor
- 执行BeanFactoryPostProcessor的方法:
registerBeanPostProcessors(beanFactory):注册BeanPostProcessor(Bean的后置处理器)intercept bean creation
- 不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的:BeanPostProcessor、DestructionAwareBeanPostProcessor、InstantiationAwareBeanPostProcessor、SmartInstantiationAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor、internalPostProcessors
- 获取所有的 BeanPostProcessor:后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
- 先注册PriorityOrdered优先级接口的BeanPostProcessor;把每一个BeanPostProcessor添加到BeanFactory中
beanFactory.addBeanPostProcessor(postProcessor) - 再注册Ordered接口的
- 最后注册没有实现任何优先级接口的
- 最终注册MergedBeanDefinitionPostProcessor;
- 注册一个ApplicationListenerDetector;来在Bean创建完成后检查是否是ApplicationListener,如果是applicationContext.addApplicationListener((ApplicationListener<?>) bean)
initMessageSource():初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
获取BeanFactory
看容器中是否有id为messageSource的,类型是MessageSource的组件如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource;
- MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取;
把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource
1
2beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
MessageSource.getMessage(String code, Object[] args, String defaultMessage, Locale locale)
initApplicationEventMulticaster():初始化事件派发器
- 获取BeanFactory
- 从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster;
- 如果上一步没有配置;创建一个SimpleApplicationEventMulticaster
- 将创建的ApplicationEventMulticaster添加到BeanFactory中,以后其他组件直接自动注入
onRefresh():留给子容器(子类)
- 子类重写这个方法,在容器刷新的时候可以自定义逻辑
registerListeners():给容器中将所有项目里面的ApplicationListener注册进来
- 从容器中拿到所有的ApplicationListener
- 将每个监听器添加到事件派发器中:
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); - 派发之前步骤产生的事件;
finishBeanFactoryInitialization(beanFactory):初始化所有剩下的单实例bean;
beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean
获取容器中的所有Bean,依次进行初始化和创建对象
获取Bean的定义信息;RootBeanDefinition
Bean不是抽象的,是单实例的,是懒加载;
判断是否是FactoryBean;是否是实现FactoryBean接口的Bean;
不是工厂Bean。利用getBean(beanName);创建对象
getBean(beanName); ioc.getBean();
doGetBean(name, null, null, false);
先获取缓存中保存的单实例Bean。如果能获取到说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存起来)
- 从private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);获取的
缓存中获取不到,开始Bean的创建对象流程;
标记当前bean已经被创建
获取Bean的定义信息;
【获取当前Bean依赖的其他Bean;如果有按照getBean()把依赖的Bean先创建出来;】
启动单实例Bean的创建流程
createBean(beanName, mbd, args);
Object bean = resolveBeforeInstantiation(beanName, mbdToUse):让BeanPostProcessor先拦截返回代理对象 【InstantiationAwareBeanPostProcessor】:提前执行
- 先触发:postProcessBeforeInstantiation()
- 如果有返回值:触发postProcessAfterInitialization()
如果前面的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属性的值;为属性利用setter方法等进行赋值:applyPropertyValues(beanName, mbd, bw, pvs);
Bean初始化:initializeBean(beanName, exposedObject, mbd);
执行Aware接口方法:invokeAwareMethods(beanName, bean);执行xxxAware接口的方法
- BeanNameAware\BeanClassLoaderAware\BeanFactoryAware
执行后置处理器初始化之前:applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName) BeanPostProcessor.postProcessBeforeInitialization();
执行初始化方法invokeInitMethods(beanName, wrappedBean, mbd)
- 是否是InitializingBean接口的实现;执行接口规定的初始化
- 是否自定义初始化方法;
执行后置处理器初始化之后:applyBeanPostProcessorsAfterInitialization BeanPostProcessor.postProcessAfterInitialization();
注册Bean的销毁方法
将创建的Bean添加到缓存中singletonObjects
- ioc容器就是这些Map;很多的Map里面保存了单实例Bean,环境信息。。。。
- 所有Bean都利用getBean创建完成以后;
- 检查所有的Bean是否是SmartInitializingSingleton接口的;如果是;就执行afterSingletonsInstantiated();
finishRefresh();完成BeanFactory的初始化创建工作;IOC容器就创建完成;
- initLifecycleProcessor():初始化和生命周期有关的后置处理器;LifecycleProcessor
- 默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】:
- 如果没有new DefaultLifecycleProcessor();加入到容器;写一个LifecycleProcessor的实现类,可以在BeanFactory
- void onRefresh();
- void onClose();
- 如果没有new DefaultLifecycleProcessor();加入到容器;写一个LifecycleProcessor的实现类,可以在BeanFactory
- 默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】:
- getLifecycleProcessor().onRefresh();
拿到前面定义的生命周期处理器(BeanFactory);回调onRefresh(); - publishEvent(new ContextRefreshedEvent(this)):发布容器刷新完成事件
- liveBeansView.registerApplicationContext(this)
- initLifecycleProcessor():初始化和生命周期有关的后置处理器;LifecycleProcessor
总结
- Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息
- xml注册bean:<bean>
- 注解注册Bean:@Service、@Component、@Bean、xxx
- Spring容器会合适的时机创建这些Bean
- 用到这个bean的时候利用getBean创建bean,创建好以后保存在容器中
- 统一创建剩下所有的bean的时候:finishBeanFactoryInitialization()
- 后置处理器:BeanPostProcessor
- 每一个bean创建完成,都会使用各种后置处理器进行处理来增强bean的功能
- AutowiredAnnotationBeanPostProcessor:处理自动注入
- AnnotationAwareAspectJAutoProxyCreator:来做AOP功能
- xxx….
- 增强的功能注解:
AsyncAnnotationBeanPostProcessor….
- 每一个bean创建完成,都会使用各种后置处理器进行处理来增强bean的功能
- 事件驱动模型:
- ApplicationListener:事件监听
- ApplicationEventMulticaster:事件派发
Web
Servlet3.0
1 |
|
Shared libraries(共享库) / runtimes pluggability(运行时插件能力)
- Servlet容器启动会扫描,当前应用里面每一个jar包的
ServletContainerInitializer的实现 - 提供ServletContainerInitializer的实现类
- 必须绑定在META-INF/services/javax.servlet.ServletContainerInitializer
- 文件的内容就是ServletContainerInitializer实现类的全类名
总结:容器在启动应用的时候,会扫描当前应用每一个jar包里面
META-INF/services/javax.servlet.ServletContainerInitializer
指定的实现类,启动并运行这个实现类的方法;传入感兴趣的类型
@HandlesTypes
1 |
|
SpringMVC
依赖
1 |
|
Servlet-SpringMVC整合分析
- web容器在启动的时候,会扫描每个jar包下的META-INF/services/javax.servlet.ServletContainerInitializer
- 加载这个文件指定的类SpringServletContainerInitializer
- spring的应用一启动会加载感兴趣的WebApplicationInitializer接口的下的所有组件;
- 并且为WebApplicationInitializer组件创建对象(组件不是接口,不是抽象类)
- AbstractContextLoaderInitializer:创建根容器createRootApplicationContext()
- AbstractDispatcherServletInitializer:
- 创建一个web的ioc容器
- createServletApplicationContext():创建了DispatcherServlet
- createDispatcherServlet():将创建的DispatcherServlet添加到ServletContext中getServletMappings()
- AbstractAnnotationConfigDispatcherServletInitializer:注解方式配置的DispatcherServlet初始化器
- 创建根容器:
- createRootApplicationContext()
- getRootConfigClasses():传入一个配置类
- 创建web的ioc容器: createServletApplicationContext()
- 获取配置类:getServletConfigClasses()
- 创建根容器:
总结
- 以注解方式来启动SpringMVC:继承AbstractAnnotationConfigDispatcherServletInitializer
实现抽象方法指定DispatcherServlet的配置信息
定制SpringMVC
- @EnableWebMvc:开启SpringMVC定制配置功能:<mvc:annotation-driven/>
- 配置组件(视图解析器、视图映射、静态资源映射、拦截器。。。):extends WebMvcConfigurerAdapter
1 |
|
1 |
|
异步请求
Servlet
1 |
|
SpringMVC
1 |
|