Spring常见的扩展点
扩展initPropertySources方法
理解:在refresh方法中的prepareRefresh方法,执行刷新前的准备工作中提供了initPropertySources模板方法,一般用于一些环境变量的设置
源码出处:
1 | protected void prepareRefresh() { |
继承具体的类并扩展实现,ClassPathXmlApplicationContext为AbstractApplicationContext的字类,可以进行一些环境变量的设置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
public MyClassPathXmlApplicationContext(String... configLocations){
super(configLocations);
}
protected void initPropertySources() {
getEnvironment().setRequiredProperties("OS");
}
}
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new MyClassPathXmlApplicationContext("test2.xml");
User user=(User)context.getBean("testbean");
System.out.println("username:"+user.getUserName()+" "+"email:"+user.getEmail());
}
}该扩展点在Spring MVC中的具体应用
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
54public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
/** Servlet context init parameters property source name: {@value}. */
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
/** Servlet config init parameters property source name: {@value}. */
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
/** JNDI property source name: {@value}. */
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
protected void customizePropertySources(MutablePropertySources propertySources) {
// 1.添加servletConfigInitParams属性源(作为占位符, 之后会被替换)
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
// 2.添加servletContextInitParams属性源(作为占位符, 之后会被替换)
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
// 3.添加jndiProperties属性源
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
// 4.调用父类中的customizePropertySources方法
super.customizePropertySources(propertySources);
}
public void initPropertySources( ServletContext servletContext, ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
}
}
public abstract class WebApplicationContextUtils {
public static void initServletPropertySources(MutablePropertySources propertySources, ServletContext servletContext) {
initServletPropertySources(propertySources, servletContext, null);
}
public static void initServletPropertySources(MutablePropertySources sources,
ServletContext servletContext, ServletConfig servletConfig) {
Assert.notNull(sources, "'propertySources' must not be null");
String name = StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME;
if (servletContext != null && sources.get(name) instanceof StubPropertySource) {
// 1.如果servletContext不为null && propertySources中包含servletContextInitParams数据源 && 该数据源的类型为StubPropertySource,
// 则将servletContextInitParams的数据源替换成servletContext
sources.replace(name, new ServletContextPropertySource(name, servletContext));
}
name = StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME;
if (servletConfig != null && sources.get(name) instanceof StubPropertySource) {
// 2.如果servletConfig不为null && propertySources中包含servletConfigInitParams数据源 && 该数据源的类型为StubPropertySource,
// 则将servletConfigInitParams的数据源替换成servletConfig
sources.replace(name, new ServletConfigPropertySource(name, servletConfig));
}
}
}
扩展实现customizeBeanFactory方法
在创建BeanFactory后, 可以重写该方法, 为BeanFactory设置属性,源码出处:
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
54public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
public void refresh() throws BeansException, IllegalStateException {
......
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
......
}
}
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 1.刷新 BeanFactory,由AbstractRefreshableApplicationContext实现
refreshBeanFactory();
// 2.拿到刷新后的 BeanFactory
return getBeanFactory();
}
}
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
protected final void refreshBeanFactory() throws BeansException {
// 1.判断是否已经存在 BeanFactory,如果存在则先销毁、关闭该 BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 2.创建一个新的BeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 可以继承该类或者其字类,重写该方法
customizeBeanFactory(beanFactory);
// 3.加载 bean 定义。
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
}
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
}此方法是用来实现BeanFactory的属性设置,主要是设置两个属性:
allowBeanDefinitionOverriding:是否允许覆盖同名称的不同定义的对象
allowCircularReferences:是否允许bean之间的循环依赖1
2
3
4
5
6
7
8
9
10
11
12
13public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
MyClassPathXmlApplicationContext(String... locations){
super(locations);
}
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.setAllowBeanDefinitionOverriding(true);
super.setAllowCircularReferences(true);
super.customizeBeanFactory(beanFactory);
}
}
preProcessXml(root),postProcessXml(root)
Spring如何扩展实现自定义属性编辑器
在日常的工作中,我们经常遇到一些特殊的案例需要自定义属性的解析器来完成对应的属性解析工作,大家需要理解它的本质来进行随意的扩展工作,但是此处的扩展没有大家想象的那么简单,详细的流程讲课的时候我大概讲一下,但是要复杂很多。主要有两种方式:
1 | class Address { |