最近在忙项目中有关OData服务的开发,由于知识储备的不足、项目的特殊复杂性,总体来说做的比较头疼。抽时间可以把自己做过的这一块东西回顾、总结一下。在今天这个悠闲的周末傍晚,静下心来总结一下这周了解到的有关Spring的一些扩展接口的其他小玩意,喵喵喵~~~
目录:
- Spring扩展接口
- 小玩意
1. Spring 扩展接口
Spring整个框架严格遵循“开闭原则”,即“对扩展开放,对修改关闭”。个人理解为,Spring框架核心之一就是IOC,即"Bean Container",整个"Bean Container"的生命周期大致为:加载(XML或者Anotation)、初始化(初始化相应的Bean)、runtime(在runtime提供Bean)、销毁,也就是说,无论在什么情况下,Spring都是按照这一套流程走下来的,没有提供相应的类、接口、方法来改变这个过程,最多提供一些接口来“丰富”一下这个过程,即对“扩展开发”。这些接口包括:
- BeanFactoryPostProcessor
- InstantiationAwareBeanPostProcessor
- BeanNameAware
- BeanFactoryAware
- BeanPostProcessor
- InitializingBean
- DiposibleBean
- FactoryBean
- 在Bean生命周期中相应接口调用
对于整个 Bean Container 的扩展
- BeanFactoryPostProcessor
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
从接口定义上可以得知,其只有一个方法
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
参数类型为ConfigurableListableBeanFactory
,追根溯源,该接口的定义如下:
public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
void ignoreDependencyType(Class<?> type);
void ignoreDependencyInterface(Class<?> ifc);
void registerResolvableDependency(Class<?> dependencyType, Object autowiredValue);
boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)throws NoSuchBeanDefinitionException;
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
Iterator<String> getBeanNamesIterator();
void clearMetadataCache();
void freezeConfiguration();
boolean isConfigurationFrozen();
void preInstantiateSingletons() throws BeansException;
}
其中有一个方法
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
通过传入相应的Bean Name,就能拿到对应的BeanDefinition,其对应着一个Bean的元信息描述。
有关BeanDefinition的接口描述:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
String getParentName();
void setParentName(String parentName);
String getBeanClassName();
void setBeanClassName(String beanClassName);
String getFactoryBeanName();
void setFactoryBeanName(String factoryBeanName);
String getFactoryMethodName();
void setFactoryMethodName(String factoryMethodName);
String getScope();
void setScope(String scope);
boolean isLazyInit();
void setLazyInit(boolean lazyInit);
String[] getDependsOn();
void setDependsOn(String... dependsOn);
boolean isAutowireCandidate();
void setAutowireCandidate(boolean autowireCandidate);
boolean isPrimary();
void setPrimary(boolean primary);
ConstructorArgumentValues getConstructorArgumentValues();
MutablePropertyValues getPropertyValues();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
int getRole();
String getDescription();
String getResourceDescription();
BeanDefinition getOriginatingBeanDefinition();
}
其中里边有几个比较常用的方法:
void setFactoryBeanName(String factoryBeanName);
void setBeanClassName(String beanClassName);
void setScope(String scope);
void setLazyInit(boolean lazyInit);
以及一些相应的Get方法。
即在runtime时,可以通过以上接口来动态修改Bean的元描述信息:name、isLazyInit,scope
所以让我们回到最初探索的地方,扩展接口BeanFactoryPostProcessor
:实现这个接口的postProcessBeanFactory
,来根据需要在Spring启动时动态修改相应Bean的元描述信息。
- BeanFactoryAware
该接口的详细描述如下:
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
也只有一个方法
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
同样可以实现该接口,在runtime获得该BeanFactory
对于 Bean 的扩展
- InstantiationAwareBeanPostProcessor
该接口的定义如下:
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
}
其中包含了三个方法:
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
这三个方法的作用时期是在Bean的实例化阶段。之前我也不太清楚“实例化”和“初始化”的区别,后来查了资料,发现大概是这样的:
实例化----实例化的过程是一个创建Bean的过程,即调用Bean的构造函数,单例的Bean放入单例池中。
初始化----初始化的过程是一个赋值的过程,即调用Bean的setter,设置Bean的属性
- BeanNameAware
该接口的详细描述如下:
public interface BeanNameAware extends Aware {
void setBeanName(String name);
}
这个接口很简单,只有一个方法
void setBeanName(String name);
在实际开发中,可以实现该接口,动态地获取每一个被加载到"Bean Container"中的Bean Name
- BeanPostProcessor
该接口的详细描述如下:
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
其中包含了两个方法:
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
这两个方法分别是在Bean初始化的前后起作用,我们可以根据beanName来筛选出相应的Bean,并结合具体的业务需求来对某些Bean进行一些有针对性的预处理。
- InitializingBean
其接口的详细描述如下:
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
该接口只有一个方法
void afterPropertiesSet() throws Exception;
很明显,该接口是在某个Bean的所有Properties初始化完成之后起作用。该方法没有任何参数,可以根据具体业务需求来自定义处理。
扩展: 在Spring对于XML配置Bean的规范中,提供了一个属性init-method
,作用于该方法一样。该属性的具体用法大致如下:
<?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-4.1.xsd">
<bean id="common0" class="org.xrq.bean.common.CommonBean" init-method="initMethod">
<property name="commonName" value="common0"/>
</bean>
<bean id="common1" class="org.xrq.bean.common.CommonBean" init-method="initMethod">
<property name="commonName" value="common1"/>
</bean>
</beans>
- DisposableBean
该接口的具体描述如下:
public interface DisposableBean {
void destroy() throws Exception;
}
其中也只有一个方法
void destroy() throws Exception;
该方法是在某个Bean的结束时(Bean Container被销毁时)起作用。
- FactoryBean
该接口的详细描述如下:
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
其中有三个方法,实现方法getObject
,就可以加载自定义的Bean
在Bean生命周期中相应接口调用:
2. 小玩意
之前一直对Spring体系中的BeanFactory
和ApplicationContext
搞不明白,这次查了一点资料,逐渐理清了。
- BeanFactory:是一个对于IOC容器行为最基本的规范接口,比如getBean()
有关BeanFactory的具体实现,常见XmlBeanFactory
,不过该类已经被弃用了。 - ApplicationContext: 继承BeanFactory,不仅具有BeanFactory的功能,还支持国际化message处理,比如MessageSource接口,事件监听
有关ApplicationContext的具体实现,常见XmlWebApplicationContext
,ClassPathXmlApplicationContext
,FileSystemApplicationContext
,AnnotationConfigApplicationContext
。
有关ApplicationContext的扩展:获取ApplicationContext的几种方式:
- 直接通过上面列举的几种描述来获得,比如
pplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
- 通过Spring提供的工具类获取ApplicationContext对象,比如
ApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc);
继承自抽象类ApplicationObjectSupport
Spring初始化时,会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入继承自抽象类WebApplicationObjectSupport
说明:类似上面方法,调用getWebApplicationContext()获取WebApplicationContext实现接口ApplicationContextAware
通过Spring提供的ContextLoader
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
最后提供一种不依赖于servlet,不需要注入的方式。但是需要注意一点,在服务器启动时,Spring容器初始化时,不能通过以下方法获取Spring 容器