Spring扩展点
Spring是一个很灵活的框架,它除了自身很棒的设计之外,还对外提供了许多的扩展点,可以说很完美地阐释了什么叫做开闭原则,对修改关闭,对扩展开放。开发人员可以根据自身的实际需要进行扩展,下面说一说我知道的几处扩展点。
Filter
过滤器是J2EE里面的概念,它可以在请求到来之前,请求结束之后做一些额外的处理,通常情况,在开发WEB项目的时候,我们会在web.xml中加入如下的一段XML文本:
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这段代码的目的是添加一个过滤器,这个过滤器的作用是设置我们的相应和请求的字符编码为指定的UTF-8。spring源码如下:
Spring就是这样为我们提供扩展点的,提供一个OncePerRequestFilter类,我们只需要继承并编写自己的逻辑,就可以实现自定义的过滤逻辑,比如权限控制
InitializingBean
这是一个接口,凡是实现了这个接口的类,spring在初始化的时候就会回调你提供的方法。为了更清晰地理解,我们看一下下面的代码:
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
/**
* 执行InitializingBean接口方法
*/
//bean是否是InitializingBean的实例
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
/**
* 执行init-method方法
*/
if (mbd != null) {
//判断是否指定了init-method方法,如果指定了init-method方法,则再调用指定的init-method
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//调用客户指定的init-method方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
这是我从Spring源码中摘出来的一段,其主要目的是调用初始化方法(看函数名字就知道啦),初始化方法主要有2个,一个是InitializingBean接口的方法,另一个是你通常会在XML中指定的init-method方法,并且从代码中不难看出,InitializingBean接口的方法先执行,init-method方法后执行。有人会问,初始化方法在什么时候执行的呢,请看下面的代码
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
/**
* 执行BeanPostProcessor接口中的方法
*/
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//执行init-method方法 || InitializingBean方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
/**
* 执行BeanPostProcessor接口中的方法
*/
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
代码一目了然,不需要多做解释了。