Spring組件開發(fā)模式支持SPEL表達(dá)式
本文是一個(gè) Spring 擴(kuò)展支持 SPEL 的簡單模式,方便第三方通過 Spring 提供額外功能。
簡化版方式
這種方式可以在任何能獲取ApplicationContext 的地方使用。還可以提取一個(gè)方法處理動態(tài) SPEL 表達(dá)式。
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 實(shí)現(xiàn)某些特殊邏輯時(shí),支持 SPEL 表達(dá)式
* @author liuzh
*/
public class SpelUtil implements ApplicationContextAware {
/**
* 通過 ApplicationContext 處理時(shí)
* @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);
//根據(jù)自己邏輯處理
//例如獲取 bean
Object bean = applicationContext.getBean(definitionName);
//獲取實(shí)際類型
Class<?> targetClass = AopUtils.getTargetClass(bean);
//獲取所有方法
for (Method method : targetClass.getDeclaredMethods()) {
//獲取自定義的注解(Bean是個(gè)例子)
Bean annotation = AnnotationUtils.findAnnotation(method, Bean.class);
//假設(shè)下面的 value 支持 SPEL
for (String val : annotation.value()) {
//解析 ${} 方式的值
val = beanFactory.resolveEmbeddedValue(val);
//解析 SPEL 表達(dá)式
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 實(shí)現(xiàn)某些特殊邏輯時(shí),支持 SPEL 表達(dá)式
* @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 {
//獲取實(shí)際類型
Class<?> targetClass = AopUtils.getTargetClass(bean);
//獲取所有方法
ReflectionUtils.doWithMethods(targetClass, method -> {
//獲取自定義的注解(Bean是個(gè)例子)
Bean annotation = AnnotationUtils.findAnnotation(method, Bean.class);
//假設(shè)下面的 value 支持 SPEL
for (String val : annotation.value()) {
//解析表達(dá)式
Object value = resolveExpression(val);
//TODO 其他邏輯
}
}, method -> {
//TODO 過濾方法
return true;
});
return null;
}
}
這種方式利用了 Spring 生命周期的幾個(gè)接口來獲取需要用到的對象。
Spring 生命周期調(diào)用順序
擴(kuò)展 Spring 我們必須了解這個(gè)順序,否則就沒法正確的使用各中對象。
完整的初始化方法及其標(biāo)準(zhǔn)順序是:
- BeanNameAware 的 setBeanName 方法
- BeanClassLoaderAware 的 setBeanClassLoader 方法
- BeanFactoryAware 的 setBeanFactory 方法
- EnvironmentAware 的 setEnvironment 方法
- EmbeddedValueResolverAware 的 setEmbeddedValueResolver 方法
- ResourceLoaderAware 的 setResourceLoader 方法 (僅在應(yīng)用程序上下文中運(yùn)行時(shí)適用)
- ApplicationEventPublisherAware 的 setApplicationEventPublisher 方法 (僅在應(yīng)用程序上下文中運(yùn)行時(shí)適用)
- MessageSourceAware 的 setMessageSource 方法 (僅在應(yīng)用程序上下文中運(yùn)行時(shí)適用)
- ApplicationContextAware 的 setApplicationContext 方法 (僅在應(yīng)用程序上下文中運(yùn)行時(shí)適用)
- ServletContextAware 的 setServletContext 方法 (僅在Web應(yīng)用程序上下文中運(yùn)行時(shí)適用)
- BeanPostProcessors 的 postProcessBeforeInitialization 方法
- InitializingBean 的 afterPropertiesSet 方法
- 自定義初始化方法
- BeanPostProcessors 的 postProcessAfterInitialization 方法
關(guān)閉bean工廠時(shí),以下生命周期方法適用:
- DestructionAwareBeanPostProcessors 的 postProcessBeforeDestruction 方法
- DisposableBean 的 destroy 方法
- 自定義銷毀方法
靈活運(yùn)用
利用上述模式可以實(shí)現(xiàn)很多便捷的操作。
Spring 中,使用類似模式的地方有:
- @Value 注解支持 SPEL(和 ${})
- @Cache 相關(guān)的注解(支持 SPEL)
- @EventListener 注解
- @RabbitListener 注解
- …
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
- Spring中@Value使用詳解及SPEL表達(dá)式
- 詳解Spring中Spel表達(dá)式和el表達(dá)式的區(qū)別
- SpringDataElasticsearch與SpEL表達(dá)式實(shí)現(xiàn)ES動態(tài)索引
- Spring AOP如何在注解上使用SPEL表達(dá)式注入對象
- spring之SpEL表達(dá)式詳解
- 使用Springboot自定義注解,支持SPEL表達(dá)式
- 基于spring?@Cacheable?注解的spel表達(dá)式解析執(zhí)行邏輯
- Spring?Cache抽象-使用SpEL表達(dá)式解析
- Spring實(shí)戰(zhàn)之Bean定義中的SpEL表達(dá)式語言支持操作示例
- Spring spel表達(dá)式使用方法示例
- Spring中SpEL表達(dá)式的使用全解
相關(guān)文章
java隨機(jī)生成8位數(shù)授權(quán)碼的實(shí)例
下面小編就為大家?guī)硪黄猨ava隨機(jī)生成8位數(shù)授權(quán)碼的實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02
SpringBoot實(shí)現(xiàn)文件下載的限速功能
在SpringBoot項(xiàng)目中,實(shí)現(xiàn)文件下載的限速功能可以有效控制服務(wù)器帶寬的占用,并防止單個(gè)用戶消耗過多的資源,本文將通過具體的代碼示例和詳細(xì)的流程解釋,介紹如何在SpringBoot項(xiàng)目中實(shí)現(xiàn)文件下載的限速功能,需要的朋友可以參考下2024-07-07
SpringBoot實(shí)現(xiàn)任意位置獲取HttpServletRequest對象
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)任意位置獲取HttpServletRequest對象,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
SpringBean和Controller實(shí)現(xiàn)動態(tài)注冊與注銷過程詳細(xì)講解
這篇文章主要介紹了SpringBean和Controller實(shí)現(xiàn)動態(tài)注冊與注銷過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-02-02
SpringBoot接受前臺參數(shù)的6種方式以及統(tǒng)一響應(yīng)代碼示例
這篇文章主要給大家介紹了關(guān)于SpringBoot接受前臺參數(shù)的6種方式以及統(tǒng)一響應(yīng)的相關(guān)資料,前端負(fù)責(zé)展示頁面和用戶交互,而后端則負(fù)責(zé)處理業(yè)務(wù)邏輯和數(shù)據(jù)存儲,在這種架構(gòu)下前端需要將用戶輸入的數(shù)據(jù)發(fā)送給后端進(jìn)行處理,需要的朋友可以參考下2023-12-12

