首页 >> 手游攻略

JAVAPARSER教师HD

大家好,关于JAVAPARSER教师HD很多朋友都还不太明白,今天小编就来为大家分享关于SPEL你真的会用吗?的知识,希望对各位有所帮助!

SpringExpressionLanguage概念

SpringExpressionLanguage(简称SpEL)是一种强大的表达式语言,支持在运行时查询和操作对象图。该语言的语法类似于UnifiedEL,但提供了额外的特性,最显著的是方法调用和基本的字符串模板功能。

虽然还有其他几种Java表达式语言可用——OGNL、MVEL和JBossEL等,SpEL是为了向Spring社区提供一种受良好支持的表达式语言,可以跨Spring产品组合中的所有产品使用。SpEL基于一种与技术无关的API,在需要时可以集成其他表达式语言实现。

作用

基于SpEL我们可以实现下面这些功能,当然是基于表达式,SpEL提供了表达式运行环境,而且不依赖于Spring,这样我可以基于其强大的执行器实现各种扩展。

支持功能字面表达式布尔和关系运算符正则表达式类表达式访问属性、数组、列表和映射方法调用关系运算符申明调用构造函数bean引用数组构造内联的list内联的map三元运算符变量用户自定义函数集合投影集合选择模板化表达式关键接口

将表达式字符串解析为可求值的编译表达式。支持解析模板以及标准表达式字符串。

publicinterfaceExpressionParser{nn/**n*解析字符串表达式为Expression对象n*/nExpressionparseExpression(StringexpressionString)throwsParseException;nn/**n*解析字符串表达式为Expression对象,基于ParserContext解析字符串,比如常见的#{exrp}n*/nExpressionparseExpression(StringexpressionString,ParserContextcontext)throwsParseException;nn}n

表达式在求值上下文中执行。正是在这个上下文中,表达式求值期间遇到的引用才会被解析。EvaluationContext接口有一个默认的实现StandardBeanExpressionResolver,可以通过继承该类进行扩展。

publicinterfaceEvaluationContext{nn/**n*获取Root上下文对象n*/nTypedValuegetRootObject();nn/**n*返回属性读写访问器n*/nList<PropertyAccessor>getPropertyAccessors();nn/**n*返回构造器解析器n*/nList<ConstructorResolver>getConstructorResolvers();nn/**n*返回方法解析器n*/nList<MethodResolver>getMethodResolvers();nn/**n*返回Bean解析器,用于Bean的查找n*/n@NullablenBeanResolvergetBeanResolver();nn/**n*根据类名(一般为全限名)返回一个类型定位器,比如T(java.lang.Math)n*/nTypeLocatorgetTypeLocator();nn/**n*返回可以将值从一种类型转换(或强制转换)为另一种类型的类型转换器。n*/nTypeConvertergetTypeConverter();nn/**n*返回一个类型比较器,用于比较对象对是否相等。n*/nTypeComparatorgetTypeComparator();nn/**n*返回一个运算符重载器,该重载器可以支持多个标准类型集之间的数学运算。n*/nOperatorOverloadergetOperatorOverloader();nn/**n*为变量设值n*/nvoidsetVariable(Stringname,@NullableObjectvalue);nn/**n*从变量取值n*/n@NullablenObjectlookupVariable(Stringname);nn}n适用场景扩展变量

正如Spring中使用的那样,我们可以基于SpEL实现基于Spring容器、运行环境上下文等动态取值。

数据审计

通过从复杂的数据结构中进行数据运算,一般针对数据汇总或者复杂的结构化数据时,通过自定义特定表达式(类似于DSL)来实现数据运算。

Spring的使用

在Spring中有着大量使用SpEL的场景,在平时的开发中,可能会看到如下的这些配置,比如通过${}、#{}这些包裹的表达式,主要都是基于SpEL实现。

@Value("#{systemProperties['pop3.port']?:25}")简单的看下源吗,可以看到针对@Value标记的类属性,是如何为其注入属性:

AutowiredAnnotationBeanPostProcessor->AutowiredFieldElement#injectvalue=beanFactory.resolveDependency(desc,beanName,autowiredBeanNames,typeConverter)DefaultListableBeanFactory#doResolveDependency

