评论

收藏

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

编程语言 编程语言 发布于:2021-10-06 13:51 | 阅读数:277 | 评论:0

今天小编就为大家分享一篇关于Spring组件开发模式支持SPEL表达式,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
本文是一个 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 注解

总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对CodeAE代码之家的支持。如果你想了解更多相关内容请查看下面相关链接
原文链接:https://blog.csdn.net/isea533/article/details/84100428

关注下面的标签,发现更多相似文章