内容简介:版权声明:版权归博主所有,转载请带上本文链接!联系方式: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 我们必须了解这个顺序,否则就没法正确的使用各中对象。
完整的初始化方法及其标准顺序是:
-
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
方法 - 自定义销毁方法
灵活运用
利用上述模式可以实现很多便捷的操作。
Spring 中,使用类似模式的地方有:
-
@Value
注解支持 SPEL(和${}
) -
@Cache
相关的注解(支持 SPEL) -
@EventListener
注解 -
@RabbitListener
注解
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- CD组件库系列:想要的iOS Swift正则表达式基本都在这里
- 正则表达式 – 如何使用正则表达式进行Erlang模式匹配?
- lambda表达式
- 表达式 / 语句
- Python正则表达式
- python正则表达式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
首席产品官1 从新手到行家
车马 / 机械工业出版社 / 2018-9-25 / 79
《首席产品官》共2册,旨在为产品新人成长为产品行家,产品白领成长为产品金领,最后成长为首席产品官(CPO)提供产品认知、能力体系、成长方法三个维度的全方位指导。 作者在互联网领域从业近20年,是中国早期的互联网产品经理,曾是周鸿祎旗下“3721”的产品经理,担任CPO和CEO多年。作者将自己多年来的产品经验体系化,锤炼出了“产品人的能力杠铃模型”(简称“杠铃模型”),简洁、直观、兼容性好、实......一起来看看 《首席产品官1 从新手到行家》 这本书的介绍吧!