发布于 

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");
// 检验环境变量中的 USER
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) {
// 允许BBD重写
super.setAllowBeanDefinitionOverriding(false);
// 允许循环依赖
super.setAllowCircularReferences(false);
super.customizeBeanFactory(beanFactory);
}
}

3.配置自定义标签并让spring解析

主要步骤:

  1. 自定义对象,用于接受xml配置
  2. 自定义BeanDefinitionParser继承自AbstractSingleBeanDefinitionParser,重写getBeanClass(Element) 和 doParse(Element element, BeanDefinitionBuilder builder)
  3. 自定义NamespaceHandler 继承自 NamespaceHandlerSupport,重写init()
  4. 自定义spring.handlers配置
  5. 自定义spring.schemas
  6. 自定义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.拓展自定义属性编辑器

  1. 自定义属性编辑器 AccountEditor 实现PropertyEditorSupport
  2. 自定义属性注册器xxxEditorRegistrar 实现PropertyEditorRegistrar
  3. 自定义 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:

  1. prepareRefresh()中 earlyApplicationListeners 和 applicationListeners 作用

  2. obtainFreshBeanFactory 时候为什么需要先refreshBeanFactory

  3. [AbstractRefreshableApplicationContext] allowBeanDefinitionOverriding allowCircularReferences

org.springframework.context.support.AbstractApplicationContext#refresh