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

栏目: Java · 发布时间: 5年前

内容简介:版权声明:版权归博主所有,转载请带上本文链接!联系方式:abel533@gmail.com https://blog.csdn.net/isea533/article/details/84100428

版权声明:版权归博主所有,转载请带上本文链接!联系方式:abel533@gmail.com https://blog.csdn.net/isea533/article/details/84100428

本文是一个 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 我们必须了解这个顺序,否则就没法正确的使用各中对象。

完整的初始化方法及其标准顺序是:

  1. BeanNameAwaresetBeanName 方法
  2. BeanClassLoaderAwaresetBeanClassLoader 方法
  3. BeanFactoryAwaresetBeanFactory 方法
  4. EnvironmentAwaresetEnvironment 方法
  5. EmbeddedValueResolverAwaresetEmbeddedValueResolver 方法
  6. ResourceLoaderAwaresetResourceLoader 方法 (仅在应用程序上下文中运行时适用)
  7. ApplicationEventPublisherAwaresetApplicationEventPublisher 方法 (仅在应用程序上下文中运行时适用)
  8. MessageSourceAwaresetMessageSource 方法 (仅在应用程序上下文中运行时适用)
  9. ApplicationContextAwaresetApplicationContext 方法 (仅在应用程序上下文中运行时适用)
  10. ServletContextAwaresetServletContext 方法 (仅在Web应用程序上下文中运行时适用)
  11. BeanPostProcessorspostProcessBeforeInitialization 方法
  12. InitializingBeanafterPropertiesSet 方法
  13. 自定义初始化方法
  14. BeanPostProcessorspostProcessAfterInitialization 方法

关闭bean工厂时,以下生命周期方法适用:

  1. DestructionAwareBeanPostProcessorspostProcessBeforeDestruction 方法
  2. DisposableBeandestroy 方法
  3. 自定义销毁方法

参考: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html

灵活运用

利用上述模式可以实现很多便捷的操作。

Spring 中,使用类似模式的地方有:

  • @Value 注解支持 SPEL(和 ${}
  • @Cache 相关的注解(支持 SPEL)
  • @EventListener 注解
  • @RabbitListener 注解

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

捉虫记

捉虫记

施迎 / 清华大学出版社 / 2010-6 / 56.00元

《捉虫记:大容量Web应用性能测试与LoadRunner实战》主要讲解大容量Web性能测试的特点和方法,以及使用业内应用非常广泛的工具——Load Runner 9进行性能测试的具体技术与技巧。《捉虫记:大容量Web应用性能测试与LoadRunner实战》共17章,分为5篇。第1篇介绍软件测试的定义、方法和过程等内容:第2篇介绍Web应用、Web性能测试的分类、基本硬件知识、Web应用服务器选型、......一起来看看 《捉虫记》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

在线进制转换器
在线进制转换器

各进制数互转换器

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码