目录
- 1 怎么使用`@Resource`?
- 1.0 实验环境
- 1.1 通过字段注入依赖
- 1.2 bean property setter methods (setter方法)
- 2 打破岁月静好(`@Resource takes a name attribute`)
- 2.1 结论
- 2.2 那我不指定呢?【结论:又能正常执行了】
- 2.2.1 default name
- 3 总结【@Resource是by-name来注入依赖的】
1 怎么使用@Resource
?
参考官方文档
1.0 实验环境
- 项目结构:
- 代码
@Configuration
public class LearnResourceConfig {@Beanpublic MovieFinder movieFinder() {return new MovieFinder();}
}public class MovieFinder {public void sayHello() {System.out.println(this.getClass().getSimpleName() + ", hello");}
}
1.1 通过字段注入依赖
- SimpleMovieLister
@Component
public class SimpleMovieLister {@Resource(name = "movieFinder")private MovieFinder movieFinder;public void sayHello() {movieFinder.sayHello();System.out.println(this.getClass().getSimpleName() + ", hello");}
}
- Application
@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
@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
@Configuration
public class LearnResourceConfig {/*MovieFinder这个Bean的名称从movieFinder变成了myMovieFinder*/@Beanpublic 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
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为字段名。
@Component
public class SimpleMovieLister {@Resourceprivate MovieFinder forrestMovieFinder;...
}
- 如果是setter方法注入(setXXX),那么defaultName为XXX
@Component
public class SimpleMovieLister {private MovieFinder movieFinder;@Resourcepublic void setJerryMovieFinder(MovieFinder movieFinder) {this.movieFinder = movieFinder;}...
}
3 总结【@Resource是by-name来注入依赖的】
- 如果@Resource注解中指定了name属性,那么Spring只会根据name属性的值去找bean,找不到则报错。
- 如果@Resource注解没有指定name属性,那么会根据字段名或setter方法推断一个默认名字。
- 如果根据默认名字找到了bean,那就注入这个bean。
- 如果根据默认名字找不到bean,那就降级为根据类型去找bean。
- 如果还找不到,那就报错。