kongxubihai

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

本文内容

  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

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

posted on 2022-02-15 21:42  kongxubihai  阅读(565)  评论(0编辑  收藏  举报