精华内容
下载资源
问答
  • @Value注解
    千次阅读
    2020-09-27 08:05:35

    1、@Value注解作用

    该注解作用的作用是将我们配置文件的属性读出来,有@Value("${}")和@Value("#{}")两种方式

    2、@Value注解作用的两种方式

    第一种方式@Value("${}"):在使用Springboot项目搭建的项目时,配置文件application.properties中

    已经被加载到了项目中,在项目中可以通过该注解获取配置文件中的信息

    第二种方式@Value("#{}"):两种的注解区别在值上的区别为:

    @Value的值有两类:
        ① ${ property : default_value }
        ② #{ obj.property? :default_value }
        第一个注入的是外部配置文件对应的property,第二个则是SpEL表达式对应的内容。 那个
        default_value,就是前面的值为空时的默认值。注意二者的不同,#{}里面那个obj代表对象。

    配置文件应为application.properties或者application.yml,springboot容器会自动加载这些文件

    更多相关内容
  • 主要介绍了Spring @Value注解失效问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 本篇文章主要介绍了详解Spring通过@Value注解注入属性的几种方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
  • 主要介绍了Springboot在有参构造方法类中使用@Value注解取值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 在开发的过程中很多时候我们需要用到公共配置组件,@Value注解就是开发中常用到的工具,但是该注解使用不当很容易出现错误,查阅资料后总结了以下几种解决方案。

    在开发的过程中很多时候我们需要用到公共配置组件,@Value注解就是开发中常用到的工具,但是该注解使用不当很容易出现错误,查阅资料后总结了以下几种解决方案。


    1、使用场景及异常错误

    最近在做项目中需要用到文件上传,我采用的是七牛云对象存储管理平台,就是将本地文件上传到云端存储及管理,这个时候就需要一些从远程配置管理中心获取公共配置参数的场景。

    在编写文件上传下载服务业务逻辑实现类的时候,启动项目报出了如下异常:
    在这里插入图片描述
    看下业务逻辑实现类:

    import com.cloudflashpay.common.domain.BusinessException;
    import com.cloudflashpay.common.domain.CommonErrorCode;
    import com.cloudflashpay.common.util.QiniuUtils;
    import com.cloudflashpay.merchant.service.FileService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    
    /**
     * @author: 一宿君
     * @date: 2022-03-23 16:47:25
     * @description: 文件上传下载服务
     */
    @Service
    @Slf4j
    public class FileServiceImpl implements FileService {
    
        @Value("${oss.qiniu.url}")
        private String qiniuUrl;
    
        @Value("${oss.qiniu.accessKey}")
        private String accessKey;
    
        @Value("${oss.qiniu.secretKey}")
        private String secretKey;
    
        @Value("${oss.qiniu.bucket}")
        private String bucket;
    
        /**
         * 上传文件
         * @param bytes 文件字节
         * @param fileName 文件名称
         * @return 文件下载访问路径地址
         * @throws BusinessException
         */
        @Override
        public String upload(byte[] bytes, String fileName) throws BusinessException {
    
            try {
                //调用上传文件到七牛云工具类方法
                QiniuUtils.uploadFileQiniu(accessKey,secretKey,bucket,bytes,fileName);
            }catch (RuntimeException e){
                e.printStackTrace();
                log.error("上传文件到七牛云异常:{}",e.getMessage());
                throw new BusinessException(CommonErrorCode.E_100106);
            }
            //上传成功后,将文件的下载访问地址返回给前端(绝对路径)
            return qiniuUrl+fileName;
        }
    }
    

    出现上述异常错误是因为在启动SpringBoot项目的时候会预先检索@Value注解对应的配置参数值,如果该注解对应的配置参数key没有取到值,就会报错无效异常!

    2、解决方法

    2.1、@Value注解后面加上默认值

    	@Value("${oss.qiniu.url: default_value}")
        private String qiniuUrl;
    
        @Value("${oss.qiniu.accessKey: default_value}")
        private String accessKey;
    
        @Value("${oss.qiniu.secretKey: default_value}")
        private String secretKey;
    
        @Value("${oss.qiniu.bucket: default_value}")
        private String bucket;
    

    注解后面加上默认值,如果@Value注解在加载的过程中没有取到值,或者说${key}不存在,则会默认采用这个default_value,这样就可以避免在启动项目的时候报错中断,便于后续排查。

    2.2、在 Application启动类中设置PropertySourcesPlaceholderConfigurer类的默认属性

    	// 设置开启忽略@Value注解取不到值时不报错
        @Bean
        public static PropertySourcesPlaceholderConfigurer placeholderConfigurer(){
            PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
            configurer.setIgnoreUnresolvablePlaceholders(true);
            return configurer;
        }
    

    这种方法虽然可以解决启动项目时避免报错,但是不推荐使用。

    2.3、将配置文件名称由application.yml修改为bootstap.yml

    这个也是最容易忽略的,SprintBoot项目在启动的过程中,会采用优先加载的机制加载配置文件。若application.ymlbootStrap.yml在同一目录下,则bootStrap.yml的加载顺序要高于application.yml,如果当前配置文件名称为application.yml,即使配置文件中存在所使用的属性key,使用@Value注解也会报错,因为在启动项目时@Value只能检索到优先及最高的配置文件,也就是bootStrap.yml

    原理:

    • bootstrap.yml用于应用程序上下文的引导阶段,由父Spring ApplicationContext加载。bootstrap.yml 可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。
    • application.yml可以用来定义应用级别的,如果搭配 spring-cloud-config 使用 application.yml 里面定义的文件可以实现动态替换。
    展开全文
  • Spring中的@Value注解详解

    千次阅读 2021-05-16 20:48:54
    本文来说下spring中的@Value注解 文章目录概述 概述

    本文主要介绍Spring @Value 注解注入属性值的使用方法的分析,文章通过示例代码非常详细地介绍,对于每个人的学习或工作都有一定的参考学习价值


    概述

    本文配置文件为yml文件

    在使用spring框架的项目中,@Value是经常使用的注解之一。其功能是将与配置文件中的键对应的值分配给其带注解的属性。在日常使用中,我们常用的功能相对简单。本文使您系统地了解@Value的用法。

    @Value 注解可以用来将外部的值动态注入到 Bean 中,在 @Value 注解中,可以使${} 与 #{} ,它们的区别如下:

    (1)@Value("${}"):可以获取对应属性文件中定义的属性值。

    (2)@Value("#{}"):表示 SpEl 表达式通常用来获取 bean 的属性,或者调用 bean 的某个方法。


    使用方式

    根据注入的内容来源,@ Value属性注入功能可以分为两种:通过配置文件进行属性注入和通过非配置文件进行属性注入。

    非配置文件注入的类型如下

    1. 注入普通字符串
    2. 注入操作系统属性
    3. 注入表达式结果
    4. 注入其他bean属性
    5. 注入URL资源

    基于配置文件的注入

    首先,让我们看一下配置文件中的数据注入,无论它是默认加载的application.yml还是自定义my.yml文档(需要@PropertySource额外加载)。

    application.yml文件配置,获得里面配置的端口号

    在这里插入图片描述

    程序源代码

    package cn.wideth.controller;
    
    import cn.wideth.PdaAndIpadApplication;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest()
    @ContextConfiguration(classes = PdaAndIpadApplication.class)
    public class ValueController {
    
        /**
         *Get in application.yml
         */
        @Value("${server.port}")
        private String port;
    
    
        @Test
        public  void  getPort(){
    
           System.out.println(port);
        }
    
    }
    

    程序结果

    在这里插入图片描述


    自定义yml文件,application-config.yml文件配置,获得里面配置的用户密码值

    注意,如果想导入自定义的yml配置文件,应该首先把自定义文件在application.yml文件中进行注册,自定义的yml文件要以application开头,形式为application-fileName

    在这里插入图片描述

    配置信息

    在这里插入图片描述

    测试程序

    package cn.wideth.controller;
    
    import cn.wideth.PdaAndIpadApplication;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest()
    @ContextConfiguration(classes = PdaAndIpadApplication.class)
    public class ValueController {
    
        /**
         *Get in application-config.yml
         */
        @Value("${user.password}")
        private String password;
    
        @Test
        public  void  getPassword(){
    
           System.out.println(password);
        }
    
    }
    

    程序结果

    在这里插入图片描述


    基于配置文件一次注入多个值

    配置信息

    在这里插入图片描述

    测试程序

    package cn.wideth.controller;
    
    import cn.wideth.PdaAndIpadApplication;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import java.util.List;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest()
    @ContextConfiguration(classes = PdaAndIpadApplication.class)
    public class ValueController {
    
        /**
         *Injection array (automatically split according to ",")
         */
        @Value("${tools}")
        private String[] toolArray;
    
        /**
         *Injection list form (automatic segmentation based on "," and)
         */
        @Value("${tools}")
        private List<String> toolList;
    
        @Test
        public  void  getTools(){
    
           System.out.println(toolArray);
           System.out.println(toolList);
        }
    
    }
    

    程序结果

    在这里插入图片描述


    基于非配置文件的注入

    在使用示例说明基于非配置文件注入属性的实例之前,让我们看一下SpEl

    Spring Expression Language是Spring表达式语言,可以在运行时查询和操作数据。使用#{…}作为操作符号,大括号中的所有字符均视为SpEl。

    让我们看一下特定实例场景的应用


    注入普通字符串

    测试程序

    package cn.wideth.controller;
    
    import cn.wideth.PdaAndIpadApplication;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import java.util.List;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest()
    @ContextConfiguration(classes = PdaAndIpadApplication.class)
    public class ValueController {
    
        // 直接将字符串赋值给 str 属性
        @Value("hello world")
        private String str;
    
    
        @Test
        public  void  getValue(){
    
            System.out.println(str);
        }
    
    }
    

    程序结果

    在这里插入图片描述


    注入操作系统属性

    可以利用 @Value 注入操作系统属性

    测试程序

    package cn.wideth.controller;
    
    import cn.wideth.PdaAndIpadApplication;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest()
    @ContextConfiguration(classes = PdaAndIpadApplication.class)
    public class ValueController {
    
        @Value("#{systemProperties['os.name']}")
        private String osName; // 结果:Windows 10
    
        @Test
        public  void  getValue(){
    
            System.out.println(osName);
        }
    }
    

    程序结果

    在这里插入图片描述


    注入表达式结果

    在 @Value 中,允许我们使用表达式,然后自动计算表达式的结果。将结果复制给指定的变量。如下

    测试程序

    package cn.wideth.controller;
    
    import cn.wideth.PdaAndIpadApplication;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest()
    @ContextConfiguration(classes = PdaAndIpadApplication.class)
    public class ValueController {
    
        // 生成一个随机数
        @Value("#{ T(java.lang.Math).random() * 1000.0 }")
        private double randomNumber;
    
        @Test
        public  void  getValue(){
    
            System.out.println(randomNumber);
        }
    }
    

    程序结果

    在这里插入图片描述


    注入其他bean属性

    其他Bean

    package cn.wideth.controller;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    //其他bean,自定义名称为 myBeans
    @Component("myBeans")
    public class OtherBean {
    
        @Value("OtherBean的NAME属性")
        private String name;
    
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    

    测试程序

    package cn.wideth.controller;
    
    import cn.wideth.PdaAndIpadApplication;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest()
    @ContextConfiguration(classes = PdaAndIpadApplication.class)
    public class ValueController {
    
        @Value("#{myBeans.name}")
        private String fromAnotherBean;
    
        @Test
        public  void  getValue(){
    
            System.out.println(fromAnotherBean);
        }
    }
    

    程序结果

    在这里插入图片描述


    注入URL资源

    测试程序

    package cn.wideth.controller;
    
    import cn.wideth.PdaAndIpadApplication;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    import java.net.URL;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest()
    @ContextConfiguration(classes = PdaAndIpadApplication.class)
    public class ValueController {
    
        /**
         *注入 URL 资源
         */
        @Value("https://www.baidu.com/")
        private URL homePage;
    
        @Test
        public  void  getValue(){
    
            System.out.println(homePage);
        }
    }
    

    程序结果

    在这里插入图片描述


    本文小结

    本文详细介绍了Spring中的@Value注解的用法。

    展开全文
  • spring @Value注解原理梳理及自定义实现@MyValue注解 目录 @Value注解如何使用? 探索@Value注解的实现过程 自定义实现@MyValue注解 1. @Value注解如何使用? 在项目中我们经常需要用到使用读取配置文件,进行属性...

    spring @Value注解原理梳理及自定义实现@MyValue注解

    目录

    • @Value注解如何使用?
    • 探索@Value注解的实现过程
    • 自定义实现@MyValue注解

    1. @Value注解如何使用?

    • 在项目中我们经常需要用到使用读取配置文件,进行属性值的注入很方便;
    • 很多时候我们不想手动的去初始化配置,在spring就提供了很强大的属性依赖配置注解@Value来实现,在实现bean创建后,自动实现属性的注入功能. 接下来我们将先 从一个简单的例子来描述,如何使用@Value注解,能达到什么效果,到最后我们自己动手实现自己的属性注解.

    1.1 准备

    创建maven项目,导入spring相关的包的此处省略…

    • 配置一个注解类,能让spring 管理, AppConfig
    package com.mp.aop.annotation.day02.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.stereotype.Component;
    @ComponentScan("com.mp.aop.annotation.day02.service")
    public class MyConfig {
    }
    
    • 此处配置@ComponentScan 注解扫描指定的package及其子包;将其所有实现了@bean @Component 等注解的类统一交由sping IOC来管理

    • 准备程序入口,访问整体的spring bean

    package com.mp.aop.annotation.day02;
    
    import com.mp.aop.annotation.day02.config.MyConfig;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import java.util.stream.Stream;
    
    public class MainManager {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
    
            // 已经完成了整个spring容器的初始化;这里先简单的获取下,我们容器负责管理的所有bean
            Stream.of(context.getBeanDefinitionNames()).forEach(s -> System.out.println(s));
    
        }
    }
    
    
    • 执行主入口程序,可以获取整个spring管理系统,自定义获取bean及其操作。

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    myConfig

    可以看到,刚开始程序会创建6个bean,其中5个为spring容器需要初始化(后面会详细介绍分析);另外一个为我们添加的配置类.

    • 添加一个带@Value注解的类 Person
    package com.mp.aop.annotation.day02.service;
    
    import com.mp.aop.annotation.MyAnnotation;
    import lombok.Data;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.stereotype.Component;
    
    /**
     * ClassName: Person
     * Function:  TODO
     * Date:      2020-04-11 21:34
     * author     mp
     * version    V1.0
     */
    @Component
    @Data
    public class Person {
        static {
            System.out.println("this is person Static");
        }
    
        @Value("mp")
        String name;   
    
        @Value("10")
        int age;
    
        String addr;
    
    
    
        public Person(String name, int age,String addr) {
            this.name = name;
            this.age = age;
            this.addr = addr;
            System.out.println("constuctor ...");
        }
    
        public void setName(String name) {
            this.name = name;
            System.out.println("person.setName。。。。"+name);
        }
    
        public void setAge(int age) {
            this.age = age;
            System.out.println("person.setAge: "+ age);
        }
    
        public void setAddr(String addr) {
            this.addr = addr;
            System.out.println("person.setAddr: "+addr);
        }
    
        public Person() {
            System.out.println("constructor null");
        }
    
        public void p1(){
            System.out.println("this name:"+this.name+"  this age:"+this.age);
        }
    
    
        /*@Bean("p1")
        public Person getPerson(){
            System.out.println("自定义...");
            return new Person("zhuge",100,"wuhan");
        }*/
    }
    
    
    • 再次执行,main入口程序,我们将看到,spring初始化的bean会多了一个person

    • 在main程序中,获取car这个bean,打印其信息

     // 获取car这个bean对象,打印其对象信息
            System.out.println(context.getBean(Person.class));
    

    打印结果:

    Person(name=mp, age=10, addr=null)

    • 至此,结果显示我们在属性上的注解值成功的注入到了我们的bean对象

    2. 探究@Value注解的原理

    • 在上面的使用例子中,成功的注入了属性值; 那我们想一下,spring到底是怎么创建带有属性的对象,并进行管理的呢?
    • 我们先大胆猜测下,有以下几种可能
      1. @Value直接调用带有属性的构造函数,创建对象并交由spring来统一管理;
      2. 分两步,先调用空构造器创建一个属性为空的对象,再通过set方法来设置属性值;
    • 到底是哪一种,我们通过程序来验证…
    • 在new AnnotationConfigApplicationContext(MyConfig.class) 打上断点,debug模式走起…
    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    		this();  // 构造器,初始化AnnotatedBeanDefinitionReader和  ClassPathBeanDefinitionScanner并准备好5个sping系统需要的BeanDefinition.
    		register(annotatedClasses); // 注册我们的配置类AppConfig 对应的BeanDefinition,此时我们的beanFactory中有6个beanDefinitionName了
    		refresh(); // 重点流程
    	}
    
    • 这里发现,spring在管理bean的时候,不是直接就创建对象扔进对象池,而是先创建起对应的BeanDefinition,这个还不是真正的bean,还未创建对象.
    • 接着我们进入refresh()
    synchronized (this.startupShutdownMonitor) {
    			// Prepare this context for refreshing.
    			prepareRefresh();
    
    			// Tell the subclass to refresh the internal bean factory.
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    			// Prepare the bean factory for use in this context.
    			prepareBeanFactory(beanFactory);
    
    			try {
    				// Allows post-processing of the bean factory in context subclasses.
    				postProcessBeanFactory(beanFactory);
    
    				// Invoke factory processors registered as beans in the context.
    				invokeBeanFactoryPostProcessors(beanFactory);  // @1 说明
    
    				// Register bean processors that intercept bean creation.
    				registerBeanPostProcessors(beanFactory);  
    
    				// Initialize message source for this context.
    				initMessageSource();
    
    				// Initialize event multicaster for this context.
    				initApplicationEventMulticaster();
    
    				// Initialize other special beans in specific context subclasses.
    				onRefresh();
    
    				// Check for listener beans and register them.
    				registerListeners();
    
    				// Instantiate all remaining (non-lazy-init) singletons.
    				finishBeanFactoryInitialization(beanFactory);   // @2  说明
    
    				// Last step: publish corresponding event.
    				finishRefresh();  // 
    			}
    
    • @1说明:
    1. 会创建好spring需要的5个bean
    2. 根据@ComponentScan扫描的包路径,ClassPathBeanDefinitionScanner 去target根据文件系统找到对应的class文件,并根据是否有注解来判断,决定是否要加入到beanDefinitionNames 列表中,为后面初始化做准备.
    3. 所以,这里beanDefinitionNames 列表扫描会新增1个person -bean
    • @2 说明
    1. 实例化通过包扫描的bean, 实例化person对象,并完成属性注入,重点来了…
    • 继续断点,finishBeanFactoryInitialization(beanFactory);
    • -> 经过一系列判断后,调用beanFactory.preInstantiateSingletons(); 进行实例化.
    • -> 遍历BeanDefinitionNames来判断是否要创建bean,针对上面已经创建过的5个bean,见到单例池中存在,则不再创建,这里所有的bean都是单例.
    • 增加断点条件beanName.equals(“person”)
    • -> getBean(beanName); 继续调用

    Object sharedInstance = getSingleton(beanName); // 这里是否单例池缓存中取对象,由于之前没有创建,所以这里为null,流程继续往下走
    mbd.isSingleton() 为默认单例,开始创建实例

    • 关键的步骤: RootBeanDefinition
    • resolveBeanClass(mbd, beanName) 根据beanName获取class
    • instanceWrapper = createBeanInstance(beanName, mbd, args); 这里调用空构造器,创建一个空对象
    • 接下来,哪里实现了属性的注入呢? 来,继续往下走…
    • populateBean(beanName, mbd, instanceWrapper); 根据 instanceof InstantiationAwareBeanPostProcessor 判断结果,dp为AutowiredAnnotationBeanPostProcessor 类, --debug发现这个postProcessor的服务会处理@Autowired 和@Value来个注解
    • PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); 会做属性注入,继续debug进去.
    • 好,看到我们想要的代码了,postProcessProperties(PropertyValues pvs, Object bean, String beanName) 注入属性值,实际调用方法. metadata.inject(bean, beanName, pvs) ,继续debug深入.
    • 获取InjectedElement 集合,可以检查到两个注解属性,name age, 遍历属性字段,根据Field类做属性注入.从注解value中获取值
    • field.set(bean, value) 至此,完成了 属性的注入
    • debug信息查看person: Person(name=mp, age=10, addr=null) 好了,完成梳理.

    后记: 本次我初步梳理流程,后面会完善各个细节.

    2. 自定义实现@MyValue注解

    2.1 创建@MyValue注解类

    package com.mp.aop.annotation.day02.config;
    
    import java.lang.annotation.*;
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MyValue {
        String value() default "";
    }
    

    2.1 创建使用@MyValue注解的属性的类.

    package com.mp.aop.annotation.day02.service;
    
    import com.mp.aop.annotation.day02.config.MyValue;
    import lombok.Data;
    import org.springframework.stereotype.Component;
    
    /**
     * ClassName: Car
     * Function:  TODO
     * Date:      2020-04-12 09:12
     * author     mp
     * version    V1.0
     */
    @Component
    @Data
    public class Car {
    
        @MyValue(value = "布加迪")
        String name;
    
        @MyValue(value = "6666w")
        String price;
    
        static {
            System.out.println("static car...");
        }
    
    }
    
    

    2.3 自定义后置处理器 MyPostProcessor

    我这边采用的策略是,在完成spring bean构建之后,通过beanFactory获取对应的bean,做字段的依赖注入

    package com.mp.aop.annotation.day02.service;
    
    import com.mp.aop.annotation.day02.config.MyValue;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.SmartInitializingSingleton;
    import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    
    import java.util.stream.Stream;
    
    /**
     * ClassName: ServicePostProcess
     * Function:  TODO
     * Date:      2020-04-10 22:59
     * author     mp
     * version    V1.0
     */
    @Component
    public class MyPostProcess implements SmartInitializingSingleton,BeanFactoryPostProcessor {
        BeanFactory beanFactory;
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("this is factory...");
            this.beanFactory = beanFactory;
    
        }
    
        @Override
        public void afterSingletonsInstantiated() {
            System.out.println("process afterSingletons...");
    
            // 处理@MyValue注解
            Car car = beanFactory.getBean(Car.class);
            Stream.of(Car.class.getDeclaredFields())
                    .filter(field -> field.getAnnotation(MyValue.class) != null)
                    .forEach(field -> {
                        MyValue myValue = field.getAnnotation(MyValue.class);
                        try {
                            field.set(car,myValue.value());  // 属性注入.
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                        // 设置属性
    //                    System.out.println(field.getName());
    
                       // 
                        //1. 方法2,反射找到对应的set方法做属性的设置
                        /*String fieldName = field.getName();
                        Class<?> type = field.getType();
                        String setMethodName = "set".concat(fieldName.substring(0,1).toUpperCase()).concat(fieldName.substring(1));
                        try {
                            Method method = Car.class.getMethod(setMethodName, type);
                            method.invoke(car,myValue.value());
                        } catch (Exception e) {
                            e.printStackTrace();
                        }*/
    
                    });
    
            System.out.println("car: "+ car);
    
        }
    
    }
    
    

    打印结果: Car(name=布加迪, price=6666w) 完成自定义属性注解.

    • 这里需要重点说如一下,自定义后置处理器,实现SmartInitializingSingleton,BeanFactoryPostProcessor 接口,需要重写postProcessBeanFactory() 和 afterSingletonsInstantiated() 方法
    • 其中postProcessBeanFactory() 方法块,在sping初始化bean之前就会调用执行
    • afterSingletonsInstantiated() 方法会在完成bean的创建及管理之后执行.

    今天先记录到这里,后面再继续细节… 每天进步一点.

    展开全文
  • Java @Value注解的用处

    千次阅读 2021-10-26 15:07:19
    @Value注解是 Spring的注解,可以用来将外部的值动态注入到 Bean 中,在 @Value 注解中,可以使用 ${} 或 #{}。${} 与 #{} 的区别如下: (1)@Value("${}"):可以获取对应属性文件中定义的属性值。 (2)@Value...
  • @Value注解从配置文件中读取数组/集合 @Value设置默认值 @Value("#{}")的使用场景
  • @Value 注解用法

    千次阅读 2022-01-18 14:00:39
    @Value的用法
  • @value注解设置默认值

    千次阅读 2021-12-14 10:40:17
    如果配置文件中没有demo.num配置属性,启动时就会报错,spring加载不到此属性值。 @value("${demo.num}") 如果配置文件中没有demo.num配置属性,取默认值100。 @value("${demo.num:100}")
  • nacos配置接口地址——@value注解

    千次阅读 2021-08-11 10:20:38
    nacos nacos配置接口地址 @value nacos配置接口地址 @value注解,冒号前相当于是配置名,后面相当于是默认值 如果从nacos中读不到配置,就默认使用代码中的默认值 @value @Value("#{}"):获取 bean 的属性,或者调用...
  • @value 注解配置默认值

    千次阅读 2021-06-29 14:10:14
    @Value注解模式下读取配置文件中的参数配置值并注入属性值。代码如下: @Value("${system.webCurVersion}") private String webCurVersion; 在配置文件中未配置参数值(system.webCurVersion)或有其他项目依赖...
  • SpringBoot中@Value注解设置默认值

    千次阅读 2021-07-19 19:25:54
    在SpringBoot项目读取配置文件中读取值,我们会用到@Value注解来读取配置值,例如我们在配置文件中配置了服务器web域名为xxx.com的配置: server.web.domain=xxx.com 在代码中读取其配置项: @Value("${server.web....
  • Spring boot @Value注解详解

    千次阅读 2021-02-24 13:23:21
    Springboot通过@Value注解将配置文件中的属性注入到容器内组件中(可用在@Controller、@Service、@Configuration、@Component等Spring托管的类中) 1.普通字符串注入 例:yml中存在key: name: zs @Value注入 ...
  • =ccc 当我们想要在程序中使用时候,想当然的使用 @Value 注解去读取这个值,就像下面这种写法一样: @Value("${test.list}") private List testList; 你会发现程序直接报错了,报错信息如下: java.lang....
  • SpringBoot中@Value注解不能使用

    千次阅读 多人点赞 2021-05-27 10:15:31
    @Value注解在controller层使用时,总是报错Cannot find method value 在前后端分离的项目中,实现前端上传的图片保存在固定位置并将图片的url返回给前端的功能,需要在application.properties文件中设置下文件保存...
  • 1、@Value注解简介 Spring框架提供的@Value注解可以将外部的值动态注入到Bean中,@Value注解使用在字段、构造器参数和方法参数上。@Value可以指定属性取值的表达式,支持通过#{}使用SpringEL来取值,也支持使用${}...
  • =ccc 当我们想要在程序中使用时候,想当然的使用 @Value 注解去读取这个值,就像下面这种写法一样: @Value("${test.list}") private List testList; 你会发现程序直接报错了,报错信息如下: java.lang....
  • java的Spring中@Value注解的使用

    千次阅读 2021-01-23 15:23:03
    1、@Value注解作用 该注解作用的作用是将我们配置文件的属性读出来,有@Value("${}")和@Value("#{}")两种方式 2、@Value注解作用的两种方式  第一种方式@Value("${}"):在使用Springboot项目搭建的项目时,配置...
  • @Value注解获取不到配置值

    万次阅读 多人点赞 2020-03-02 00:48:57
    碰到过三种情况导致@Value获取不到配置值 变量被关键字static修饰 类没有使用@Component及其衍生标签修饰 在Bean初始化时构造方法中引用被@Value修饰的变量 如果不是以上三种情况那么这篇博文就没法给你提供...
  • 通常来说,我们都使用@Value注解来注入properties文件中的内容,注入集合类时,我们也使用@Value来注入。 properties文件中的内容如下: my.set=foo,bar my.list=foo,bar my.map={"foo": "bar"} 分别是我们要注入的...
  • spring的@Value注解使用

    万次阅读 多人点赞 2018-04-03 15:52:12
    昨天看到了springMVC的controller中的属性使用了@value注解,并且本人之前用的${}形式,看到别人用的#{}形式,特此记录下。 1.@Value注解作用 该注解的作用是将我们配置文件的属性读出来,有@Value(“${}”)和@...
  • SpringBoot中@Value注解默认值使用一、使用@Value注解的代码注意事项User.javaJunit测试UserTest.java测试结果 一、使用@Value注解的代码 注意事项 (1)注解修饰的变量不能是final、static。 (2)使用@Component...
  • spring mvc 的@Value注解使用中的坑——@Value神奇的不生效     @Value注解可以将已经加载的.properties或者.yml配置文件中的属性变量赋值给类中定义的变量。例如: //student.properties ...
  • 常见注解 @Value("#{${weixin.users}}") private Map<String, String> users; @Value("#{'${weixin.all_user}'.split(',')}") private List<String> weixinUserIds; weixin.users={liming:'oU2...
  • @value注解和@ConfigurationProperties注解的基本使用 基于@value读取默认配置 yml文件内容如下(装了STS插件以后即可直接使用,改后缀就行了) user: username: xiongda sex: man age: 20 school: name: ...
  • @value 注解注入静态变量

    千次阅读 2020-03-08 18:20:38
    普通变量在使用@value注解时,直接在变量上加 @value 注解,并通过 spring表达式写上想要获取的值,就可以将配置值注入到变量中。但如果是静态变量就无法这样注入,那么静态变量如何通过 @value 注解进行注入,这和...
  • Springboot中@value注解取不到值

    千次阅读 2021-02-07 22:38:46
    一般情况下,我们可以用@value注解从核心配置文件里获取参数的值,例如application.properties,application.yml文件等,但要注意以下几点: 一:能用注解获取的前提是必须将当前类交由spring容器来统一管理,一般用...
  • SpringBoot的@Value注解设置默认值

    万次阅读 2020-02-02 14:42:06
    在Spring Boot中,如果使用@Value注解对属性进行赋值,但如果在配置文件或启动参数中未指定对应的参数值,则会抛出异常。异常信息往往是对应注入属性的类实例化失败。 此时,需要对@Value对应的值进行配置,或设置...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 493,045
精华内容 197,218
关键字:

@value注解