@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String value();
}
修饰范围:字段,方法,方法参数,注解。
@Component
public class DbConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
//省略
}
如果application.yml和properties同时存在会解析properties。
valued1.properties
jdbc.url=v1Url
jdbc.username=v1Name
jdbc.password=v1password
@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;
//省略
}
@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;
}
修饰在类型上,有@Repeatable重复使用注解。
既然允许重复,我们修改新增一个配置文件 valued2.properties
jdbc.url=v2
jdbc.username=v2name
jdbc.password=v3name
在DbConfig上面,并且修改顺序查看输出验证以哪一个配置文件为准。
@PropertySource("classpath:valued2.properties")
@PropertySource("classpath:valued1.properties")
经过测试,以最下面一个读取的配置文件为准。
省略 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;
}
配置类
@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;
}
}
深入浅出Spring注解@Scope、@DependsOn、@ImportResource、@Lazy
在这篇中我们没有说 ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT,这个参数为TARGET_CLASS的作用。
先来看一下枚举上的注释 Create a class-based proxy (uses CGLIB). 创建一个基于CGLIB代理的类。
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;
}
我们在nacos中就使用了这个注解实现配置文件更新后刷新。

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();
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Scope("MyRefreshScope")
@Documented
public @interface MyRefreshScope {
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
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;
}
}
@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;
}
}
@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));
}
}
}
从容器中获取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
官方示例一:注入catalog.name
@Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(@Value("${catalog.name}") String catalog) {
this.catalog = catalog;
}
}