publicclassDefaultListableBeanFactory{nnpublicObjectdoResolveDependency(DependencyDescriptordescriptor,@NullableStringbeanName,n@NullableSet<String>autowiredBeanNames,@NullableTypeConvertertypeConverter)throwsBeansException{nnInjectionPointpreviousInjectionPoint=ConstructorResolver.setCurrentInjectionPoint(descriptor);ntry{nClass<?>type=descriptor.getDependencyType();nObjectvalue=getAutowireCandidateResolver().getSuggestedValue(descriptor);nif(value!=null){nif(valueinstanceofString){n//处理${}占位替换nStringstrVal=resolveEmbeddedValue((String)value);nBeanDefinitionbd=(beanName!=null&&containsBean(beanName)?ngetMergedBeanDefinition(beanName):null);n//SpEL处理nvalue=evaluateBeanDefinitionString(strVal,bd);n}n}n//省略...nreturnresult;n}catch(Exceptione){n//...n}n}n}n@Cacheable(value="users",key="#p0")具体实现可以阅读源码:org.springframework.cache.interceptor.CacheOperationExpressionEvaluator@KafkaListener(topics="#{'${topics}'.split(',')}")具体实现可以阅读源码:org.springframework.kafka.annotation.KafkaListenerAnnotationBeanPostProcessor示例

下面通过一些测试示例了解SpEL的基本用法,对应上面的一些功能实现,通过这些简单的例子,可以大概了解其语法与使用方式:

publicclassTests{n@TestnpublicvoidrunParser()throwsNoSuchMethodException{nSpelExpressionParserparser=newSpelExpressionParser();nMapmap=newHashMap();nmap.put("name","SpEL");nStandardEvaluationContextcontext=newStandardEvaluationContext(map);ncontext.setVariable("var1",1);ncontext.setVariable("func1",StringUtils.class.getMethod("hasText",String.class));ncontext.setVariable("func2",newRoot());ncontext.setBeanResolver(newMyBeanResolver());nnlog.info("字面量:{}",parser.parseExpression("'hello'").getValue(context));nlog.info("对象属性:{}",parser.parseExpression("'hello'.bytes").getValue(context));nlog.info("变量:{}",parser.parseExpression("#var1").getValue(context));nlog.info("调用方法:{}",parser.parseExpression("'hello'.concat('world')").getValue(context));nlog.info("静态方法:{}",parser.parseExpression("T(java.lang.System).currentTimeMillis()").getValue(context));nlog.info("方法:{}",parser.parseExpression("#func1('1')").getValue(context));nlog.info("实例方法:{}",parser.parseExpression("#func2.print('2')").getValue(context));nnRootroot=newRoot();nroot.list.add("0");nparser.parseExpression("list[0]").setValue(context,root,"1");nlog.info("设值:{}",root);nnlog.info("ROOT:{}",parser.parseExpression("#root").getValue(context));nlog.info("ROOT取值:{}",parser.parseExpression("#root[name]").getValue(context));nlog.info("ROOT取值:{}",parser.parseExpression("[name]").getValue(context));nnlog.info("THIS:{}",parser.parseExpression("#this").getValue(context));nnlog.info("运算符:{}",parser.parseExpression("1+1").getValue(context));nlog.info("操作符:{}",parser.parseExpression("1==1").getValue(context));nlog.info("逻辑运算:{}",parser.parseExpression("true&&false").getValue(context));nnParserContextparserContext=newParserContext(){n@OverridenpublicbooleanisTemplate(){nreturntrue;n}nn@OverridenpublicStringgetExpressionPrefix(){nreturn"#{";n}nn@OverridenpublicStringgetExpressionSuffix(){nreturn"}";n}n};nlog.info("#{表达式}:{}",parser.parseExpression("#{1+1}",parserContext).getValue(context));nnlog.info("Map:{}",parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context));nlog.info("List:{}",parser.parseExpression("{1,2,3,4}").getValue(context));nlog.info("Array:{}",parser.parseExpression("newint[]{1,2,3}").getValue(context));nnlog.info("instanceof:{}",parser.parseExpression("'hello'instanceofT(Integer)").getValue(context,Boolean.class));nlog.info("regex:{}",parser.parseExpression("'5.00'matches'^-?\\d+(\\.\\d{2})?$'").getValue(context,Boolean.class));nlog.info("三目运算:{}",parser.parseExpression("false?'trueExp':'falseExp'").getValue(context,String.class));nnlog.info("Bean:{}",parser.parseExpression("@bean1").getValue(context));n}n}n特殊处理T通过T(CLASS)指定类型,可以用来类型判断或者调用类静态方法sec.setTypeLocator(newStandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader()));@通过@Name获取beansec.setBeanResolver(newBeanFactoryResolver(evalContext.getBeanFactory()));&通过&Name获取beanFactory

sec.setBeanResolver(newBeanFactoryResolver(evalContext.getBeanFactory()));

#通过#{}标识表达式,主要在springBeanExpressionResolverresolver=beanFactory.getBeanExpressionResolver();BeanExpressionContextcontext=newBeanExpressionContext(beanFactory,null);

从root取值:#root.name或者name(#root可以忽略)从variables取值或方法:#var

扩展

下面以一个示例看下SpEL在我们项目中的具体应用:

publicclassTests{n/**n*执行测试n*/n@TestnpublicvoidrunCalc(){nSpelExpressionParserparser=newSpelExpressionParser();nStandardEvaluationContextcontext=newStandardEvaluationContext();ncontext.setVariable("helper",newStudentHelper());ncontext.setVariable("students",genStudents(100));nnlog.info("maxscore:{}",parser.parseExpression("#helper.max(#students)").getValue(context,Double.class));nlog.info("minscore:{}",parser.parseExpression("#helper.min(#students)").getValue(context,Double.class));nlog.info("avgscore:{}",parser.parseExpression("#helper.avg(#students)").getValue(context,Double.class));n}nn/**n*生成测试数据n*@paramcountn*@returnn*/nprivateList<Student>genStudents(intcount){nList<Student>students=newArrayList<>();nFakerfaker=newFaker(Locale.CHINA);nNamename=faker.name();nNumbernumber=faker.number();nIntStream.range(0,count).forEach(i->{nstudents.add(newStudent(name.name(),number.randomDouble(3,60,100)));n});nreturnstudents;n}nn@Datan@AllArgsConstructornclassStudent{nprivateStringname;nprivatedoublescore;n}nn/**n*工具类n*/nclassStudentHelper{nnpublicdoublemax(List<Student>students){nif(CollectionUtils.isEmpty(students)){nreturn0;n}nreturnstudents.stream().mapToDouble(Student::getScore).max().getAsDouble();n}nnpublicdoublemin(List<Student>students){nif(CollectionUtils.isEmpty(students)){nreturn0;n}nreturnstudents.stream().mapToDouble(Student::getScore).min().getAsDouble();n}nnpublicdoubleavg(List<Student>students){nif(CollectionUtils.isEmpty(students)){nreturn0;n}nreturnstudents.stream().mapToDouble(Student::getScore).average().getAsDouble();n}n}n}n

在这个示例中,我们主要通过SpEL获取获取学生分值的最大值、最小值、平均值等方式,在实际的项目中使用时,绝非如此简单,比如我们在做数据统计时,对各项指标数值的计算就是通过SpEL实现,因为具体功能的实现是由我们自己定义,因此在业务扩展上会非常的方便。

结束语

SpEL是一个功能非常强大的基于Java的解释型语言解析器,如果你想基于表达式的形式,对复杂结构数据计算或审计的需求时,不妨试试这个轻量级工具。

OK,关于JAVAPARSER教师HD和SPEL你真的会用吗?的内容到此结束了,希望对大家有所帮助。



本文由欣欣吧手游攻略栏目发布,感谢您对欣欣吧的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人站长或者朋友圈,但转载请说明文章出处“JAVAPARSER教师HD

标签:
Javaparser教师Big
« 上一篇 2023-10-17