能今天做好的事就不要等到明天。以梦为马,学习趁年华。
spring是什么
轻量级的JavaEE开源框架,是一种容器框架,用来装载Java Bean对象,是个中间层框架,江湖人称万能胶,可以和市场上的主流框架进行无缝集成,比如mybatis、redis、encache等。让企业开发方便快捷。
Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架
- 从大小与开销方面都是,spring是轻量级的。
- 通过控制反转的技术达到松耦合目的–比如A对象有B属性,正常为A主动创建并获取B对象,反转为IOC容器主动注入属性B对象,并给A的属性B赋值
- 提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑于系统级服务进行内聚性的开发
- 包含并管理应用对象(Bean)的配置和生命周期-这个意义上为一个容器
- 将简单的组件配置,组合成为复杂的应用- 这个意义上是一个框架
一、Spring的生命周期
a、整体流程图如下:
我以AbstractApplicationContext中的refresh()方法为起点进行解读,详细见如下:
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//前夕
1、设置容器的启动时间
2、设置活跃状态为true
3、设置关闭状态为false
4、获取environment队形,并加载当前系统的属性值到environment对象中
5、准备监听器和事件的集合对象,默认为空的集合
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//创建容器对象:DefaultListableBeanFactory
//加载xml配置文件的属性到当前工厂中,重要的是BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//这个是空的扩展
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//实例化并且注册所有的beanPostProcessor,注册监听器,广播
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context. 国际化用途操作
initMessageSource();
// Initialize event multicaster for this context.准备工作
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 留给子类扩展的工作
onRefresh();
// Check for listener beans and register them.
//注册监听
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//用的很多,这里是重点,过程复杂,流程多
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
b、基本流程
1、解析xml文件/注解/配置类等,生成environment对象
2、通过BeanDefinitionReader读取加载出bean定义信息,然后存放BeanDefinitionRegistry里,(BeanDefinition包含是不是单例对象 init-method销毁方法等属性)
3、创建beanFactory工厂,spring容器创建beanFactoryPostProcessor
4、调用BeanFactoryPostProcessor的postProcessBeanFactory方法(创建工厂需要做的一些前置处理)
5、beanFactory扫描BeanDefinitionRegistry拿出来所有的BeanDefinition并把实现了PropertyEditor的bean注册到属性编辑器注册表里
6、注册监听器
7、beanFactory工厂创建/注册BeanPostProcessor实例,对bean实例化前做一些加工(通过反射创建bean对象 实例之前有一些前置操作,属性赋值以及实例化之后的后置操作等等)
8、调用instantationStrategy进行对bean的实例化工作(instantiationStrategy实例化对象相当于代码中的new 所以没有属性赋值)
9、实例化之后使用beanWapper对bean进行封装,(beanWapper从BeanDefinitionRegistry获取beanDefinition,然后获取BeanDefinition中的propertyValue属性,使用属性编辑器对PropertyValue进行转换得到属性值,再通过反射机制完成bean属性赋值)
10、利用容器中注册BeanPostProcessor实例对实例化后的对象进行加工
二、Bean的生命周期
1. 结合上图基本流程如下
1、解析类得到BeanDefinition
2、实例化Bean:反射的方式生成对象
3、填充bean的属性:populateBean()
4、调用aware接口相关的方法:invokeAwareMethod(完成BeanName,BeanFactory,BeanClassLoader对象的属性赋值)
5、调用BeanPostProcessor中的初始化前的方法:使用比较多的有(ApplicationContextPostProcessor,Environment,ResourceLoader,EmbedValueReolver等)
6、调用初始化方法:invokeInitMethod(), 判断是否实现了initialingBean接口,如有则调用afterPropertiesSet()
7、调用BeanPostProcessor的初始化后的方法,这里进行AOP: spring的apo就是在此处实现,
8、如果当前创建的bean是单例的则会把bean放入单例池,通过getBean获取对象**
9、销毁流程:判断是否实现DisposableBean接口,有则destory()方法
2. 各种接口方法分类
Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
1、Bean的自身方法: 这个包括了init-method和destory-method方法
2、Bean级别生命周期接口方法:包含了BeanNameAware、BeanFactoryAware、initialzingBean和DiposableBean这些接口的方法
3、容器级生命周期接口方法:包含了InstantiationAwareBeanPostProcessor和BeanProcessor这两个接口实现,称他们的实现类为“后处理器”。
4、工厂后处理器接口方法:包含了AspectJWeavingEnabler、ConfigurationClassPostProcessor、CustomAutowreConfigure等非常有用的工厂后处理器接口的方法,会在应用上下文装配配置文件后立即调用。
3. Demo演示
示例代码A:
这是一个简单的Spring Bean,调用bean自身的方法和Bean级生命周期接口方法,实现了BeanFactoryAware、BeanNameAware、InitializingBean、DisposableBean这四个接口,同时有2个方法,对应xml配置 init-method和destory-method
package com.changtong.crm.spring.lifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
public class Person implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean {
private String name;
private String addr;
private String phone;
private BeanFactory beanFactory;
private String beanName;
public Person() {
System.out.println("~~[构造器]调用Person构造器实例化");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("~~【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()");
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String name) {
System.out.println("~~[BeanAware接口] 调用BeanAware.setBeanName()");
this.beanName = name;
}
@Override
public void destroy() throws Exception {
System.out.println("~~[diposibleBean接口]调用DiposibleBean.destory()");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("~~[initializingBean接口]调用InitializingBean.afterPropertiesSet()");
}
public void initData(){
System.out.println("~~[init-method] <bean>指定init-method属性初始化方法");
}
public void destoryData(){
System.out.println("~~[destory-method] <bean>的destory-method属性指定的方法");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("~~[注入属性] name="+name);
this.name = name;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
System.out.println("~~[注入属性] addr="+addr);
this.addr = addr;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
System.out.println("~~[注入属性] phone="+phone);
this.phone = phone;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", addr='" + addr + '\'' +
", phone=" + phone +
'}';
}
}
示例代码B:
BeanPostProcessor接口的方法,2个方法postProcessAfterInitialtiztion和postProcessBeforeInitialization,这两个方法的第一个参数都是要处理的Bean对象,第二个参数是Bean的name。返回值也都是要处理的Bean对象。具体如下:
package com.changtong.crm.spring.lifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class FangBeanPostProcessor implements BeanPostProcessor {
public FangBeanPostProcessor() {
System.out.println("~~此处FangBeanPostProcessor构造器");
}
private String name;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("~~BeanPostProcessor接口方法postProcessBeforeInitialization对bean:"+beanName+"属性进行更改"+beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("~~BeanPostProcessor接口方法postProcessAfterInitialization对bean:"+beanName+"属性进行更改"+beanName);
return bean;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "FangBeanPostProcessor{" +
"name='" + name + '\'' +
'}';
}
}
实例代码C:
InstantiationAwareBeanPostProcessor接口本质是BeanPostProcessor的子接口,一般继承Spring为其提供的适配器类InstantiationAwareBeanPostProcessor Adapter来使用,这里有三个方法,启动第二个postProcessAfterInstantiation就是重写了BeanPostProcessor的方法,第三个方法postProcessPropertyValues用来操作属性,返回值也应该是PropertyValues对象,如下:
package com.changtong.crm.spring.lifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import java.beans.PropertyDescriptor;
public class FangInstantiationAwareBeanProcessor extends InstantiationAwareBeanPostProcessorAdapter {
public FangInstantiationAwareBeanProcessor() {
System.out.println("~~这是FangInstantiationAwareBeanProcessor构造方法");
}
//接口方法实例化Bean之前调用
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("~~InstantiationAwareBeanPostProcessorAdapter调用postProcessBeforeInstantiation方法 beanClass="+beanClass+" |beanName="+beanName);
return null;
}
//接口方法实例化Bean之后调用
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("~~InstantiationAwareBeanPostProcessorAdapter调用postProcessAfterInstantiation方法 | bean="+bean+" |beanName="+beanName);
return super.postProcessAfterInstantiation(bean, beanName);
}
//接口方法、设置某个属性时候调用
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
System.out.println("~~InstantiationAwareBeanPostProcessorAdapter调用postProcessPropertyValues方法"+pvs+" | bean="+bean+" |beanName="+beanName);
return pvs;
}
}
实例代码D:
工厂后置处理接口方法,如下:
package com.changtong.crm.spring.lifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class FangBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public FangBeanFactoryPostProcessor() {
System.out.println("~~这是FangBeanFactoryPostProcessor构造方法");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("~~[BeanFactoryPostProcessor调用postProcessBeanFactory方法]");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("person");
System.out.println("~~bean定义信息beanDefinition props"+beanDefinition.getPropertyValues());
PropertyValue[] propertyValues = beanDefinition.getPropertyValues().getPropertyValues();
for (PropertyValue pv:propertyValues) {
System.out.println("~~bean定义信息beanDefinition prop key="+pv.getName()+" | value="+pv.getValue());
}
beanDefinition.getPropertyValues().addPropertyValue("phone","13800138000");
}
}
配置文件beans.xml,如下;
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="fangBeanPostProcessor" class="com.changtong.crm.spring.lifecycle.FangBeanPostProcessor" />
<bean id="fangInstantiationAwareBeanPostProcessor" class="com.changtong.crm.spring.lifecycle.FangInstantiationAwareBeanProcessor" />
<bean id="fangBeanFactoryPostProcessor" class="com.changtong.crm.spring.lifecycle.FangBeanFactoryPostProcessor" />
<bean id="person" class="com.changtong.crm.spring.lifecycle.Person"
init-method="initData" destroy-method="destoryData" scope="singleton"
p:name="张三" p:addr="南昌" p:phone='13612304561' />
</beans>
执行代码
package com.changtong.crm.spring.lifecycle;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeCycle {
public static void main(String[] args) {
System.out.println("~~初始化 IOC Container开始");
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("容器初始化成功");
Person p = ac.getBean("person",Person.class);
System.out.println(p);
System.out.println("容器开始关闭");
((ClassPathXmlApplicationContext)ac).registerShutdownHook();
}
}
结果展示:
~~初始化 IOC Container开始
17:13:26.440 [main] DEBUG org.springframework.core.env.StandardEnvironment - Adding PropertySource 'systemProperties' with lowest search precedence
17:13:26.445 [main] DEBUG org.springframework.core.env.StandardEnvironment - Adding PropertySource 'systemEnvironment' with lowest search precedence
17:13:26.445 [main] DEBUG org.springframework.core.env.StandardEnvironment - Initialized StandardEnvironment with PropertySources [MapPropertySource@2017354584 {
name='systemProperties', properties={
java.runtime.name=Java(TM) SE Runtime Environment, sun.boot.library.path=C:\Program Files\Java\jdk1.8.0_201\jre\bin, java.vm.version=25.201-b09, java.vm.vendor=Oracle Corporation, java.vendor.url=http://java.oracle.com/, path.separator=;, java.vm.name=Java HotSpot(TM) 64-Bit Server VM, file.encoding.pkg=sun.io, user.country=CN, user.script=, sun.java.launcher=SUN_STANDARD, sun.os.patch.level=, java.vm.specification.name=Java Virtual Machine Specification, user.dir=D:\hxyl\changtong-crm, java.runtime.version=1.8.0_201-b09, java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment, java.endorsed.dirs=C:\Program Files\Java\jdk1.8.0_201\jre\lib\endorsed, os.arch=amd64, java.io.tmpdir=C:\Users\Jason\AppData\Local\Temp\, line.separator=
, java.vm.specification.vendor=Oracle Corporation, user.variant=, os.name=Windows 10, sun.jnu.encoding=GBK, java.library.path=C:\Program Files\Java\jdk1.8.0_201\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Java\jdk1.8.0_201\bin;C:\Program Files\nodejs\;C:\cmder;C:\Program Files\Git\cmd;C:\Program Files\TortoiseSVN\bin;D:\software\maven\apache-maven-3.6.2\bin;C:\Program Files (x86)\ZeroTier\One\;C:\Program Files\MySQL\MySQL Shell 8.0\bin\;C:\Users\Jason\AppData\Local\Microsoft\WindowsApps;C:\Users\Jason\AppData\Roaming\npm;., java.specification.name=Java Platform API Specification, java.class.version=52.0, sun.management.compiler=HotSpot 64-Bit Tiered Compilers, os.version=10.0, user.home=C:\Users\Jason, user.timezone=Asia/Shanghai, java.awt.printerjob=sun.awt.windows.WPrinterJob, file.encoding=UTF-8, java.specification.version=1.8, java.class.path=C:\Program Files\Java\jdk1.8.0_201\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jsse.jar;C:\Program