软件编程
位置:首页>> 软件编程>> java编程>> Spring组件开发模式支持SPEL表达式

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

作者:isea533  发布时间:2023-09-05 11:53:31 

标签: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 注解

来源:https://blog.csdn.net/isea533/article/details/84100428

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com