Spring扩展点

Posted by 大雁小鱼的博客 on June 24, 2018

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;
	}

代码一目了然,不需要多做解释了。