【Spring】SpEL 二 PropertyAccessor 相关(BeanFactoryAccessor EnvironmentAccessor)

前言

本章节介绍 PropertyAccessor 相关类

PropertyAccessor

public interface PropertyAccessor {

	@Nullable
	// 指定目标类型
	Class<?>[] getSpecificTargetClasses();

	// 是否可读
	boolean canRead(EvaluationContext context, @Nullable Object target, String name) throws AccessException;

	// 读操作
	TypedValue read(EvaluationContext context, @Nullable Object target, String name) throws AccessException;

	// 是否可写
	boolean canWrite(EvaluationContext context, @Nullable Object target, String name) throws AccessException;

	// 写操作
	void write(EvaluationContext context, @Nullable Object target, String name, @Nullable Object newValue)
			throws AccessException;

}

属性操作相关,即如何通过 表达式 定位、操作对应属性
PropertyAccessor
继承图如上:

  • ReflectivePropertyAccessor,基于反射操作
  • BeanFactoryAccessor,依赖 BeanFactory 进行操作
  • EnvironmentAccessor,依赖 Environment 进行操作
  • BeanExpressionContextAccessor,依赖 BeanExpressionContext 进行操作
  • 等等

BeanFactoryAccessor

public class BeanFactoryAccessor implements PropertyAccessor {

	// 数据源类型指定为 BeanFactory
	@Override
	public Class<?>[] getSpecificTargetClasses() {
		return new Class<?>[] {BeanFactory.class};
	}

	// BeanFactory 中要有对应的 bean
	@Override
	public boolean canRead(EvaluationContext context, @Nullable Object target, String name) throws AccessException {
		return (target instanceof BeanFactory && ((BeanFactory) target).containsBean(name));
	}

	// 获取对应的 bean
	@Override
	public TypedValue read(EvaluationContext context, @Nullable Object target, String name) throws AccessException {
		Assert.state(target instanceof BeanFactory, "Target must be of type BeanFactory");
		return new TypedValue(((BeanFactory) target).getBean(name));
	}

	// 不可写
	@Override
	public boolean canWrite(EvaluationContext context, @Nullable Object target, String name) throws AccessException {
		return false;
	}

	@Override
	public void write(EvaluationContext context, @Nullable Object target, String name, @Nullable Object newValue)
			throws AccessException {

		throw new AccessException("Beans in a BeanFactory are read-only");
	}

}
  • BeanFactoryAccessor 的实现很简单,就是基于 BeanFactory 进行操作,注意是只可读不可写
  • EnvironmentAccessor 的实现也类似,读操作委托给 getProperty 方法,同样不可写

StandardEvaluationContext

上一章节中,我们使用最频繁的 解析上下文 就是 StandardEvaluationContext,它内部便是维护了一组 PropertyAccessor,当然如果不指定,其默认维护一个 ReflectivePropertyAccessor,源码如下:

	private List<PropertyAccessor> initPropertyAccessors() {
		List<PropertyAccessor> accessors = this.propertyAccessors;
		if (accessors == null) {
			accessors = new ArrayList<>(5);
			accessors.add(new ReflectivePropertyAccessor());
			this.propertyAccessors = accessors;
		}
		return accessors;
	}

所以上一章节我们解析的表达式,都是基于 反射 操作对应对象、属性了

接下来,我们就基于 BeanFactoryAccessorEnvironmentAccessor 给出示例

示例

@SpringBootTest
@ContextConfiguration(classes = { PropertyAccessorTest.class })
public class PropertyAccessorTest {

    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();

    @Autowired
    BeanFactory beanFactory;

    @Autowired
    Environment environment;

    @Bean
    public A a() {
        return new A();
    }

    @Test
    public void bean() {
        context.addPropertyAccessor(new BeanFactoryAccessor());
        context.setRootObject(beanFactory);

        A a = parser
                .parseExpression("a")
                .getValue(context, A.class);
        Assertions.assertNotNull(a);
    }

    @Test
    public void env() {
        context.addPropertyAccessor(new EnvironmentAccessor());
        context.setRootObject(environment);

        System.out.println(parser
                .parseExpression("user")
                .getValue(context, String.class));
    }
}
  • StandardEvaluationContext 类提供方法 addPropertyAccessor,可以额外添加 PropertyAccessor
  • 示例中注册了名为 abean,再上下文中添加对应的 BeanFactoryAccessor 后,就可以解析到表达式 a
  • 同理,添加对应 EnvironmentAccessor,可以从 EnvironmentAccessor 中获取对应属性,示例中的 userSystemProperties 中的属性
  • 同样,我们可以实现 PropertyAccessor 来自定义拓展,可参考文末给出的链接

总结

本章节主要介绍了 PropertyAccessor 类相关,重点示例了 BeanFactoryAccessorEnvironmentAccessor 的用法,可以基于 Spring 环境进行表达式解析

深入了解这块知识最初的目的是为 Spring 处理 表达式 做铺垫,结果发现它也是可以解耦 Spring 来使用的,希望能在今后的开发工作中尽可能使用,因为它功能实在很强大

相关参考

【小家Spring】SpEL你感兴趣的实现原理浅析spring-expression~(SpelExpressionParser、EvaluationContext、rootObject)

上一篇:【Spring】SpEL 一 语法总结与示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值