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

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

内容简介:版权声明:版权归博主所有,转载请带上本文链接!联系方式: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 注解

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

查看所有标签

猜你喜欢:

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

Effective JavaScript

Effective JavaScript

David Herman / Addison-Wesley Professional / 2012-12-6 / USD 39.99

"It's uncommon to have a programming language wonk who can speak in such comfortable and friendly language as David does. His walk through the syntax and semantics of JavaScript is both charming and h......一起来看看 《Effective JavaScript》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具