本文内容

  1. @Resource实现依赖注入
  2. @Value详细使用
  3. @PostConstruct @PreDestroy的使用

@Resource实现依赖注入

前面章节介绍了使用@Autowired注入依赖的详细用法,感兴趣的可以翻看前面的文章。Spring 还支持通过在字段或 bean 的Setter方法上使用 JSR-250 @Resource 注解进行注入。

@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
// 指定名称
String name() default "";
}

基本使用

依赖组件定义

@Component
public class RepositoryA implements RepositoryBase {
} @Component
public class RepositoryB implements RepositoryBase {
}

使用@Resource注入依赖

@Component
public class Service1 {
// 字段
@Resource
private RepositoryA repositoryA; private RepositoryB repositoryB; // Setter方法
@Resource
public void setRepositoryB(RepositoryB repositoryB) {
this.repositoryB = repositoryB;
}
// ... }

运行测试

@org.junit.Test
public void test() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
Service1 service1 = context.getBean(Service1.class);
System.out.println(service1);
context.close();
}
// 结果
Service1{repositoryA=com.crab.spring.ioc.demo09.RepositoryA@1622f1b, repositoryB=com.crab.spring.ioc.demo09.RepositoryB@72a7c7e0}

@Resource@Autowired的区别

  1. 使用范围不同:@Resource使用范围是类字段和Setter方法,@Autowired范围更广:类字段、Setter方法、构造方法、方法参数。
  2. 当依赖缺失时,@Resource注入会报错,@Autowired(required=false)可以避免报错。
  3. @Resource有属性可以指定依赖的bean名称,@Autowired@Qulifier也可以达到该效果。

@Value详细使用

@Value 通常用于注入外部化属性。在字段或方法构造函数参数级别使用的注释,指示注解元素的默认值表达式。

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value { // 实际值表达式如 #{systemProperties.myProp}
// 或属性占位符如${my.app.myProp}
String value();
}

案例1

使用@Value注入配置属性值

@Component
public class MovieRecommender {
private final String catalog; public MovieRecommender(@Value("${catalog.name}") String catalog) {
this.catalog = catalog;
} // ...
}

外部配置文件demo10/application.properties

catalog.name=MovieCatalog

容器中通过@PropertySource配置文件资源

@Configuration
@ComponentScan(basePackages = "com.crab.spring.ioc.demo10")
@PropertySource("classpath:demo10/application.properties")
public class AppConfig { }

运行测试

@org.junit.Test
public void test() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
MovieRecommender recommender = context.getBean(MovieRecommender.class);
System.out.println(recommender);
context.close();
}
// 结果
MovieRecommender{catalog='MovieCatalog'}

从结果看,外部配置文件中的属性值成功注入。

案例2:无法解析属性值

Spring 提供了一个默认的宽松嵌入式值解析器。它将尝试解析属性值,如果无法解析,属性名称(例如 ${catalog.name})将作为值注入。

将配置文件内容修改如下

xxx.catalog.name=MovieCatalog

运行同样上一个案例的测试,可以发现无法解析到属性值则将属性名称注入了。

MovieRecommender{catalog='${catalog.name}'}

如果需要严格控制不存在的值,可以声明一个 PropertySourcesPlaceholderConfigurer并注入到Spring中

@Configuration
@ComponentScan(basePackages = "com.crab.spring.ioc.demo10")
@PropertySource("classpath:demo10/application.properties")
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}

运行同样的测试程序,此时严格模式下会抛出异常

java.lang.IllegalArgumentException: Could not resolve placeholder 'catalog.name' in value "${catalog.name}"

扩展: Spring Boot 默认配置一个 PropertySourcesPlaceholderConfigurer bean,它将从 application.properties 和 application.yml 文件中获取属性。

案例3: 提供默认值

可以提供默认值在无法解析属性值作为属性值注入。

@Component
public class MovieRecommender {
private final String catalog; public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
this.catalog = catalog;
}
}

此时配置文件如下

xxx.catalog.name=MovieCatalog

运行同样的测试程序,注入的是默认值

MovieRecommender{catalog='defaultCatalog'}

案例4:支持SpEL表达式

SpEL表达式后续专门讲,此处不展开。

@PostConstruct @PreDestroy的使用

Spring支持生命周期回调接口注解,@PostConstruct @PreDestroy是JSR 250提供的。

@PostConstruct 注解的方法在容器初始化化bean的阶段回调。

@PostConstruct 注解的方法在容器销毁bean的阶段回调。

直接来看案例

@Component
public class FoodRecommender { @PostConstruct
public void onInit() {
System.out.println("FoodRecommender onInit");
}
@PreDestroy
public void onDestroy() {
System.out.println("FoodRecommender onDestroy");
} }

注解的配置相当于下面的xml配置文件

<bean class="com.crab.spring.ioc.demo10.FoodRecommender" id="foodRecommender"
init-method="onInit"
destroy-method="onInit"></bean>

运行下测试程序并观察结果

@org.junit.Test
public void test1() {
System.out.println("开始初始化容器");
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
FoodRecommender bean = context.getBean(FoodRecommender.class);
System.out.println("使用容器中");
System.out.println("销毁容器");
context.close();
}
// 结果
开始初始化容器
FoodRecommender onInit
使用容器中
销毁容器
FoodRecommender onDestroy

