Spring组件开发模式支持SPEL表达式
作者:isea533 发布时间:2023-09-05 11:53:31
本文是一个 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 方法
自定义销毁方法
参考:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html
灵活运用
利用上述模式可以实现很多便捷的操作。
Spring 中,使用类似模式的地方有:
@Value 注解支持 SPEL(和 ${})
@Cache 相关的注解(支持 SPEL)
@EventListener 注解
@RabbitListener 注解
…
来源:https://blog.csdn.net/isea533/article/details/84100428


猜你喜欢
- LRU是Least Recently Used 的缩写,翻译过来就是“最近最少使用”,LRU缓存就是使用这种原理实现,简单的说就是缓存一定量
- 概述在Spring中,我们可以通过 @Autowired注解的方式为一个方法中注入参数,那么这种方法背后到底发生了什么呢,这篇文章将讲述如何
- maven打包指定jdk的版本问题今天遇到个问题,项目中新写了一个接口,其中用到了lambda表达式,本地跑是没问题的,但提交到gitLab
- 本文实例讲述了java读取properties文件的方法。分享给大家供大家参考。具体实现方法如下:package com.test.demo
- volatile变量volatile是Java的关键词,我们可以用它来修饰变量或者方法。为什么要使用volatilevolatile的典型用
- 修改\packages\apps\Camera\res\values\arrays.xml中的以下代码: <string-array
- 集合、数组都是对多个数据进行存储操作(主要是内存层面存储)的结构,简称Java容器。数组的特点1.数组初始化以后,长度确定不可变2.数组定义
- 1.Mybatis概述 MyBatis 是一款
- 本文实例为大家分享了WheelPicker自定义时间选择器控件的具体代码,供大家参考,具体内容如下先上图:使用android自带的DateP
- Android中的线程池ThreadPoolExecutor解决了单线程下载数据的效率慢和线程阻塞的的问题,它的应用也是优化实现的方式。所以
- Android MotionEvent中getX()和getRawX()的区别实例详解实例代码:public class Res exten
- 本文实例讲述了C#封装的Sqlite访问类。分享给大家供大家参考。具体分析如下:C#封装的Sqlite访问类,要访问Sqlite这下简单了,
- 本文实例讲述了基于JavaMail API收发邮件的方法。分享给大家供大家参考。具体如下:1.JavaMail API按其功能划分通常可分为
- 简要DecimalFormat 的 pattern 都包含着 正负子 pattern ,例如 “#,##0.00;(#,##0.00)”:/
- 小编在之前给大家介绍过很多android项目打包的经验,本篇内容我们通过一个项目实例来给大家讲解android每一步打包和签名的过程。and
- 多态性1理解多态性:可以理解为一个事物的多种形态。2何为多态性:对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)3多态的
- springBoot集成Elasticsearch 报错 Health check failed今天集成Elasticsearch 时启动报
- 为什么需要将webView放在独立进程webView 加载网页的时候可能占用大量内存,导致应用程序OOM。webView 在访问结束的时候可
- webview是一个很简单的功能,代码没有什么逻辑上的难度,只是需要注意权限上的问题。其实在安卓编程的过程当中,权限问题可以算是出现的比较多
- 一般而言在Android上使用JAVA实现彩图转换为灰度图,与J2ME上的实现方法类似,不过遇到频繁地转换或者是大图转换时,就必须使用NDK