本文是一个 Spring 扩展支持 SPEL 的简单模式,方便第三方通过 Spring 提供额外功能。
简化版方式
这种方式可以在任何能获取 ApplicationContext
的地方使用。还可以提取一个方法处理动态 SPEL 表达式。
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.expression.StandardBeanExpressionResolver;
import org.springframework.core.annotation.AnnotationUtils;
import java.lang.reflect.Method;
/**
* 针对 Spring 实现某些特殊逻辑时,支持 SPEL 表达式
*
* @author liuzh
*/
public class SpelUtil implements ApplicationContextAware {
/**
* 通过 ApplicationContext 处理时
*
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (applicationContext instanceof ConfigurableApplicationContext) {
ConfigurableApplicationContext context = (ConfigurableApplicationContext)applicationContext;
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
StandardBeanExpressionResolver expressionResolver = new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader());
for (String definitionName : applicationContext.getBeanDefinitionNames()) {
BeanDefinition definition = beanFactory.getBeanDefinition(definitionName);
Scope scope = (definition != null ? beanFactory.getRegisteredScope(definition.getScope()) : null);
//根据自己逻辑处理
//例如获取 bean
Object bean = applicationContext.getBean(definitionName);
//获取实际类型
Class<?> targetClass = AopUtils.getTargetClass(bean);
//获取所有方法
for (Method method : targetClass.getDeclaredMethods()) {
//获取自定义的注解(Bean是个例子)
Bean annotation = AnnotationUtils.findAnnotation(method, Bean.class);
//假设下面的 value 支持 SPEL
for (String val : annotation.value()) {
//解析 ${} 方式的值
val = beanFactory.resolveEmbeddedValue(val);
//解析 SPEL 表达式
Object value = expressionResolver.evaluate(val, new BeanExpressionContext(beanFactory, scope));
//TODO 其他逻辑
}
}
}
}
}
}
上面是完全针对 ApplicationContext
的,下面是更推荐的一种用法。
推荐方式
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.expression.StandardBeanExpressionResolver;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;
/**
* 针对 Spring 实现某些特殊逻辑时,支持 SPEL 表达式
*
* @author liuzh
*/
public class SpelUtil2 implements BeanPostProcessor, BeanFactoryAware, BeanClassLoaderAware {
private BeanFactory beanFactory;
private BeanExpressionResolver resolver;
private BeanExpressionContext expressionContext;
/**
* 解析 SPEL
*
* @param value
* @return
*/
private Object resolveExpression(String value){
String resolvedValue = resolve(value);
if (!(resolvedValue.startsWith("#{") && value.endsWith("}"))) {
return resolvedValue;
}
return this.resolver.evaluate(resolvedValue, this.expressionContext);
}
/**
* 解析 ${}
* @param value
* @return
*/
private String resolve(String value){
if (this.beanFactory != null && this.beanFactory instanceof ConfigurableBeanFactory) {
return ((ConfigurableBeanFactory) this.beanFactory).resolveEmbeddedValue(value);
}
return value;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.resolver = new StandardBeanExpressionResolver(classLoader);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
if(beanFactory instanceof ConfigurableListableBeanFactory){
this.resolver = ((ConfigurableListableBeanFactory) beanFactory).getBeanExpressionResolver();
this.expressionContext = new BeanExpressionContext((ConfigurableListableBeanFactory) beanFactory, null);
}
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 对 bean 的后置处理
*
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//获取实际类型
Class<?> targetClass = AopUtils.getTargetClass(bean);
//获取所有方法
ReflectionUtils.doWithMethods(targetClass, method -> {
//获取自定义的注解(Bean是个例子)
Bean annotation = AnnotationUtils.findAnnotation(method, Bean.class);
//假设下面的 value 支持 SPEL
for (String val : annotation.value()) {
//解析表达式
Object value = resolveExpression(val);
//TODO 其他逻辑
}
}, method -> {
//TODO 过滤方法
return true;
});
return null;
}
}
这种方式利用了 Spring 生命周期的几个接口来获取需要用到的对象。
Spring 生命周期调用顺序
扩展 Spring 我们必须了解这个顺序,否则就没法正确的使用各中对象。
完整的初始化方法及其标准顺序是:
BeanNameAware
的setBeanName
方法BeanClassLoaderAware
的setBeanClassLoader
方法BeanFactoryAware
的setBeanFactory
方法EnvironmentAware
的setEnvironment
方法EmbeddedValueResolverAware
的setEmbeddedValueResolver
方法ResourceLoaderAware
的setResourceLoader
方法 (仅在应用程序上下文中运行时适用)ApplicationEventPublisherAware
的setApplicationEventPublisher
方法 (仅在应用程序上下文中运行时适用)MessageSourceAware
的setMessageSource
方法 (仅在应用程序上下文中运行时适用)ApplicationContextAware
的setApplicationContext
方法 (仅在应用程序上下文中运行时适用)ServletContextAware
的setServletContext
方法 (仅在Web应用程序上下文中运行时适用)BeanPostProcessors
的postProcessBeforeInitialization
方法InitializingBean
的afterPropertiesSet
方法- 自定义初始化方法
BeanPostProcessors
的postProcessAfterInitialization
方法
关闭bean工厂时,以下生命周期方法适用:
DestructionAwareBeanPostProcessors
的postProcessBeforeDestruction
方法DisposableBean
的destroy
方法- 自定义销毁方法
灵活运用
利用上述模式可以实现很多便捷的操作。
Spring 中,使用类似模式的地方有:
@Value
注解支持 SPEL(和${}
)@Cache
相关的注解(支持 SPEL)@EventListener
注解@RabbitListener
注解- …