正确使用@Resource

目录

  • [1 怎么使用`@Resource`?](#1 怎么使用@Resource?)
    • [1.0 实验环境](#1.0 实验环境)
    • [1.1 通过字段注入依赖](#1.1 通过字段注入依赖)
    • [1.2 bean property setter methods (setter方法)](#1.2 bean property setter methods (setter方法))
  • [2 打破岁月静好(`@Resource takes a name attribute`)](#2 打破岁月静好(@Resource takes a name attribute))
    • [2.1 结论](#2.1 结论)
    • [2.2 那我不指定呢?【结论:又能正常执行了】](#2.2 那我不指定呢?【结论:又能正常执行了】)
      • [2.2.1 default name](#2.2.1 default name)
  • [3 总结【@Resource是by-name来注入依赖的】](#3 总结【@Resource是by-name来注入依赖的】)

1 怎么使用@Resource

参考官方文档

1.0 实验环境

  • 项目结构:
  • 代码
java 复制代码
@Configuration
public class LearnResourceConfig {
    @Bean
    public MovieFinder movieFinder() {
        return new MovieFinder();
    }
}

public class MovieFinder {
    public void sayHello() {
        System.out.println(this.getClass().getSimpleName() + ", hello");
    }
}

1.1 通过字段注入依赖

  • SimpleMovieLister
java 复制代码
@Component
public class SimpleMovieLister {
    @Resource(name = "movieFinder")
    private MovieFinder movieFinder;

    public void sayHello() {
        movieFinder.sayHello();
        System.out.println(this.getClass().getSimpleName() + ", hello");
    }
}
  • Application
java 复制代码
@ComponentScan
public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Application.class);
        Arrays.stream(applicationContext.getBeanDefinitionNames()).forEach(System.out::println);
        System.out.println("---------------------------------------------------------------");
        SimpleMovieLister simpleMovieLister = applicationContext.getBean(SimpleMovieLister.class);
        simpleMovieLister.sayHello();
    }
}

/*
org.springframework.context.event.internalEventListenerFactory
application
simpleMovieLister
learnResourceConfig
movieFinder
---------------------------------------------------------------
MovieFinder, hello
SimpleMovieLister, hello
*/

1.2 bean property setter methods (setter方法)

  • SimpleMovieLister
java 复制代码
@Component
public class SimpleMovieLister {
    private MovieFinder movieFinder;

    @Resource(name = "movieFinder")
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    public void sayHello() {
        movieFinder.sayHello();
        System.out.println(this.getClass().getSimpleName() + ", hello");
    }
}
  • SimpleMovieLister打上了@Component注解,因此,在Spring的眼中,这是一个bean。
    • movieFinder是这个bean的property
    • 这个property提供了setter方法
  • 所以,这称为在"bean property setter methods"上用@Resource注解注入依赖。

2 打破岁月静好(@Resource takes a name attribute

  • 修改LearnResourceConfig
java 复制代码
@Configuration
public class LearnResourceConfig {
	/*
	MovieFinder这个Bean的名称从movieFinder变成了myMovieFinder
	*/
    @Bean
    public MovieFinder myMovieFinder() {
        return new MovieFinder();
    }
}
  • 无论是字段注入还是setter方法注入,都没法运行了。报错:No bean named 'movieFinder' available

2.1 结论

  • 如果@Resource注解中指定了name属性,那么Spring只会根据name属性的值去找bean,找不到则报错。

2.2 那我不指定呢?【结论:又能正常执行了】

  • 如果@Resource注解没有指定name属性,那么会根据字段名或setter方法推断一个默认名字。
    • 如果根据默认名字找到了bean,那就注入这个bean。
    • 如果根据默认名字找不到bean,那就降级为根据类型去找bean。
    • 如果还找不到,那就报错。

2.2.1 default name

  • org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ResourceElement#ResourceElement
java 复制代码
public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
		super(member, pd);
		Resource resource = ae.getAnnotation(Resource.class);
		String resourceName = resource.name();
		Class<?> resourceType = resource.type();
		this.isDefaultName = !StringUtils.hasLength(resourceName);
		if (this.isDefaultName) {
			resourceName = this.member.getName();
			if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
				resourceName = Introspector.decapitalize(resourceName.substring(3));
			}
		}
		...
  • 如果是字段注入,那么defaultName为字段名。
java 复制代码
@Component
public class SimpleMovieLister {
    @Resource
    private MovieFinder forrestMovieFinder;

	...
}
  • 如果是setter方法注入(setXXX),那么defaultName为XXX
java 复制代码
@Component
public class SimpleMovieLister {
    private MovieFinder movieFinder;

    @Resource
    public void setJerryMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    ...
}

3 总结【@Resource是by-name来注入依赖的】

  • 如果@Resource注解中指定了name属性,那么Spring只会根据name属性的值去找bean,找不到则报错。
  • 如果@Resource注解没有指定name属性,那么会根据字段名或setter方法推断一个默认名字。
    • 如果根据默认名字找到了bean,那就注入这个bean。
    • 如果根据默认名字找不到bean,那就降级为根据类型去找bean。
    • 如果还找不到,那就报错。
相关推荐
让你三行代码QAQ7 小时前
SpringAI-Advisors
spring·ai编程
杰哥哥不是个好叔叔7 小时前
【Spring AI】Spring AI 2.0.1 新特性袭来
java·人工智能·spring
落魄实习生8 小时前
Spring AI Alibaba入门-生态集成
java·人工智能·spring
山鬼龙王10 小时前
从源码角度剖析:Spring如何用三级缓存解决循环依赖
spring
MetaLite11 小时前
Spring-MVC微服务接口怎么分层-网关Controller与Service边界
spring·微服务·mvc
大模型码小白11 小时前
Spring AI 框架中集成 MCP 的完整指南:从服务端到客户端的全流程实践
大数据·运维·数据库·人工智能·python·sql·spring
小江的记录本12 小时前
【ORM 框架】MyBatis-Plus 核心特性、条件构造器、分页插件、乐观锁插件(附《思维导图》、《问题排查与实践清单》和《面试高频考点汇总》)
java·windows·spring boot·python·spring·面试·mybatis
小江的记录本12 小时前
【ORM框架】MyBatis核心原理、ORM思想、MyBatis vs JPA
java·数据库·后端·spring·spring cloud·oracle·mybatis
卓怡学长1 天前
w176基于SpringBoot的医院管理系统
java·spring boot·spring·maven·intellij-idea
大模型码小白1 天前
Spring AI Tool 实现自然语言操作 MySQL 数据库详解
服务器·开发语言·数据库·人工智能·python·mysql·spring