这个问题一听上去好像挺刁钻的,其实逻辑很简单,但很多人因为日常没注意,就容易掉坑里。我就拿个小 demo 来说明。
先说两个注解的作用
@Component:直接标在类上,Spring 做包扫描的时候会把这个类注册成 bean。
@Bean:一般写在方法上,方法的返回值会注册成 bean,方法名就是 bean 的名字,除非你自己指定。
所以一个是类级别的,一个是方法级别的,功能上其实没冲突。
demo 示例
我写了个最简单的例子:
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
publicclass MyService {
public String hello() {
return"hello from component";
}
@Bean
public Helper helper() {
returnnew Helper();
}
publicstaticclass Helper {
public String help() {
return"i am helper";
}
}
}
然后我写个启动类:
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
publicclass DemoApplication implements CommandLineRunner {
privatefinal ApplicationContext context;
public DemoApplication(ApplicationContext context) {
this.context = context;
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) {
MyService myService = context.getBean(MyService.class);
System.out.println(myService.hello());
MyService.Helper helper = context.getBean(MyService.Helper.class);
System.out.println(helper.help());
}
}
启动日志和输出
项目跑起来的时候,你会在日志里看到 Spring 注册了两个 bean,一个叫myService,另一个叫helper。运行输出是这样的:
hello from component
i am helper
很直观吧? 所以这就说明@Component和@Bean同时用的时候,Spring 会把类本身注册成一个 bean,再把方法返回的对象也注册进去,互不干扰。
但这里有个坑
如果这个类不是@Configuration而是@Component,那么它里面的@Bean方法不会被 Spring 用代理增强。什么意思呢?就是如果你在同一个类里写两个@Bean方法,方法 A 里去调用方法 B,那返回的可能是新建的实例,而不是单例。这个细节很多人忽略了。
所以虽然同时用不会报错,但实际开发中最好还是分开用:
工厂方法写在@Configuration类里,配合@Bean。
普通业务类就直接用@Component。
这样不容易踩坑,也方便别人看懂。