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;
  }
}
目录
相关文章
|
11月前
|
缓存 监控 Java
SpringBoot @Scheduled 注解详解
使用`@Scheduled`注解实现方法周期性执行,支持固定间隔、延迟或Cron表达式触发,基于Spring Task,适用于日志清理、数据同步等定时任务场景。需启用`@EnableScheduling`,注意线程阻塞与分布式重复问题,推荐结合`@Async`异步处理,提升任务调度效率。
1595 128
|
10月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
800 2
|
11月前
|
XML Java 数据格式
常用SpringBoot注解汇总与用法说明
这些注解的使用和组合是Spring Boot快速开发和微服务实现的基础,通过它们,可以有效地指导Spring容器进行类发现、自动装配、配置、代理和管理等核心功能。开发者应当根据项目实际需求,运用这些注解来优化代码结构和服务逻辑。
699 12
|
11月前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
608 0
探索Spring Boot的@Conditional注解的上下文配置
|
11月前
|
智能设计 Java 测试技术
Spring中最大化@Lazy注解,实现资源高效利用
本文深入探讨了 Spring 框架中的 `@Lazy` 注解,介绍了其在资源管理和性能优化中的作用。通过延迟初始化 Bean,`@Lazy` 可显著提升应用启动速度,合理利用系统资源,并增强对 Bean 生命周期的控制。文章还分析了 `@Lazy` 的工作机制、使用场景、最佳实践以及常见陷阱与解决方案,帮助开发者更高效地构建可扩展、高性能的 Spring 应用程序。
420 0
Spring中最大化@Lazy注解,实现资源高效利用
|
XML Java 数据格式
|
XML Java 数据格式
spring@PropertySource用法
测试例子 package com.hjzgg.auth.config; import org.springframework.beans.factory.annotation.Autowired; import org.
1092 0
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1462 0
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
1395 0
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
602 0