容器的生命周期:构建(好比房子搭建好内部的结构),初始化(在基础结构进行装配),销毁
所有的bean交给spring应用容器管理,所以"工作前"需要先构建容器,并将配置的bean放入到容器中,列举一些常见的Spring容器(也叫Spring上下文)
ClassPathXmlApplicationContext,加载xml文件,然后解析生成Bean,注册Bean,通过getBean获取对象
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<context:component-scan base-package="cn.mytest.spring" />
beans>
配置了注解方式去注册Bean,测试一下IoC和DI
--需要注入的bean
@Data
@Component
public class NameBean {
private String prefix="张";
private String suffix="三";
}
--IoC
@Component
public class TestBean {
private String name;
@Autowired
NameBean nameBean;
public String test(){
this.name=nameBean.getPrefix()+nameBean.getSuffix();
return name;
}
}
--或者通过@Configuration+@Bean
@Configuration
public class ValidateBean {
@Bean
public ValidateBean get(){
return new ValidateBean();
}
}
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
TestBean testBean = (TestBean)context.getBean("testBean");
System.out.println(testBean.test()); //张三
Object validateBean = context.getBean("validateBean");
}
AnnotationConfigApplicationContext,初步实践得知,先注册类中贴有@Bean的实例,再直接根据类的简单名去注册bean,跟@Configuration无关
public class ValidateBean {
@Bean
public NameBean getName(){
System.out.println(1111);
return new NameBean();
}
}
// 用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
//容器先后注册了NameBean,ValidateBean和TestBean
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ValidateBean.class,TestBean.class);
Object testBean = applicationContext.getBean("testBean"); System.out.println(testBean);//1111 cn.mytest.spring.bean.TestBean@2d6eabae
WebApplicationContext,web.xml会构建为一个ServletContext容器,加载监听器ContextLoaderListener,用于监听web容器的生命周期,当web容器启动时就会触发初始化构建一个WebApplicationContext,ServletContext就是整个web容器获取web.xml信息的公共源
//ContextLoaderListener在创建时会默认查找WEB-INF/下的applicationContext.xml
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:application.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
SpringBoot构建的ConfigurableApplicationContext表示可配置的应用容器,ClassPathXmlApplicationContext加载xml配置的节点内容,而WebApplicationContext是依赖ServletContext提供的公共信息构建的容器,比如默认的XmlWebApplicationContext就同时实现了可配置的web容器
对于ConfigurableWebApplicationContext来说,首先是通过web.xml构建的ServletContext中实现一个WebApplicationContext应用,并在此基础上拓展应用配置(Java配置或XML配置)完善为一个可配置的web应用
public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {...}
以下图中继承体系只是其中之一
简单先理解几个容器,首先是ServletContext,就是web.xml的内存形式暂时称为web容器,每个web应用只会存在一个,而ServletConfig就是每个servlet实例init-param标签封装的实例;
对于SpringMVC WEB项目存在两种WebApplicationContext,一个 "ROOT WebApplicationContext"容器,称为Spring应用容器,可以通过ContextLoaderListener监听web容器,当web容器创建时进行初始化构建;
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:application.xmlparam-value>
context-param>
另一个就称为Servlet容器,ServletWebApplicationContext在调用DispatcherServlet 时初始化,可以理解为每个Servlet程序的容器,属于分支容器,并且在构建时将ROOT 容器设置为为parent容器,当在servlet容器无法找到对应的bean时则从parentBeanFactory中查找
<servlet>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:dispatcher.xmlparam-value>
init-param>
servlet>
总结来说对于SpringMVC而言web.xml配置实例是交由ServletContext容器管理,当有构建的servlet容器时,其servlet包含的rest,handleMapping等mvc实例则由Servlet容器管理,其他实例依然由spring容器管理
对于SpringMVC的部分后续再跟,目前先了解一下WebApplicationContext Spring应用容器
监听web并进行Spring容器初始化
--ContextLoaderListener 容器加载监听器
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
//判断servletContext容器中是否已经有初始化的Spring容器,有就报错!
if (servletContext.getAttribute
(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
}
//WebApplicationContext为空则构建一个Spring容器
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
//如果环境未激活,也就是没有执行过refresh方法
if(!cwac.isActive()) {
//配置并刷新当前上下文(容器)环境,详见-初始化Environment环境章节
this.configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
//将应用容器以键值对形式封装到servletContext中
servletContext.setAttribute(WebApplicationContext.
ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
}
determineContextClass类加载需要构建的容器类,可以在web.xml中自定义容器,默认的容器类就是XmlWebApplicationContext容器,容器实例封装bean
--ContextLoader
protected WebApplicationContext createWebApplicationContext
(ServletContext sc) {
//根据配置确定构建自定义容器还是默认的容器XmlWebApplicationContext
Class<?> contextClass = determineContextClass(sc);
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
protected Class<?> determineContextClass(ServletContext servletContext) {
//String CONTEXT_CLASS_PARAM = "contextClass";表示在标签中是否有配置的自定义的contextClass
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
else {
//defaultStrategies通过静态方法在类加载时已经添加了默认的参数
//这个默认的就是XmlWebApplicationContext
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
}
defaultStrategies默认策略是加载org.springframework.web.context包下properties参数:
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
--配置自定义的Context
contextClass
org.springframework.web.context.support.MyWebApplicationContext
加载资源文件的方式properties.load(inputStream)
--ContextLoader
private static final Properties defaultStrategies;
static {
//String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
}
通过监听器构建WebApplicationContext,以XmlWebApplicationContext为例来简单了解Spring容器的结构
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
//默认Spring容器加载的资源
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
...
//AbstractRefr..父类封装的servletContext和servletConfig实例
private ServletContext servletContext;
private ServletConfig servletConfig;
}
激活或者说初始化容器环境前,首先为ROOT容器设置唯一id,并将必要的web容器封装setServletContext;然后构建一个空的ConfigurableEnvironment环境容器,封装配置信息(xlm配置文件,properties配置,javaConfig等);
protected void configureAndRefreshWebApplicationContext(
ConfigurableWebApplicationContext wac, ServletContext sc) {
//配置应用程序id:getClass().getName() + "@" + Integer.toHexString(hashCode())
//id:org.springframework..support.XmlWebApplicationContext@710c986
//@后面是对象16位的hash值
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
//首先找web.xml中配置:param-name为contextId
String idParam = sc.getInitParameter("contextId");
if (idParam != null) {
wac.setId(idParam);
}else {
//默认id:org.springframework.web.context.WebApplicationContext
wac.setId(WebApplicationContext.class.getName() + ":" +
ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
//将ServletContext添加到应用容器
wac.setServletContext(sc);
/**
* 设置要加载的配置文件路径
*
* contextConfigLocation
* classpath:spring.xml
*
*/
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
//Environment用于选择应用程序需要运行的环境,子类ConfigurableEnvironment:提供设置激活的 profile 和默认的 profile 的功能以及操作 Properties 的功能
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
//ConfigurableWebEnvironment兼具了config和web属性的enviroment
//web属性是封装了servlet环境,config是封装PropertySource(properties)
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
//初始化Initializer类,在容器刷新之前加载的类,实现ApplicationContextInitializer完成自定义加载
customizeContext(sc, wac);
//刷新环境和容器完成容器的启动
wac.refresh();
}
Environment:即当前应用运行时所处的环境,主要为应用程序环境的两个方面的支持:profiles 和properties,Spring根据不同的环境配置加载不同的配置信息
profile组,一个profile就代表一组BeanDefinition,比如当加载解析xml配置文件的时候,只有active=true激活的BeanDefinition才会被加载进容器,可以指定哪一个Profile是生效
Properties环境变量来自于各种PropertySource属性源,如:properties/yml文件、jvm虚拟机环境变量、操作系统环境变量、JNDI、Servlet上下文参数、自定义的属性对象。比如Springboot在启动时就将properties文件初始化加载到Environment中,并且增强profile后能够在不同环境下加载不同的配置
1. 当前目录的/config子目录
2. 当前目录
3. classpath下的/config目录
4. classpath路径根目录
initPropertySources初始化PropertySources容器,PropertySource接口类似一个Map,PropertySources的实现类MutablePropertySources用链表实现存放PropertySource
刷新容器前如果有自定义提前装在到环境中则可以通过customizeContext实现,需要实现容器初始化接口applicationcontextInitializer,这个接口提供ConfigurableWebApplicationContext,通过initializer方法封装或者装载context实例属性
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext ccontext) {
//强转为子类AbstractApplicationContext
AbstractApplicationContext abContext = (AbstractApplicationContext) context;
abContext.getBeanFactory();
}
}
1.加载context-param节点中自定义配置的InitializerClasses,一般用不到
protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
/**
* globalInitializerClasses 代表所有的web application都会应用
* contextInitializerClasses 代表只有当前的web application会使用
* 配置自定义的globalInitializerClasses/contextInitializerClasses:
*
* contextInitializerClasses
* com..MyContextInitializerClasses
*
*/
List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>
initializerClasses = determineContextInitializerClasses(sc);
...
//自定的ApplicationContextInitializer再调用initialize()方法
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
initializer.initialize(wac);
}
2.加载spring.factories配置
ApplicationContextInitializer接口在springboot中频繁用到,refresh之前ConfiurableApplicationContext在springboot中启动时封装所有需要初始化的配置类,比如start相关包中META-INF/spring.factories中配置
3.mian函数中添加:application.addInitializers(new MyApplicationContextInitializer());
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MySpringBootApplication.class);
application.addInitializers(new MyApplicationContextInitializer());
application.run(args);
}
}
4.配置文件中配置:context.initializer.classes=xxx.MyApplicationContextInitializer
启动容器之后进行初始化
applicationcontextInitializer排序问题:@Order(Ordered.HIGHEST_PRECEDENCE)
无论是config容器和web容器最终初始化数据时都会通过父类AbstractApplicationContext的refresh方法实现容器初始化,而AbstractApplicationContext及子类封装了environment,beanFactory,applicationListeners等Spring核心组件
其中beanFactory容器就是Spring工作的核心,用来管理bean;ApplicationContext实现BeanFactory的一部分功能,但是ApplicationContext的实现类又封装了BeanFactory的拓展功能的实现类,我理解是ApplicationContext协助完成beanFactory的初始化封装,然后factoryBean封装beanFactory完成实例生命周期管理
应用容器构建完成后则需要容器初始化数据,比如加载xml配置,注解方式配置,java配置(@Configuration)添加到容器中
-- 构建和初始化config容器
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Object testVo = context.getBean("tempVo");
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="tempVo" class="com.pingan.mytest.vo.TempVo"/>
</beans>
refresh()方法和方法内的具体实现都在AbstractApplicationContext类
--AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
//防止并发
synchronized (this.startupShutdownMonitor) {
//预处理,初始化容器的设值
prepareRefresh();
//根据不同容器的实现解析beanDefinition并添加到beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//填充BeanFactory:添加处理器,比如spring语言处理器等等,封装几个特殊的bean等
prepareBeanFactory(beanFactory);
try {
// 容器后处理器
postProcessBeanFactory(beanFactory);
// 激活BeanFactoryPostProcessor处理器
invokeBeanFactoryPostProcessors(beanFactory);
//注册其他的BeanPostProcessor,beanFactory.addBeanPostProcessor(postProcessor)
//添加到beanFactory,并将原处理器放在链尾
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource接口用于支持信息的国际化和包含参数的信息的替换
initMessageSource();
// 初始化事件广播器ApplicationEventMulticaster
initApplicationEventMulticaster();
// 留给子类初始化其他Bean(空的模板方法)
onRefresh();
// 将listener添加到广播器中
registerListeners();
// 到这时才开始初始化非延迟加载的单例Bean
finishBeanFactoryInitialization(beanFactory);
// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知
finishRefresh();
}
catch (BeansException ex) {
// 销毁已经创建的Bean
destroyBeans();
// 重置active设值为false
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
}
}
}
初始化部分context参数,设置active标识的状态为true,封装web实例到environment中(initPropertySources是空实现,当web容器初始化时其实现是验证并将servletConfig和servletContext实例封装到web环境的propertySources中),earlyApplicationListeners和applicationListeners参数的设值
protected void prepareRefresh() {
//激活容器标识为true
this.active.set(true);
//封装servletContext和所有servletConfig到enviroment中
initPropertySources();
//验证在spring启动的时候自定义配置的环境变量必须存在,重写initPropertySources方法:比如getEnvironment().setRequiredProperties("xx")的值是否存在
getEnvironment().validateRequiredProperties();
//初始化earlyApplicationListeners,applicationListeners
...
}
earlyApplicationListeners,applicationListeners都封装在AbstractApplicationContext中,所以如果要添加这些监听器需要注入它的子类
@Autowired
AbstractApplicationContext applicationContext;
applicationContext.getBean("testController");
applicationContext.addApplicationListener(...);
BeanFactory 接口只提供了getBean()等基本功能,而子接口ConfigurableListableBeanFactory继承了ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory三个容器的功能
将context容器的初始值设置到beanFactory中,allowBeanDefinitionOverriding和allowCircularReferences,这俩个参数默认都是false
解析并装载普通Bean信息,比如xml容器将所有 Spring 配置文件中的 bean 标签解析成bean,并构建成一个个 BeanDefinition,添加到 BeanFactory 中
这里涉及的BeanFactory,其接口是用于管理Bean,而在ApplicationContext继承实现图中可以了解到,ApplicationContext实现了BeanFactory的部分功能,而ApplicationContext中实际上又封装了BeanFactory
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
//是否允许 Bean 覆盖,默认是false,不支持名称相同的bean的覆盖,可以在容器刷新之后进行设置
//applicationContext.setAllowBeanDefinitionOverriding(true);
//applicationContext.refresh(); 然后再刷新一次就生效了
private Boolean allowBeanDefinitionOverriding;
//是否允许循环引用
private Boolean allowCircularReferences;
private DefaultListableBeanFactory beanFactory;
...
}
--- DefaultListableBeanFactory
//封装的beanDefinitionMap
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
refreshBeanFactory刷新BeanFactory,BeanFactory封装到config容器中,将解析出的BeanDefinition封装到BeanFactory中
--AbstractRefreshableApplicationContext
protected final void refreshBeanFactory() throws BeansException {
//清除原BeanFactory
...
//新建一个默认的ConfigurableListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//前面有设值过:org.springframework.web.context.WebApplicationContext:
beanFactory.setSerializationId(getId());
//设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
customizeBeanFactory(beanFactory);
//解析成BeanDefinition,将bean添加到beanDefinitionMap中
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
封装一些特殊的bean和处理器等,就是应用初始化的数据,目前从这里并无法判定每个处理器的作用,所以这里主要作用是封装后续所需的对象/处理器
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 添加classLoader类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 添加beanFactory的表达式语言处理器,默认可以使用#{xxx.xxx}的形式来调用相关属性值
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 添加默认的PropertyEditors属性编辑器,实现PropertyEditorSupport接口可以自定义属性编辑器
//Set propertyEditorRegistrars
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
//添加一个bean后置处理器BeanPostProcessor
//封装在List beanPostProcessors
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//添加忽略bean 依赖于以下几个接口的实现类,Spring 会通过其他方式来加载这些依赖
//实现了ApplicationContextAware通过setter注入
//Set> ignoredDependencyInterfaces
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
...
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 添加几个自动装配的特殊Bean,比如BeanFactory和ApplicationContext
//Map, Object> resolvableDependencies
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
...
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
//添加的这个处理器作用就是将实现了接口ApplicationListener的bean添加到beanFactory
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
//如果存在bean名称为loadTimeWeaver的bean则注册一个BeanPostProcessor,aspctj功能
//类加载期织入切面,在xml配置
//解析context的namespace会解析这个LTW
if (beanFactory.containsBean("loadTimeWeaver")) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
//ClassLoader tempClassLoader
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册默认的系统环境bean,environment,systemProperties,systemEnvironment
if (!beanFactory.containsLocalBean("environment")) {
//就是封装到BeanFactory中多个集合中:singletonObjects,registeredSingletons等
beanFactory.registerSingleton("environment", getEnvironment());
}
...
}
beanFactory添加一些后置处理器,注册web应用的scopes,注册web应用的servletContext和servletConfig实例
--AbstractRefreshableWebApplicationContext
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//将ServletContext传递给实现ServletContextAware接口的bean
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
//忽略实现了以下2个接口的实现类的注册,添加到ignoredDependencyInterfaces
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
//注册 WEB 应用特定的域(scope),比如: request session response application等.
//AbstractBeanFactory-registerScope:封装到Map scopes
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
//注册 WEB 应用特定的 Environment bean,比如contextAttributes等
//registerSingleton servletContext和servletConfig实例
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
注册 WEB 应用特定的域(scope),Scope注解分为ConfigurableBeanFactory和WebApplicationContext两个大类,ConfigurableBeanFactory包含singleton、prototype两种Scope,WebApplicationContext包含request、session、application、servletContext等基于prototype的Scope;scope用于管理bean的作用域,singleton表示应用中只存在一个共享的bean实例,prototype域时每次请求都会创建新的实例,request域则在prototype基础上针对HTTP请求时会产生一个新的bean且仅在当前HTTP请求域中有效(ThreadLocal)
public static void registerWebApplicationScopes
(ConfigurableListableBeanFactory beanFactory, ServletContext sc) {
//将scope添加到beanFactory中Map scopes
beanFactory.registerScope("request", new RequestScope());
//RequestScope和SessionScope都是空实现
beanFactory.registerScope("session", new SessionScope());
//ServletContextScope封装了ServletContext
ServletContextScope appScope = new ServletContextScope(sc);
beanFactory.registerScope("application", appScope);
//将ApplicationScope作为ServletContext的属性进行注册
sc.setAttribute(ServletContextScope.class.getName(), appScope);
//注册域的bean,封装到resolvableDependencies映射中
beanFactory.registerResolvableDependency(ServletRequest.class, new WebApplicationContextUtils.RequestObjectFactory());
...
}
如果在refresh前初始化Initializer时自定义添加了Bean工厂后置处理器beanFactoryPostProcessors,则会在这个方法中进行初始化 ;BeanFactoryPostProcessor作用是对Spring初始化过程中的通过参数BeanFactory实例进行功能的拓展,比如增强beanFactory的功能或者打印beanFactory的内容
//实现BeanFactoryPostProcessor接口,通过beanFactory完成一些拓展功能
public class MyBeanFactoryProceesor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
}
}
//自定义ApplicationContextInitializer中添加处理器
public class MyTestInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext context) {
//将自定义的实现BeanFactoryPostProcessor接口的处理器添加到context中
context.addBeanFactoryPostProcessor(new MyBeanFactoryProceesor());
}
}
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//getBeanFactoryPostProcessors获取的是Application的beanFactoryPostProcessors
//在customizeContext方法实现自定义添加BeanFactoryPostProcessor
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
...
}
Bean的后置处理器,其作用或者说触发条件是在构建bean之后,并且在init()之前和之后对所有的bean进行增强,BeanPostProcessor接口主要是对bean实例init前后处理
以观察者模式理解,BeanPostProcessor是观察者,而bean是被观察者,触发条件则是在创建实例bean时
public interface BeanPostProcessor {
//在init方法之前执行,监听bean
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
//在init方法之后执行
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
执行完BeanFactoryPostProcessors后会注册所有的BeanPostProcessor到beanFactory中beanPostProcessors.
//这个方法的主要作用就是找到所有BeanPostProcessor注册bean并缓存到beanPostProcessors
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
然后在创建实例时获取相应的BeanPostProcessor,调用(执行)处理器的回调方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
//bean预处理增强
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
//init增强,@PostConstruct>InitializingBean>init()
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
}
protected Object initializeBean(..) {
//从容器this.getBeanPostProcessors()找到所有符合的处理器并执行回调
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean..);
this.invokeInitMethods(beanName, wrappedBean, mbd);
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(..);
}
BeanPostProcessor默认是对所有bean进行增强,所以使用aware接口实现个性化定制,对不同的bean做不同的增强,判断bean是否是xxxAware接口的实现,从而实现bean增强;以ApplicationContextAwareProcessor为例,对实现ApplicationContextAware的bean注入一个applicationContext
---ApplicationContextAwareProcessor
//对实现了ApplicationContextAware接口的bean填充一个ApplicationContext
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
//实现ApplicationContextAware可以获取到applicationContext
//一般用于不方便直接去注入applicationContext时用
@Component
public class SpringBootApolloRefreshConfig implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.applicationContext = context;
}
}
将实现ApplicationListener的bean添加到beanFactory的applicationListeners中,实现了两个接口,
class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {}
DestructionAwareBeanPostProcessor在BeanPostProcessor基础上拓展了可以处理bean销毁前的工作,
//在bean卸载之前时会调用postProcessBeforeDestruction方法
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
void postProcessBeforeDestruction(Object var1, String var2) throws BeansException;
//bean在销毁前会判断scope!=prototype && 必须是销毁的bean,默认返回true
default boolean requiresDestruction(Object bean) {
return true;
}
}
--- ApplicationListenerDetector.class 的实现 ---------------
//这个处理器只会处理ApplicationListener的实现bean
public void postProcessBeforeDestruction(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
//当bean即将被销毁时从容器的multicaster中移除监听bean的监听器
ApplicationEventMulticaster multicaster = this.applicationContext.getApplicationEventMulticaster();
multicaster.removeApplicationListener((ApplicationListener)bean);
multicaster.removeApplicationListenerBean(beanName);
}
}
//ApplicationListener的实现bean必须销毁
public boolean requiresDestruction(Object bean) {
return bean instanceof ApplicationListener;
}
ApplicationListenerDetector还实现了MergedBeanDefinitionPostProcessor接口
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {
//RootBeanDefinition原始bean解析之后的封装
void postProcessMergedBeanDefinition(RootBeanDefinition var1, Class<?> var2, String var3);
}
//ApplicationListenerDetector中
private final transient Map<String, Boolean> singletonNames = new ConcurrentHashMap(256);
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//isAssignableFrom()方法是判断是否为某个类的父类,instanceof关键字是判断是否某个类的子类
if (ApplicationListener.class.isAssignableFrom(beanType)) {
//scope=singleton,表示如果这个ApplicationListener是单例则会在初始化后添加到beanFactory
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
}
//在init方法之后addApplicationListener
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
Boolean flag = (Boolean)this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
this.applicationContext.addApplicationListener((ApplicationListener)bean);
} else if (Boolean.FALSE.equals(flag)) {
this.singletonNames.remove(beanName);
}
}
return bean;
}
spring事件监听由事件发布器,事件和监听器组成,类似Initializer,后置处理器这些都使用了观察者模式;首先是确立被观察对象,监听事件中event就是被观察的对象,Initializer中的被观察者是Context,而beanFactory是BeanFactoryPostProcessor处理器的观察对象;然后确立观察者,依次是listener,ApplicationContextInitializer和BeanFactoryPostProcessor,这些观察者都会提供一个用于发布的方法
初始化一个发布器
applicationEventMulticaster事件多路广播器,用于事件发布,具体实现AbstractApplicationEventMulticaster还实现了BeanClassLoaderAware, BeanFactoryAware 接口,从经验上就知道广播器封装了beanClassLoader和beanFactory
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
//判断是否已存在注册的applicationEventMulticaster
if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
} else {
//默认创建SimpleApplicationEventMulticaster并注册其实例
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
}
}
---AbstractApplicationEventMulticaster
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
// 监听器回收器(注册器)封装ApplicationListener 的所有实现bean
private final AbstractApplicationEventMulticaster.ListenerRetriever defaultRetriever = new AbstractApplicationEventMulticaster.ListenerRetriever(false);
...
//类加载和beanFactory
private ClassLoader beanClassLoader;
private ConfigurableBeanFactory beanFactory;
// 单例对象的缓存: Map singletonObjects
private Object retrievalMutex;
}
SimpleApplicationEventMulticaster 封装了线程池,在refresh方法中最终会通过finishRefresh方法调用实现广播事件multicastEvent方法时会激活监听器发布事件
public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
...
Executor executor = this.getTaskExecutor();
//获取bean容器注册的listeners
Iterator var5 = this.getApplicationListeners(event, type).iterator();
while(var5.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> {
//线程执行激活listener
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
//监听器在事件发布的时候才会创建Bean,也就是在事件发布的时候才能执行监听器的onApplicationEvent方法
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
// 监听器发布事件
listener.onApplicationEvent(event);
...
}
ApplicationListenerDetector将ApplicationListener添加到beanFactory,而registerListeners则将监听器添加到广播器中等待发布
protected void registerListeners() {
Iterator var1 = this.getApplicationListeners().iterator();
//添加到广播器的内部类ListenerRetriever中集合中
while(var1.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var1.next();
this.getApplicationEventMulticaster().addApplicationListener(listener);
}
//getBeanNamesForType获取接口的所有实现bean
String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
String[] var7 = listenerBeanNames;
int var3 = listenerBeanNames.length;
for(int var4 = 0; var4 < var3; ++var4) {
String listenerBeanName = var7[var4];
//将实现beanName添加到ListenerRetriever
this.getApplicationEventMulticaster()
.addApplicationListenerBean(listenerBeanName);
}
//发布这个earlyEventsToProcess
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
Iterator var9 = earlyEventsToProcess.iterator();
while(var9.hasNext()) {
ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();
//multicastEvent发布事件的方法
this.getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
当bean的初始化完成之后,这一步主要是负责启动app和发布ApplicationEvent事件
protected void finishRefresh() {
//resourceCaches清除资源缓存
this.clearResourceCaches();
//初始化生命周期处理器负责管理ApplicationContext生命周期,默认使用DefaultLifecycleProcessor
this.initLifecycleProcessor();
//onRefresh启动容器生命周期,stop结束生命周期
this.getLifecycleProcessor().onRefresh();
//publishEvent推送事件到相应监听器,这一步会完成ApplicationEvent事件的发布
this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
...
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
...
//获取广播器发布事件
this.getApplicationEventMulticaster()
.multicastEvent((ApplicationEvent)applicationEvent, eventType);
}
public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
//可以实现通过线程池执行任务
Executor executor = this.getTaskExecutor();
//获取广播器内所有的ApplicationListener
Iterator var5 = this.getApplicationListeners(event, type).iterator();
while(var5.hasNext()) {
//调用listener.onApplicationEvent(event),没有线程池则直接调用
ApplicationListener<?> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
监听发布事件机制本质上就是一种设计模式,观察者模式,所谓的监听其实当监听器通过发布器发布之后就获取到event实例,根据event封装的信息去处理事情;类比推荐算法,获取到你的行为和数据之后进行分析,将分析的标签贴在你身上并根据这些标签向你推送内容
捋一下ApplicationEvent事件的顺序,首先加载所有的后置处理器,包括了ApplicationListenerDetector,然后initApplicationEventMulticaster初始化一个广播器,finishBeanFactoryInitialization开始进行非延迟加载的bean的初始化,在init之后通过ApplicationListenerDetector处理器将所有ApplicationListener添加到beanFactory,最后finishRefresh方法将ApplicationListener添加到EventMulticaster等待完成监听发布,因为监听器的类别是ApplicationListener只监听ApplicationEvent事件,所以在容器的生命周期内才会发布ApplicationEvent事件
//限定了这个监听器只会监听ApplicationEvent事件
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
自定义一个事件,如果ApplicationListener不加泛型会默认监听ApplicationEvent和其所有子类事件,而容器启动的时候,执行finishRefresh方法发布ContextRefreshedEvent事件
//自定义一个ApplicationEvent事件
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
自定义发布事件
--- spring方式
//发布自定的事件
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
context.publishEvent(new MyEvent("11111")); //myListener:com.pingan.mytest.listener.MyEvent[source=11111]
//如果只想监听自定义的事件则补充好泛型
//@Component标记
@Component
public class MyListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent myEvent) {
System.out.println("myListener:"+myEvent.toString());
}
}
--- springboot方式
@SpringBootApplication
public class SingleManApp {
//通过添加自定义的addApplicationListener和发布自定义事件
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SingleManApp.class);
//如果MyListener被@Component标记则不需要再添加这个
run.addApplicationListener(new MyListener());
run.publishEvent(new MyEvent("1111"));
}
}
@SpringBootApplication
public class SingleManApp {
//SpringApplication不能发布事件,但是可以添加监听器
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(SingleManApp.class);
//这里是添加到SpringApplication容器的监听器
//可以只需要对自定义的监听器加@Component标记即可
springApplication.addListeners(new MyListener());
springApplication.run(args);
}
}
装载BeanDefinitions,在obtainFreshBeanFactory方法中完成解析Spring配置,将定义的bean解析为一个个BeanDefinition并装载在BeanFactory中
//定义了BeanName->BeanDefinition的映射关系
Map<String, BeanDefinition> beanDefinitionMap;
//根据注册顺序,存储所有的beanDefinitionName,即beanName
List<String> beanDefinitionNames;
loadBeanDefinitions有多个实现,这里以默认的XmlWebApplicationContext为例
通过解析器解析xml配置文件加载和注册bean,简单来说就是将Xml的配置全部解析出来封装成一个BeanDefinition交由BeanFactory管理
--XmlWebApplicationContext
// root context的默认配置位置
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
// 默认配置相对路径的前缀
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
// 默认配置位置的后缀
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
//通过XmlBeanDefinitionReader加载bean
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//空实现,留给XmlWebApplicationContext子类进行自定义初始化
initBeanDefinitionReader(beanDefinitionReader);
//使用给定的reader加载bean定义
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
//就是context-param配置的contextConfigLocation,没有则返回context的默认配置
//classpath*:appcontext-*.xml
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
//遍历xml配置文件进行加载解析DOM,最终注册到beanDefinitionMap
reader.loadBeanDefinitions(configLocation);
}
}
}
进入loadBeanDefinitions,首先要构建解析xml的解析器环境,将xml文件转为Resource并封装在InputSource中
--AbstractBeanDefinitionReader
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//解析bean配置文件加载器
ResourceLoader resourceLoader = getResourceLoader();
//XmlWebApplicationContext实现了ResourcePatternResolver接口
//也就是以xml配置bean进行加载的,非xml配置就不会实现这个接口
if (resourceLoader instanceof ResourcePatternResolver) {
try {
//将配置文件的内容转化为Resource对象
//判断是否是classpath*:开头的通配符
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//获取Resource对象流进行解析,转化为bean进行封装
int loadCount = loadBeanDefinitions(resources);
...
}
//EncodedResource对Resource封装了字符集编码
public int loadBeanDefinitions(Resource resource) {
//这里其实仅仅将resource封装了一层
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
//使用ThreadLocal防止资源文件循环加载
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
//确认没有加载过当前的Resource
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
try {
//获取Resource的流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//InputSource可以简单理解为解析输入资源的所需条件的总装
InputSource inputSource = new InputSource(inputStream);
//这里encoding为null
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//解析成DOM对象,进行Bean的加载和注册
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
...
}
}
bean的加载和注册
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {
//解析xml封装为Document对象
Document doc = doLoadDocument(inputSource, resource);
//根据Document对象注册Bean
return registerBeanDefinitions(doc, resource);
...
}
BeanDefinition就是Bean的定义信息,封装了每个bean的信息,对于spring框架来说操作bean就是操作BeanDefinition;BeanFactory封装了所有注册的BeanDefinition(beanDefinitionMap)
refresh()–>obtainFreshBeanFactory()–>registerBeanDefinitions(),经过一系列的解析之后,最终将dom解析成BeanDefinition并封装到BeanFactory(DefaultListableBeanFactory)中
Schema是对XML文档结构的定义和描述,其主要的作用是用来约束XML文件,并验证XML文件有效性。DTD的作用是定义XML的合法构建模块,它使用一系列的合法元素来定义文档结构,示例:
//beans 整个配置文件的根节点, 包含一个或多个bean元素
//属性:location:配置文件路径,system-properties-mode 写上NEVER, 不使用环境变量中的配置参数
<context:property-placeholder location="classpath:jdbc.properties" system-properties-mode="NEVER" />
<context:annotation-config/>
<context:component-scan base-package=""/>
<aop:aspectj-autoproxy/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driverClassName}"/>
bean>
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:mybatis.cfg.xml" />
<property name="mapperLocations" value="classpath:xx/mapper/*Mapper.xml" />
<property name="typeAliasesPackage" value="xx.domain" />
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="xx.mapper" />
bean>
<bean id="目标对象名称" class="目标对象类全名"/>
<bean id="transaction" class="com.pingan.test.springtest.aop.TransactionDemo"/>
<aop:config>
<aop:aspect ref="transaction">
<aop:pointcut id="crudPointcut" expression="execution(..)" />
<aop:after method="writeLog" pointcut-ref="crudPointcut" />
aop:aspect>
aop:config>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
<tx:advice id="tx" transaction-manager="事务管理器实例名称">
<tx:attributes>
<tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/>
<tx:method name="select*" read-only="true" propagation="NOT_SUPPORTED"/>
<tx:method name="query*" read-only="true" propagation="NOT_SUPPORTED"/>
<tx:method name="*"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:aspect ref="transaction">
<aop:pointcut id="pc" expression="事务切入点正则表达式" />
<aop:advisor advice-ref="tx" pointcut-ref="pc"/>
aop:aspect>
aop:config>
beans>
registerBeanDefinitions返回注册的Bean数量
---XmlBeanDefinitionReader
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//构建读取Document的工具类
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//BeanFactory实现BeanDefinitionRegistry接口
//获取this.beanDefinitionMap.size()+
int countBefore = getRegistry().getBeanDefinitionCount();
//注册本次需要加载的Bean,createReaderContext构建一个XmlReaderContext
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回本次注册的bean:总注册的bean减去之前注册的bean
return getRegistry().getBeanDefinitionCount() - countBefore;
}
---DefaultBeanDefinitionDocumentReader
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
this.doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
//BeanDefinitionParserDelegate通过类名可知为解析代理
//封装了bean相关的Xml属性
BeanDefinitionParserDelegate parent = this.delegate;
//创建bean解析代理
this.delegate = createDelegate(getReaderContext(), root, parent);
//是否匹配:"http://www.springframework.org/schema/beans"
if (this.delegate.isDefaultNamespace(root)) {
//profile:根节点属性,是否匹配当前环境,不匹配则不解析当前xml文件
//
String profileSpec = root.getAttribute("profile");
...
}
//解析root节点之前的操作,空实现,留给子类实现
preProcessXml(root);
//解析dom的root节点判断命名空间是否为默认的
//默认命名http://www.springframework.org/schema/beans
parseBeanDefinitions(root, this.delegate);
//解析root节点之后的操作,空实现
postProcessXml(root);
//通过这个方式还原初始化的BeanDefinitionParserDelegate
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//有默认的namespace
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 解析 default namespace 下面的几个四个元素
//、、 和
parseDefaultElement(ele, delegate);
}
else {
// 解析其他 namespace 的元素
//例如:、
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 解析自定义 namespace 的元素
delegate.parseCustomElement(root);
}
}
构建一个解析容器XmlReaderContext,XmlReaderContext继承的ReaderContext封装了透传的Resource和eventListener,而其封装了XmlBeanDefinitionReader(当前bean解析器)和NamespaceHandlerResolver(也是当前解析器封装的透传给容器的)
---XmlBeanDefinitionReader
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, this.getNamespaceHandlerResolver());
}
public class XmlReaderContext extends ReaderContext {
private final XmlBeanDefinitionReader reader;
private final NamespaceHandlerResolver namespaceHandlerResolver;
//problemReporter,eventListener和sourceExtractor都是透传的空实现
//resource是加载xml的资源,reader是透传自己
public XmlReaderContext(Resource resource, ProblemReporter problemReporter, ReaderEventListener eventListener, SourceExtractor sourceExtractor, XmlBeanDefinitionReader reader, NamespaceHandlerResolver namespaceHandlerResolver) {
super(resource, problemReporter, eventListener, sourceExtractor);
this.reader = reader;
//默认的 handlerMappingsLocation = "META-INF/spring.handlers";
//作用就是获取xsd对应的处理器
this.namespaceHandlerResolver = namespaceHandlerResolver;
}
}
namespaceHandlerResolver: 默认值为META-INF/spring.handlers获取该配置项所有的handler类,实现了NamespaceHandler并封装在handlerMappings中;当然也可以自定义一些handler并配置在默认的目录下,这些handler实现parse和decorate方法
初始化解析代理,delegate封装了readerContext,DocumentDefaultsDefinition等
---DefaultBeanDefinitionDocumentReader
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {
//BeanDefinitionParserDelegate设值readerContext
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
//初始化delegate
delegate.initDefaults(root, parentDelegate);
return delegate;
}
public void initDefaults(Element root, @Nullable BeanDefinitionParserDelegate parent) {
//defaults:DocumentDefaultsDefinition
this.populateDefaults(this.defaults, parent != null ? parent.defaults : null, root);
//可自定义实现EventListener(这里ReaderEventListener是个空实现)
this.readerContext.fireDefaultsRegistered(this.defaults);
}
populateDefaults会处理beans标签的属性(默认解析的方法),解析的属性值都被封装在defaults,也就是DocumentDefaultsDefinition中
//bean标签一般也会指定lazy-init/init-method等方法,也可以在beans指定默认方法
<beans ...
default-lazy-init="true" default-init-method="">
解析默认namespace,默认的命名空间beans只包含了import、alias、bean 和 beans四个标签,其中beans又是一个嵌套的dom继续递归调doRegisterBeanDefinitions
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// import标签:解耦式的导入,将其他xml配置文件引入解析
//比如
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// alias标签:
//作用就是增加test1,test2作为bean名称指向bean
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//解析bean标签,并注册beanDefinition
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//beans标签:递归方法解析
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
doRegisterBeanDefinitions(ele);
}
}
processBeanDefinition核心在于解析bean标签并注册beanDefinition到factory
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析之后BeanDefinition,beanName以及aliases封装到BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//当对默认namespace的xsd增加了自定义子标签时去通过handler解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
//执行注册,将BeanDefinition信息添加到beanFactory中
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
//自定义实现ReaderEventListener的componentRegistered方法
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
将beanDefinition、beanName、bean别名数组封装成BeanDefinitionHolder
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//解析bean的属性,id,name和配置的别名都可以作为bean的key值
String id = ele.getAttribute(ID_ATTRIBUTE);
// 获取name属性,缓存至别名List
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// 如果bean的id为空,但是别名不为空的话,那么默认采用第一个别名作为beanName
// 例如:
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
//使用myDog1作为beanName,并移除别名集合
beanName = aliases.remove(0);
}
//检查beanName和别名是否被使用
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//重载方法,解析bean标签,将属性及子节点信息封装
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
....
}
解析bean及子节点标签封装到BeanDefinition
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
//this.beanDefinitionName = beanName
this.parseState.push(new BeanEntry(beanName));
//解析class属性,类全限定名
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
//解析parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//创建AbstractBeanDefinition对象,将标签的信息进行封装
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析bean标签属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//解析bean标签下的子节点并封装到bd中
//包括,注入之类标签等等
bd.set....
}
parseBeanDefinitionAttributes解析bean属性封装到BeanDefinition
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,BeanDefinition containingBean,AbstractBeanDefinition bd) {
// 1.设置bean作用域scope属性,不能设置为单例
// 未明确指定bean的作用域,且当前被解析bean是内部bean的话,
// 则默认使用outer bean的的作用域作为当前bean的作用域
// 例如:下面的配置,解析到inner属性时,inner未指定作用域,则使用outer的作用域,也就是prototype
/**
**/
bd.setScope(containingBean.getScope());
//2.设置abstract属性:abstract=true
// 3.设置lazy-init(延迟加载)属性;
// 如果该属性为true的话,ApplicationContext容器在初始化时不会加载该bean;
// 而是在第一次向容器索取该bean时才会被初始化
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
//4.设置autowire属性,自动注入,有byName和byType方式,默认不开启
//byName,按照setXxx方法的Xxx名称去注入bean
//byType,按照set方法的入参属性类去注入bean
bd.setAutowireMode(getAutowireMode(autowire));
//5.设置depends-on属性,如果BeanA依赖于BeanB,可通过depends-on属性使BeanB在BeanA之前完初始化
//6.设置autowire-candidate属性,默认为true
//当设置为false时,不让其他类通过autowire注入当前bean
// 7、设置primary属性,当byType注入有多个类型时,
// 可以指定primary="true",提高注入的优先级,避免抛出异常
// 8、设置init-method,bean初始化完成后回调该方法
// 9、设置destroy-method属性,bean销毁后回调该方法
// 10、设置factory-method属性,该属性可指定静态工厂或实例工厂方法实例化bean
// 11、设置factory-bean属性,一般和factory-method属性一起使用,
// 指定工厂bean和工厂bean的工厂方法
}
BeanDefinitionReaderUtils.registerBeanDefinition去执行注册
---BeanDefinitionReaderUtils
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
//注册beanName与beanDefinition的映射
String beanName = definitionHolder.getBeanName();
//由registry的子类DefaultListableBeanFactory实现
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
//由SimpleAliasRegistry实现,是当前BeanFactory的父类
//主要作用是将去重(不能和beanName相同)的别名和beanName形成映射
//aliasMap:key为别名,value为beanName
registry.registerAlias(beanName, alias);
}
}
}
注册bean,将beanName和BeanDefinition形成映射,将beanName添加到各个相应的集合中
---DefaultListableBeanFactory
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
if (beanDefinition instanceof AbstractBeanDefinition) {
//验证不能有静态工厂方法(factory-method的配置)
((AbstractBeanDefinition) beanDefinition).validate();
}
//优先从缓存中加载BeanDefinition,覆盖原先的bean
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
//添加到beanfactory的beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
}else {
// 如果beanDefinition已经被标记为创建(为了解决单例bean的循环依赖问题)
//alreadyCreated为空
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
//更新updatedDefinitions的容量,并添加重新添加所有beanName
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
// 将updatedDefinitions赋值给beanDefinitionNames
this.beanDefinitionNames = updatedDefinitions;
// 手动单例集合manualSingletonNames,bean已存在则移除
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}else {
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
// manualSingletonNames缓存的是手动注册的单例bean
// 例如:xmlBeanFactory.registerSingleton("myDog", new Dog());
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
// 如果当前注册的bean的定义已经在beanDefinitionMap缓存中存在,
// 或者实例已经存在于单例bean的缓存中,将该beanName对应的缓存信息、单例对象清除
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
解析其他namespace
xmlns 属性可以在文档中定义一个或多个可供选择的命名空间,使用时在子标签内添加他的前缀作为标识: 比如context,aop等
<context:component-scan base-package="cn.mytest.spring" />
delegate.parseCustomElement解析非默认标签和自定义namespace
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
// node.getNamespaceURI拿到节点的命名空间,例如常见的:
// 节点对应命名空间: http://www.springframework.org/schema/aop
String namespaceUri = getNamespaceURI(ele);
// 命名空间对应的的handler, 例如:contex 对应 ContextNameSpaceHandler
//namespaceHandlerResolver解析namespaceUri, 拿到NamespaceHandler
NamespaceHandler handler = this.readerContext
.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
return null;
}
// handler解析节点(ParserContext用于存放解析需要的一些上下文信息)
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
readerContext.getNamespaceHandlerResolver()获取了默认的命名空间处理器DefaultNamespaceHandlerResolver,其封装了所有包下的handler
每个包下MATA-INF/spring.handlers文件记录对应的hanlder,因此使用指定的 classLoader 从所有类路径资源(META-INF/spring.handlers)加载所有属性,并使用 Properties 来存放 spring.handlers 文件中的内容(命名空间和 handler 的键值对)
--MATA-INF/spring.handler
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler"
//使用给定的类加载器从指定的类路径资源加载所有属性
Properties mappings = PropertiesLoaderUtils
.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
//将Properties转换成Map, mappings -> handlerMappings
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
每个命名空间处理都会封装不同标签的bean解析器,例如ContextNamespaceHandler中封装了诸如property-placeholder,annotation-config等标签解析器
<!-- 加载db.properties文件,属性占位 -->
<context:property-placeholder location="classpath:db.properties"
system-properties-mode="NEVER" />
<!-- DI的解析器 -->
<context:annotation-config />
<!-- IoC的解析器 -->
<context:component-scan base-package="cn.xxx" />
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
先获取每个标签对应的BeanDefinitionParser解析器,再根据不同的解析器去实现parse方法,对于各个标签的解析功能暂不深入,主要是太多了,也可以自定义namespace和标签
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
//拿到节点的localName,例如:
String localName = parserContext.getDelegate().getLocalName(element);
//从parsers缓存中,拿到localName对应的解析器, 例如: component-scan -> ComponentScanBeanDefinitionParser
BeanDefinitionParser parser = this.parsers.get(localName);
return parser;
}
--parser.parse(element, parserContext);