内容简介:版权声明:版权归博主所有,转载请带上本文链接!联系方式:abel533@gmail.com https://blog.csdn.net/isea533/article/details/84100428
版权声明:版权归博主所有,转载请带上本文链接!联系方式:abel533@gmail.com https://blog.csdn.net/isea533/article/details/84100428
本文是一个 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注解
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- CD组件库系列:想要的iOS Swift正则表达式基本都在这里
- 正则表达式 – 如何使用正则表达式进行Erlang模式匹配?
- lambda表达式
- 表达式 / 语句
- Python正则表达式
- python正则表达式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Effective JavaScript
David Herman / Addison-Wesley Professional / 2012-12-6 / USD 39.99
"It's uncommon to have a programming language wonk who can speak in such comfortable and friendly language as David does. His walk through the syntax and semantics of JavaScript is both charming and h......一起来看看 《Effective JavaScript》 这本书的介绍吧!