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

网友投稿 266 2023-01-16


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 注解

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:网络电脑接口管理工具(网线接口工具)
下一篇:包含网上post测试的词条
相关文章

 发表评论

暂时没有评论,来抢沙发吧~