中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring組件開發模式支持SPEL表達式

發布時間:2020-10-24 17:08:06 來源:腳本之家 閱讀:249 作者:isea533 欄目:編程語言

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

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。如果你想了解更多相關內容請查看下面相關鏈接

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

贵州省| 庄浪县| 新野县| 客服| 沙坪坝区| 永丰县| 天峻县| 潮安县| 肥城市| 通渭县| 本溪市| 凌云县| 察雅县| 泗阳县| 长乐市| 深圳市| 金沙县| 莎车县| 吕梁市| 文成县| 延津县| 宿迁市| 抚远县| 天津市| 巴彦淖尔市| 静海县| 原平市| 泾源县| 阳新县| 蒙阴县| 太保市| 南木林县| 丹棱县| 吉隆县| 闽侯县| 安新县| 新津县| 南靖县| 资中县| 乐东| 南通市|