多平台统一管理软件接口,如何实现多平台统一管理软件接口
302
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小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~