Spring源码
流程图
一些基础类/接口 BeanFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Bean 工厂实现应尽可能支持标准的 Bean 生命周期接口。完整的初始化方法集及其标准顺序为: · BeanNameAware's setBeanName · BeanClassLoaderAware's setBeanClassLoader · BeanFactoryAware's setBeanFactory · EnvironmentAware's setEnvironment · EmbeddedValueResolverAware's setEmbeddedValueResolver · ResourceLoaderAware's setResourceLoader (only applicable when running in an application context) · ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context) · MessageSourceAware's setMessageSource (only applicable when running in an application context) · ApplicationContextAware's setApplicationContext (only applicable when running in an application context) · ServletContextAware's setServletContext (only applicable when running in a web application context) · postProcessBeforeInitialization methods of BeanPostProcessors · InitializingBean's afterPropertiesSet · a custom init-method definition · postProcessAfterInitialization methods of BeanPostProcessors
测试获取FactoryBean对象
1 2 3 4 5 6 7 8 <bean class ="cn.devnook.c1_entry.bean.User" name ="user" init-method ="initUser" factory-bean ="userFactoryBean" > <property name ="name" value ="Nook.Young" /> <property name ="sex" value ="女" /> <property name ="age" value ="18" /> </bean > <bean class ="cn.devnook.c1_entry.bean.UserFactoryBean" name ="userFactoryBean" > <property name ="createBy" value ="Factory" /> </bean >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class UserFactoryBean implements FactoryBean <User> { String createBy; public void setCreateBy (String createBy) { this .createBy = createBy; } @Override public User getObject () { User user = new User (); user.setCreateBy(createBy); return user; } @Override public Class<User> getObjectType () { return User.class; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 public class C1_EntryTest { public static void main (String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext ("applicationContext.xml" ); User user = ac.getBean("user" , User.class); System.out.println(user); UserFactoryBean userFactoryBean = ac.getBean("&userFactoryBean" , UserFactoryBean.class); System.out.println(userFactoryBean); User userFromFactory = userFactoryBean.getObject(); System.out.println(userFromFactory.getCreateBy()); } }
BeanDefinition
BeanDefinitionReader
BeanFactoryPostProcessor
BeanPostProcessor
Environment
Aware
自定义扩展 1.校验启动参数 必须环境变量/启动参数 中必须有某个变量 1 2 3 4 # 确定环境变量 echo $USER zy
假如必须校验环境变量中有USER
变量:
自定义:MyClassPathXmlApplicationContext
继承自ClassPathXmlApplicationContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext { public MyClassPathXmlApplicationContext (String... configLocations) { super (configLocations); } @Override protected void initPropertySources () { System.out.println("自定义操作:>>>initPropertySources" ); getEnvironment().setRequiredProperties("USER" ); super .initPropertySources(); } }
单元测试:
1 2 3 4 5 6 7 public class C2_MyClassPathXmlApplicationContextTest { public static void main (String[] args) { ApplicationContext ac = new MyClassPathXmlApplicationContext ("spring-${USER}.xml" ); User user = ac.getBean("user" , User.class); System.out.println(user); } }
2.扩展实现customizeBeanFactory
设置是否允许bbd重写以及循环依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext { public MyClassPathXmlApplicationContext (String... configLocations) { super (configLocations); } @Override protected void customizeBeanFactory (DefaultListableBeanFactory beanFactory) { super .setAllowBeanDefinitionOverriding(false ); super .setAllowCircularReferences(false ); super .customizeBeanFactory(beanFactory); } }
3.配置自定义标签并让spring解析
主要步骤:
自定义对象,用于接受xml配置
自定义BeanDefinitionParser继承自AbstractSingleBeanDefinitionParser,重写getBeanClass(Element) 和 doParse(Element element, BeanDefinitionBuilder builder)
自定义NamespaceHandler 继承自 NamespaceHandlerSupport,重写init()
自定义spring.handlers配置
自定义spring.schemas
自定义xsd文件
自定义对象:DevNook
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 package cn.devnook.c1_entry.selftag;public class DevNook { private String username; private String email; public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getEmail () { return email; } public void setEmail (String email) { this .email = email; } @Override public String toString () { return "DevNook{" + "username='" + username + '\'' + ", email='" + email + '\'' + '}' ; } }
自定义parser
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 package cn.devnook.c1_entry.selftag;import org.springframework.beans.factory.support.BeanDefinitionBuilder;import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;import org.springframework.util.StringUtils;import org.w3c.dom.Element;public class DevNookBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { @Override protected Class<?> getBeanClass(Element element) { return DevNook.class; } @Override protected void doParse (Element element, BeanDefinitionBuilder builder) { String username = element.getAttribute("username" ); String email = element.getAttribute("email" ); if (StringUtils.hasText(username)){ builder.addPropertyValue("username" , username); } if (StringUtils.hasText(email)){ builder.addPropertyValue("email" , email); } } }
自定义handler
1 2 3 4 5 6 7 8 9 10 package cn.devnook.c1_entry.selftag;import org.springframework.beans.factory.xml.NamespaceHandlerSupport;public class DevNookNamespaceHandler extends NamespaceHandlerSupport { @Override public void init () { registerBeanDefinitionParser("user" , new DevNookBeanDefinitionParser ()); } }
META-INF/spring.handlers
1 http\://www.devnook.cn/schema/devnook =cn.devnook.c1_entry.selftag.DevNookNamespaceHandler
META-INF/spring.schemas
1 http\://www.devnook.cn/schema/devnook =cn.devnook.c1_entry.selftag.DevNookNamespaceHandler
META-INF/devnook.xsd
1 2 3 4 5 6 7 8 9 10 11 12 <?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.devnook.cn/schema/devnook" elementFormDefault="qualified"> <element name="user"> <complexType> <attribute name="id" type="string"/> <attribute name="username" type="string"/> <attribute name="email" type="string"/> </complexType> </element> </schema>
spring主配置文件:selftag.xml
1 2 3 4 5 6 7 8 9 10 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:context ="http://www.springframework.org/schema/context" xmlns:devnook ="http://www.devnook.cn/schema/devnook" 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 http://www.devnook.cn/schema/devnook http://www.devnook.cn/schema/devnook.xsd" > <devnook:user id ="devnook" username ="devnook@user" email ="[email protected] " /> </beans >
入口程序: SelfTagTest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package cn.devnook.c1_entry.selftag;import cn.devnook.c1_entry.bean.MyClassPathXmlApplicationContext;import cn.devnook.c1_entry.bean.User;import org.springframework.context.support.ClassPathXmlApplicationContext;public class SelfTagTest { public static void main (String[] args) { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext ("selftag.xml" ); DevNook devnook = ac.getBean("devnook" , DevNook.class); System.out.println(devnook); ac.close(); } }
4.拓展自定义属性编辑器
自定义属性编辑器 AccountEditor 实现PropertyEditorSupport
自定义属性注册器xxxEditorRegistrar
实现PropertyEditorRegistrar
自定义 AccountEditorConfigurer 继承自 CustomEditorConfigurer 并交由spring管理(在xml声明)Account
1 2 3 4 5 6 7 8 9 10 11 package cn.devnook.c1_entry.selfeditor;@Data public class Account { private Integer id; private String name; private AccountAddress address; }
AccountAddress
1 2 3 4 5 6 7 package cn.devnook.c1_entry.selfeditor;@Data public class AccountAddress { private String province; private String city; }
自定义属性编辑器 AccountEditor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package cn.devnook.c1_entry.selfeditor;import java.beans.PropertyEditorSupport;public class AccountEditor extends PropertyEditorSupport { @Override public void setAsText (String text) throws IllegalArgumentException { String [] arr = text.split("_" ); AccountAddress address = new AccountAddress (); address.setProvince(arr[0 ]); address.setCity(arr[1 ]); this .setValue(address); } }
自定义注册器 AccountEditorRegistrar
1 2 3 4 5 6 7 8 9 10 11 12 package cn.devnook.c1_entry.selfeditor;import org.springframework.beans.PropertyEditorRegistrar;import org.springframework.beans.PropertyEditorRegistry;public class AccountEditorRegistrar implements PropertyEditorRegistrar { @Override public void registerCustomEditors (PropertyEditorRegistry registry) { registry.registerCustomEditor(AccountAddress.class, new AccountEditor ()); } }
自定义配置类:AccountEditorConfigurer
1 2 3 4 5 6 7 8 9 package cn.devnook.c1_entry.selfeditor;import org.springframework.beans.factory.config.CustomEditorConfigurer;public class AccountEditorConfigurer extends CustomEditorConfigurer {}
spring主配置文件:selfeditor.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?xml version="1.0" encoding="UTF-8" ?> <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" xmlns:util ="http://www.springframework.org/schema/util" 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 http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd" > <bean id ="account" class ="cn.devnook.c1_entry.selfeditor.Account" > <property name ="id" value ="1" > </property > <property name ="name" value ="devnook" > </property > <property name ="address" value ="上海_闵行" > </property > </bean > <bean class ="cn.devnook.c1_entry.selfeditor.AccountEditorConfigurer" > <property name ="propertyEditorRegistrars" > <array > <bean class ="cn.devnook.c1_entry.selfeditor.AccountEditorRegistrar" > </bean > </array > </property > </bean > </beans >
入口程序: SelfEditorTest
1 2 3 4 5 6 7 8 9 10 11 package cn.devnook.c1_entry.selfeditor;import org.springframework.context.support.ClassPathXmlApplicationContext;public class SelfEditorTest { public static void main (String[] args) { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext ("selfeditor.xml" ); Account account = ac.getBean("account" , Account.class); System.out.println(account); } }
运行结果:
1 Account{id=1, name='devnook', address=AccountAddress{province='上海', city='闵行'}}
从xml加载BeannDefinition到DefaultListableBeanFactory
Q:
prepareRefresh()中 earlyApplicationListeners 和 applicationListeners 作用
obtainFreshBeanFactory 时候为什么需要先refreshBeanFactory
[AbstractRefreshableApplicationContext] allowBeanDefinitionOverriding allowCircularReferences
org.springframework.context.support.AbstractApplicationContext#refresh