问题(已解决):Spring-Expression中,SpelNodeImpl类的子类BeanReference对应什么场景?
【背景】
在研究SpEL表达式漏洞官方推出的增强方案时发现,官方推出的SimpleEvaluationContext.java对比StandardEvaluationContext.java修改了一些东西。其中一个就是修改了getBeanResolver()方法的实现,将其返回置为空。分析源码以后,我猜测:SimpleEvaluationContext.java重写getBeanResolver()方法的实现,目的是为了禁止在bean中使用表达式。getBeanResolver()方法调用图如下(虚线表示接口或抽象类的方法):
【问题描述】
为了验证这个猜想,我写了一个使用bean中使用SpEL的demo,但是发现demo运行时,并没有构造BeanReference类的实例,更没有调用到BeanReference.getValueInternal()方法以及EvaluationContext.getBeanResolver()方法。因此,BeanReference类的作用是什么呢?在什么情况下才能触发这个类的构造以及BeanReference.getValueInternal()方法的执行呢?
我用来测试的demo如下:
Inventor.java(Bean的java对象)
package com.power.bean; import java.util.Date; import java.util.GregorianCalendar; /** * @author power * @date 2018/10/8 下午2:34 */ public class Inventor { private String name; private Date birthday; private String nationality; private Object random; public Inventor() {} public Inventor(String name, Date birthday, String nationality) { this.name = name; this.birthday = birthday; this.nationality = nationality; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getNationality() { return nationality; } public void setNationality(String nationality) { this.nationality = nationality; } public Object getRandom() { return random; } public void setRandom(Object random) { this.random = random; } }
bean的配置文件spel01.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <bean id="test" class="com.power.bean.Inventor"> <!--<property name="random" value="#{T(java.lang.Math).random()*100}"></property>--> <property name="random" value="1000"></property> </bean> <bean id = "Tesla" class="com.power.bean.Inventor"> <!--<property name="name" value="#{test.name}"></property>--> <property name="name" value="#{'Hello'+ 'World'}"></property> <!-- <property name="birthday" value="1972-09-01"></property>--> <property name="nationality" value="Serbian"></property> <property name="random" value="#{test.random}"></property> </bean>测试类test.java:
package com.power.spel; import com.power.bean.Inventor; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.DataBindingPropertyAccessor; import org.springframework.expression.spel.support.SimpleEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext; import java.util.GregorianCalendar; /** * @author power * @date 2018/10/8 下午2:32 */ public class SpEL { public void test() { GregorianCalendar calendar = new GregorianCalendar(); calendar.set(1856,7,9); //Inventor tesla = new Inventor("Nikola Tesla", calendar.getTime(), "Serbian"); ApplicationContext ctx = new ClassPathXmlApplicationContext("spel01.xml"); Inventor tesla = ctx.getBean("Tesla",Inventor.class); System.out.println(tesla.getRandom()); } public static void main(String[] args) { SpEL demo = new SpEL(); demo.test(); } }
【实验情况】
最终实验的时候,SpelNodeImpl.getValue()并未调用BeanReference,getValueInternal()的实现,调用的是CompoundExpression.getValueInternal()。且整个执行过程均未调用到BeanReference.getValueInternal()
【问题出现原因】
最后,重新阅读了Spring-Expression的官方文档以后发现:此处的BeanReference的应用场景不是在BeanDefinition中使用表达式,而是允许用户自定义的BeanResolver,处理ExpressionParser.parseExpression(String expression)中的expression。具体说明见:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions
- test.java
package com.power.spel; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; /** * @author power * @date 2018/10/10 上午10:39 */ public class BeanReferenceTest { public void test() { ExpressionParser parser = new SpelExpressionParser(); StandardEvaluationContext context = new StandardEvaluationContext(); context.setBeanResolver(new MyBeanResolver()); Object bean = parser.parseExpression("&foo").getValue(context); System.out.println(bean); } public static void main(String[] args) { BeanReferenceTest demo = new BeanReferenceTest(); demo.test(); } }
- MyBeanResolver.java
package com.power.spel; import org.springframework.expression.AccessException; import org.springframework.expression.BeanResolver; import org.springframework.expression.EvaluationContext; /** * @author power * @date 2018/10/9 下午9:09 */ public class MyBeanResolver implements BeanResolver { @Override public Object resolve(EvaluationContext context, String beanName) throws AccessException { if (beanName.equals("foo") || beanName.equals("bar")) { return "MyBeanResolver"; } if (beanName.equals("&foo")) { return "MyBeanResolver-&foo"; } throw new AccessException("not heard of " + beanName); } }阅读更多
- spring学习笔记①spring出现为了解决什么问题?
- 流式计算strom,Strom解决的问题,实现实时计算系统要解决那些问题,离线计算是什么,流式计算什么,离线和实时计算区别,strom应用场景,Strorm架构图和编程模型(来自学习资料)
- struts,spring和hibernate的出现解决了什么问题
- java.lang.ClassNotFoundException:org.springframework.web.context.ContextLoaderListener问题解决
- mybatis加Spring项目: 解决There is no getter for property named '***' in 'class java.lang.String'问题
- 根据原生JS封装函数,根据传递的选择器查找对应的元素以及解决getElementsByClassName() 兼容问题
- 关于Spring RestTemplate乱码问题解决
- org.springframework.dao.DuplicateKeyException问题解决
- 解决JAVA中内部类所对应的外部类引用初始化的问题
- spring-session和redis解决spring cloud中session不一致性问题
- 什么是跨域?怎么解决跨域问题?Flask解决跨域的问题
- 解决微信小程序中wxml中明明有数据,但是页面中什么都没有的问题
- 解决Spring+Quartz无法自动注入bean问题
- Spring MVC @ResponseBody注解返回响应流时中文乱码问题的解决
- Spring中的循环依赖问题介绍及解决方法
- 真正解决问题:maven eclipse tomcat java.lang.ClassNotFoundException: org.springframework.web.context.Contex
- [置顶] spring boot项目实战:跨域问题解决
- AJAX中的跨域问题:什么是跨域?如何解决跨域问题?
- 解决在场景中销毁无用对象的问题,详见tick方法
- Teradata Expression 12 在Windows 2003上Connection Reset 问题的解决方法