首页 > 开发 > Java > 正文

Spring组件开发模式支持SPEL表达式

2024-07-14 08:43:19
字体:
来源:转载
供稿:网友

本文是一个 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 注解

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对VeVb武林网的支持。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表