Spring注解驱动开发二组件赋值-@Value和@PropertySource及XXXXAware接口

简介: Spring注解驱动开发二组件赋值-@Value和@PropertySource及XXXXAware接口

【1】@Value和@PropertySource

① @Value

该注解可以直接给bean的属性赋值(不支持JSR303校验),具体有以下几种用法:


  • 基本数值
  • 可以写SpEL; #{}
  • 可以写${};取出配置文件【properties】中的值(在运行环境变量里面的值)



Bean类如下:

public class Person {
  @Value("张三")
  private String name;
  @Value("#{20-2}")
  private Integer age;
  @Value("${person.nickName}")
  private String nickName;
  //...
}


注意到,nickName属性使用了配置文件中的值,那么如何引入配置文件呢?


② @PropertySource

该注解读取外部配置文件中的k/v保存到运行的环境变量中,加载完外部的配置文件以后使用${}取出配置文件的值。

注解接口如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {
   // 声明资源文件名字
  String name() default "";
   // 声明需要加在的资源文件位置,例如classpath:/com/myco/app.properties
   // 或者 file:/path/to/file,不支持通配符,必须是确切的文件路径
   // 可以使用${...}
  String[] value();
   // 声明如果查找资源文件失败,是否忽略
   // 如果资源文件是可选的,那么建议设置为true
   // 默认是false
  boolean ignoreResourceNotFound() default false;
   // 资源文件字符编码,如"UTF-8"
  String encoding() default "";
   // 指定一个自定义的PropertySourceFactory
  Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
}

配置类如下:

@PropertySource(value={"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {
  @Bean
  public Person person(){
    return new Person();
  }
}

测试如下:

public class IOCTest_PropertyValue {
  AnnotationConfigApplicationContext applicationContext = 
  new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
  @Test
  public void test01(){
    printBeans(applicationContext);
    System.out.println("=============");
    Person person = (Person) applicationContext.getBean("person");
    System.out.println(person);
    //配置文件中的值存在于环境中,可以使用如下方式获取
    ConfigurableEnvironment environment = applicationContext.getEnvironment();
    String property = environment.getProperty("person.nickName");
    System.out.println(property);
    applicationContext.close();
  }
  private void printBeans(AnnotationConfigApplicationContext applicationContext){
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    for (String name : definitionNames) {
      System.out.println(name);
    }
  }
}

测试结果如下:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfigOfPropertyValues
person
=============
Person [name=张三, age=18, nickName=小李四]
小李四

从Properties文件中取值得三种方式:

@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
  @Value("${db.user}")//第一种,成员属性 @Value
  private String user;
  private StringValueResolver valueResolver;
  private String  driverClass;
  @Bean
  public Yellow yellow(){
    return new Yellow();
  }
  // 第二种,参数 @Value
  @Profile("test")
  @Bean("testDataSource")
  public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
    // 第二种,参数 @Value
    ComboPooledDataSource dataSource = new ComboPooledDataSource();
    dataSource.setUser(user);
    dataSource.setPassword(pwd);
    dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
    dataSource.setDriverClass(driverClass);
    return dataSource;
  }
// 第三种,使用值解析器,从环境中获取值。
  @Override
  public void setEmbeddedValueResolver(StringValueResolver resolver) {
    // TODO Auto-generated method stub
    this.valueResolver = resolver;
    driverClass = valueResolver.resolveStringValue("${db.driverClass}");
  }
}

【2】@Autowired @Resource 和 @Inject


【3】实现XxxAware接口,将Spring底层组件注入bean

自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx)。


自定义组件实现xxxAware接口,在创建对象的时候,会调用接口规定的方法注入相关组件。

每一个xxxAware都有一个对应的xxxProcessor后置处理器来实现其功能。

ApplicationContextAware==》ApplicationContextAwareProcessor;

自定义bean类如下:

@Component
public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware {
  private ApplicationContext applicationContext;
  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    System.out.println("传入的ioc:"+applicationContext);
    this.applicationContext = applicationContext;
  }
  @Override
  public void setBeanName(String name) {
    System.out.println("当前bean的名字:"+name);
  }
  @Override
  public void setEmbeddedValueResolver(StringValueResolver resolver) {
    String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}");
    System.out.println("解析的字符串:"+resolveStringValue);
  }
}


测试如下:

当前bean的名字:red
解析的字符串:你好 Windows 7 我是 360
传入的ioc:org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347: 
startup date [Tue Apr 10 11:09:18 CST 2018]; root of context hierarchy


后置处理器实现源码:

ApplicationContextAwareProcessor 是一个bean后置处理器实现类,将ApplicationContext 传递给那些实现了EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware及ApplicationContextAware接口的bean。


被实现的接口按照上述顺序得到满足。应用程序上下文将自动向其基础bean工厂注册。应用程序不直接使用它。


这个过程可以参考AbstractApplicationContext#refresh()的方法。

class ApplicationContextAwareProcessor implements BeanPostProcessor {
  private final ConfigurableApplicationContext applicationContext;
  private final StringValueResolver embeddedValueResolver;
   // 创建一个ApplicationContextAwareProcessor 
  public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
    this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
  }
  @Override
  public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    AccessControlContext acc = null;
    if (System.getSecurityManager() != null &&
        (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
            bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
            bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
      acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    }
    if (acc != null) {
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
        @Override
        public Object run() {
          invokeAwareInterfaces(bean);
          return null;
        }
      }, acc);
    }
    else {
    // 核心方法
      invokeAwareInterfaces(bean);
    }
    return bean;
  }
// 判断bean的类型,然后传递applicationContext
  private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof Aware) {
      if (bean instanceof EnvironmentAware) {
        ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
      }
      if (bean instanceof EmbeddedValueResolverAware) {
        ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
      }
      if (bean instanceof ResourceLoaderAware) {
        ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
      }
      if (bean instanceof ApplicationEventPublisherAware) {
        ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
      }
      if (bean instanceof MessageSourceAware) {
        ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
      }
      if (bean instanceof ApplicationContextAware) {
        ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
      }
    }
  }
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) {
    return bean;
  }
}
目录
相关文章
|
15天前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
36 0
|
22天前
|
XML JSON Java
SpringBoot必须掌握的常用注解!
SpringBoot必须掌握的常用注解!
45 4
SpringBoot必须掌握的常用注解!
|
17天前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
39 5
|
24天前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
35 1
|
18天前
|
存储 安全 Java
springboot当中ConfigurationProperties注解作用跟数据库存入有啥区别
`@ConfigurationProperties`注解和数据库存储配置信息各有优劣,适用于不同的应用场景。`@ConfigurationProperties`提供了类型安全和模块化的配置管理方式,适合静态和简单配置。而数据库存储配置信息提供了动态更新和集中管理的能力,适合需要频繁变化和集中管理的配置需求。在实际项目中,可以根据具体需求选择合适的配置管理方式,或者结合使用这两种方式,实现灵活高效的配置管理。
13 0
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
177 2
|
3月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
|
16天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
27 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
12天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
25 2
下一篇
无影云桌面