• 深入浅出Spring(25)


    参考链接

    官方文档

    这些问题你都知道吗?

    1. @Value的用法
    2. @Value数据来源
    3. @Value动态刷新的问题

    @Value的用法

    源码

    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Value {
    	String value();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    修饰范围:字段,方法,方法参数,注解。

    案例1 解析默认配置文件内容

    @Component
    public class DbConfig {
    
        @Value("${jdbc.url}")
        private String url;
    
        @Value("${jdbc.username}")
        private String username;
    
        @Value("${jdbc.password}")
        private String password;
        
    	//省略
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如果application.yml和properties同时存在会解析properties。

    案例2 指定配置文件解析

    valued1.properties

    jdbc.url=v1Url
    jdbc.username=v1Name
    jdbc.password=v1password
    
    • 1
    • 2
    • 3
    @Component
    @PropertySource("classpath:valued1.properties")
    public class DbConfig {
    
        @Value("${jdbc.url}")
        private String url;
    
        @Value("${jdbc.username}")
        private String username;
    
        @Value("${jdbc.password}")
        private String password;
    
    	//省略
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    PropertySource

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Repeatable(PropertySources.class)
    public @interface PropertySource {
    
    	String name() default "";
    
    	String[] value();
    
    	boolean ignoreResourceNotFound() default false;
    
    	String encoding() default "";
    	
    	Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    修饰在类型上,有@Repeatable重复使用注解。
    既然允许重复,我们修改新增一个配置文件 valued2.properties

    jdbc.url=v2
    jdbc.username=v2name
    jdbc.password=v3name
    
    • 1
    • 2
    • 3

    在DbConfig上面,并且修改顺序查看输出验证以哪一个配置文件为准。

    @PropertySource("classpath:valued2.properties")
    @PropertySource("classpath:valued1.properties")
    
    • 1
    • 2

    经过测试,以最下面一个读取的配置文件为准。

    @Value数据来源

    省略 get、set、tostring

    @Component
    public class MailConfig {
    
        @Value("${mail.host}")
        private String host;
    
        @Value("${mail.username}")
        private String username;
    
        @Value("${mail.password}")
        private String password;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    配置类

    @Configuration
    @ComponentScan
    public class Client {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            java.util.Map<String, Object> mailInfoFromDb = getMailInfoFromDb();
            MapPropertySource mailPropertySource = new MapPropertySource("mail", mailInfoFromDb);
            context.getEnvironment().getPropertySources().addFirst(mailPropertySource);
            context.register(Client.class);
            context.refresh();
            MailConfig mailConfig = context.getBean(MailConfig.class);
            System.out.println(mailConfig);
        }
    
        public static Map<String, Object> getMailInfoFromDb() {
            Map<String, Object> result = new HashMap<>();
            result.put("mail.host", "smtp.qq.com");
            result.put("mail.username", "路人");
            result.put("mail.password", "123");
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    org.springframework.beans.factory.config.scope

    深入浅出Spring注解@Scope、@DependsOn、@ImportResource、@Lazy

    在这篇中我们没有说 ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT,这个参数为TARGET_CLASS的作用。

    先来看一下枚举上的注释 Create a class-based proxy (uses CGLIB). 创建一个基于CGLIB代理的类。

    org.springframework.cloud.context.config.annotation.RefreshScope

    package org.springframework.cloud.context.config.annotation;
    
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Scope("refresh")
    @Documented
    public @interface RefreshScope {
    
    	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    我们在nacos中就使用了这个注解实现配置文件更新后刷新。

    在这里插入图片描述

    org.springframework.beans.factory.config.Scope 接口

    public interface Scope {
    	//获取对象
    	Object get(String name, ObjectFactory<?> objectFactory);
    	//删除对象
    	@Nullable
    	Object remove(String name);
    	//注册销毁回调
    	void registerDestructionCallback(String name, Runnable callback);
    	//根据给定的key解析上下文
    	@Nullable
    	Object resolveContextualObject(String key);
    	
    	@Nullable
    	String getConversationId();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    实现@Value动态刷新

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Scope("MyRefreshScope")
    @Documented
    public @interface MyRefreshScope {
    
        ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    public class MyRefreshScopeConfig implements org.springframework.beans.factory.config.Scope {
    
        @Override
        public Object get(String name, ObjectFactory<?> objectFactory) {
            System.out.println("BeanMyScope >>>>>>>>> get:" + name);
            return objectFactory.getObject(); //@3
        }
    
        @Override
        public Object remove(String name) {
            return null;
        }
    
        @Override
        public void registerDestructionCallback(String name, Runnable callback) {
    
        }
    
        @Override
        public Object resolveContextualObject(String key) {
            return null;
        }
    
        @Override
        public String getConversationId() {
            return null;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    @Component
    @MyRefreshScope
    public class User {
    
        private String username;
    
        public User() {
            System.out.println("---------创建User对象" + this);
            this.username = UUID.randomUUID().toString();
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    @ComponentScan
    @Configuration
    public class Client {
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.getBeanFactory().registerScope("MyRefreshScope", new MyRefreshScopeConfig());
            context.register(Client.class);
            context.refresh();
    
            System.out.println("从容器中获取User对象");
            User user = context.getBean(User.class);
            System.out.println("user对象的class为:" + user.getClass());
    
            System.out.println("多次调用user的getUsername感受一下效果\n");
            for (int i = 1; i <= 3; i++) {
                System.out.println(String.format("********\n第%d次开始调用getUsername", i));
                System.out.println(user.getUsername());
                System.out.println(String.format("第%d次调用getUsername结束\n********\n", i));
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    从容器中获取User对象
    user对象的class为:class com.example.lurenjia.spring.c24.d3.User$$EnhancerBySpringCGLIB$$4e23e0c6
    多次调用user的getUsername感受一下效果
    
    ********1次开始调用getUsername
    BeanMyScope >>>>>>>>> get:scopedTarget.user
    ---------创建User对象com.example.lurenjia.spring.c24.d3.User@3e58a80e
    adb8ff42-e42c-4949-9662-79bd40bbb063
    第1次调用getUsername结束
    ********
    
    ********2次开始调用getUsername
    BeanMyScope >>>>>>>>> get:scopedTarget.user
    ---------创建User对象com.example.lurenjia.spring.c24.d3.User@9597028
    fb145915-a3bf-40e3-8c51-c987f9756b05
    第2次调用getUsername结束
    ********
    
    ********3次开始调用getUsername
    BeanMyScope >>>>>>>>> get:scopedTarget.user
    ---------创建User对象com.example.lurenjia.spring.c24.d3.User@6069db50
    a918c35d-0bff-4148-8d17-4dcfc2b29a77
    第3次调用getUsername结束
    ********
    
    
    进程已结束,退出代码为 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    官方文档用法

    https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-value-annotations

    官方示例一:注入catalog.name

    @Component
    public class MovieRecommender {
    
        private final String catalog;
    
        public MovieRecommender(@Value("${catalog.name}") String catalog) {
            this.catalog = catalog;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    优化算法|MOAVOA:一种新的多目标人工秃鹰优化算法(Matlab代码实现)
    python3安装opencv
    C#/.NET该如何自学入门?
    JavaScript模块化:提高代码可维护性和可重用性的利器
    视频号挂公众号链接引流到公众号还能加,好消息来了
    VS 中的生成事件
    【国科大——矩阵分析与应用】使用高斯消元法,测试二元一次方程系数产生的误差
    Matlab:解决错误:未定义的函数或变量
    从数据、产品、管理的视角探讨MES管理系统
    信息系统项目管理师第四版学习笔记——组织通用治理
  • 原文地址:https://blog.csdn.net/qq_37151886/article/details/127571016