总结

本文介绍@Resource实现依赖注入,@Value详细使用和@PostConstruct @PreDestroy的使用。

本篇源码地址: https://github.com/kongxubihai/pdf-spring-series/tree/main/spring-series-ioc/src/main/java/com/crab/spring/ioc/demo09

知识分享,转载请注明出处。学无先后,达者为先!

Spring系列12: `@Value` `@Resource` `@PostConstruct` `@PreDestroy` 详解的更多相关文章

  1. 精通awk系列(12):awk getline用法详解

    回到: Linux系列文章 Shell系列文章 Awk系列文章 getline用法详解 除了可以从标准输入或非选项型参数所指定的文件中读取数据,还可以使用getline从其它各种渠道获取需要处理的数据 ...

  2. spring的IOC,DI及案例详解

    一:spring的基本特征 Spring是一个非常活跃的开源框架:它是一个基于Core来架构多层JavaEE系统的框架,它的主要目的是简化企业开发.Spring以一种非侵入式的方式来管理你的代码,Sp ...

  3. spring在IoC容器中装配Bean详解

    1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean ...

  4. (转)java之Spring(IOC)注解装配Bean详解

    java之Spring(IOC)注解装配Bean详解   在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看 ...

  5. Spring Boot 启动(二) 配置详解

    Spring Boot 启动(二) 配置详解 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Boot 配置 ...

  6. 转载 Spring、Spring MVC、MyBatis整合文件配置详解

    Spring.Spring MVC.MyBatis整合文件配置详解   使用SSM框架做了几个小项目了,感觉还不错是时候总结一下了.先总结一下SSM整合的文件配置.其实具体的用法最好还是看官方文档. ...

  7. Java 8系列之Stream的基本语法详解

    本文转至:https://blog.csdn.net/io_field/article/details/54971761 Stream系列: Java 8系列之Stream的基本语法详解 Java 8 ...

  8. Python操作redis系列以 哈希(Hash)命令详解(四)

    # -*- coding: utf-8 -*- import redis #这个redis不能用,请根据自己的需要修改 r =redis.Redis(host=") 1. Hset 命令用于 ...

  9. SpringBoot系列(六)集成thymeleaf详解版

    SpringBoot系列(六)集成thymeleaf详解版 1. thymeleaf简介  1. Thymeleaf是适用于Web和独立环境的现代服务器端Java模板引擎.  2. Thymeleaf ...

随机推荐

  1. CentOS 系统 查看 cpu核数

    转载自 :Centos下查看cpu核数 - 韩憨 - 博客园 (cnblogs.com) 1.概念物理CPU:实际Server中插槽上的CPU个数.物理cpu数量:可以数不重复的 physical i ...

  2. unittest_skip跳过用例执行(3)

    在执行测试用例时,有时候有些用例是不需要执行的,比如版本迭代用例弃用,测试周期短只需要执行优先级高的用例,那我们怎么办呢?难道删除这些用例?那下次执行时如果又需要执行这些用例时,又把它补回来?这样操作 ...

  3. Selenium_使用switch_to.window方法处理窗口切换(12)

    想一下这样的场景,打开页面A点击一个链接,在一个新的窗口打开页面B,由于之前的driver实例对象在页面A,但是你接下来操作的元素在页面B中,此时脚本就会报错找不到元素.该场景需要使用到seleniu ...

  4. 在使用django admin的后台搜索时报错

    在使用django admin的后台搜索时报错 百度说在search_fields中定义了非字符串字段,最后发现author引用了外键 解决办法: 有外健时应写成: 本表外键字段__外键所在表所需要查 ...

  5. java POJO中 Integer 和 int 的不同,用int还是用Integer

    https://www.jianshu.com/p/ff535284916f [int和Integer的区别] int是java提供的8种原始类型之一,java为每个原始类型提供了封装类,Intege ...

  6. java.exe and -classpth or -cp

    mydirname=$(dirname $0) java -cp $classes_dir:$lib_dir/*:$config_dir -Doracle.net.wallet_location=${ ...

  7. Zuul的应用

    一.介绍 注:Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制.但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了. 二.依赖 <dependency ...

  8. v4l2数据获取流程

    V4L2数据获取流程 整个过程相关的数据结构有如下几个: struct v4l2_capability m_cap; /* 驱动能力 */ struct v4l2_format m_fmt; /* 数 ...

  9. 闯祸了,生成环境执行了DDL操作《死磕MySQL系列 十四》

    由于业务随着时间不停的改变,起初的表结构设计已经满足不了如今的需求,这时你是不是想那就加字段呗!加字段也是个艺术活,接下来由本文的主人咔咔给你吹. 试想一下这个场景 事务A在执行一个非常大的查询 事务 ...

  10. 一文搞清楚 DNS 的来龙去脉

    目录 美国霸权 ICANN:互联网界的联合国 IP 地址分配 域名解析架构 分层架构: DNS 缓存: 根 DNS 服务器: 顶级 DNS 服务器(TLD): 权威 DNS 服务器: 本地 DNS: ...