[Spring 从模拟开始学习源码]`@Value`的底层实现

发布时间:2023年12月18日

@Value 注入主要有三种场景:

  1. 注入原始值,比如说注入Value("hello")
  2. 注入变量,比如@Value("${JAVA_HOME}")
  3. 注入spel表达式,比如@Value("#{1 + 2}")

package com.example.value;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

@Configuration // 自动扫描bean3
public class ValueApplication {

    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(ValueApplication.class);
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();

        ContextAnnotationAutowireCandidateResolver resolver =
            new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);

        test1(context, resolver);
        test2(context, resolver);
        test3(context, resolver, Bean2.class.getDeclaredField("bean3"));
        System.out.println(">>>>>>>>>>>>>>>>>>>");
        test3(context, resolver, Bean4.class.getDeclaredField("value"));
    }

    private static void test1(AnnotationConfigApplicationContext context,
                              ContextAnnotationAutowireCandidateResolver resolver) throws Exception {
        DependencyDescriptor dd1 =
            new DependencyDescriptor(Bean1.class.getDeclaredField("home"), false);
        // 获取 @Value 的内容
        String value = resolver.getSuggestedValue(dd1).toString();
        System.out.println(value);

        // 解析 ${}
        value = context.getEnvironment().resolvePlaceholders(value);
        System.out.println(value);
    }

    // ${} -> 类型
    private static void test2(AnnotationConfigApplicationContext context,
                              ContextAnnotationAutowireCandidateResolver resolver) throws Exception{
        DependencyDescriptor dd1 =
            new DependencyDescriptor(Bean1.class.getDeclaredField("age"), false);
        // 获取 @Value 的内容
        String value = resolver.getSuggestedValue(dd1).toString();
        System.out.println("@Value 的 value 属性值: " + value);

        // 解析 ${}
        value = context.getEnvironment().resolvePlaceholders(value);
        System.out.println("解析得到的值: " + value);
        System.out.println("解析得到的值的类型: " + value.getClass());
        // 转成字段的类型
        Object age = context.getBeanFactory()
            .getTypeConverter()
            .convertIfNecessary(value, dd1.getDependencyType());
        System.out.println("转换后的类型: " + age.getClass());
    }

    // spel
    private static void test3(AnnotationConfigApplicationContext context,
                              ContextAnnotationAutowireCandidateResolver resolver,
                              Field field) throws Exception {
        DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
        // 获取 @Value 的内容
        String value = resolver.getSuggestedValue(dd1).toString();
        System.out.println("@Value 的 value 属性值: " + value);

        // 解析 ${}
        value = context.getEnvironment().resolvePlaceholders(value);
        System.out.println("解析得到的值: " + value);
        System.out.println("解析得到的值的类型: " + value.getClass());

        // 解析 #{}
        Object bean3 = context.getBeanFactory()
            .getBeanExpressionResolver()
            .evaluate(value, new BeanExpressionContext(context.getBeanFactory(), null));

        // 类型转换
        Object result = context.getBeanFactory()
            .getTypeConverter()
            .convertIfNecessary(bean3, dd1.getDependencyType());
        System.out.println("转换后的类型: " + result.getClass());
    }

    static class Bean1 {
        @Value("${JAVA_HOME}")
        private String home;
        @Value("18")
        private int age;
    }

    static class Bean2 {
        @Value("#{@bean3}")
        private Bean3 bean3;
    }

    @Component("bean3")
    static class Bean3 {
    }

    static class Bean4 {
        @Value("#{'hello, ' + '${JAVA_HOME}'}")
        private String value;
    }


}

输出结果

${JAVA_HOME}
/Users/xx/Library/Java/JavaVirtualMachines/corretto-17.0.8.1/Contents/Home
@Value 的 value 属性值: 18
解析得到的值: 18
解析得到的值的类型: class java.lang.String
转换后的类型: class java.lang.Integer
@Value 的 value 属性值: #{@bean3}
解析得到的值: #{@bean3}
解析得到的值的类型: class java.lang.String
转换后的类型: class com.example.value.ValueApplication$Bean3
>>>>>>>>>>>>>>>>>>>
@Value 的 value 属性值: #{'hello, ' + '${JAVA_HOME}'}
解析得到的值: #{'hello, ' + '/Users/xx/Library/Java/JavaVirtualMachines/corretto-17.0.8.1/Contents/Home'}
解析得到的值的类型: class java.lang.String
转换后的类型: class java.lang.String

用到的几个工具类

获取 @Value内容

Bean2.class.getDeclaredField("bean3")
DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
// 获取 @Value 的内容
String value = resolver.getSuggestedValue(dd1).toString();

解析 ${}内容

value = context.getEnvironment().resolvePlaceholders(value);

解析 SPEL

Object bean3 = context.getBeanFactory()
            .getBeanExpressionResolver()
            .evaluate(value, new BeanExpressionContext(context.getBeanFactory(), null));

类型转换

Object result = context.getBeanFactory()
    .getTypeConverter()
    .convertIfNecessary(bean3, dd1.getDependencyType());
文章来源:https://blog.csdn.net/qq_45704048/article/details/135051808
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。