@Bean与@Component

1.@Component修饰类,可对修饰的类在项目启动时注入ioc容器之中

(1)对于类中只有含参构造器:

在将该类注入到 Spring IoC 容器之前,Spring 会调用这个含参构造器。这是因为 Spring 需要通过含参构造器来完成依赖注入,创建类的实例。

(2)对于类中只有无参构造器:这种又会根据依赖的注入方式分为两种

1)使用setter方法注入,Spring会先调用无参构造器创建实例,接着使用setter方法进行注入。

代码示例:

	import org.springframework.stereotype.Component;
	@Component
class Dependency {
    public void doWork() {
        System.out.println("Dependency is working.");
    }
}
	@Component
public class MyComponent {
    private Dependency dependency;
	public MyComponent() {
        System.out.println("MyComponent's no-arg constructor is called.");
    }
	public void setDependency(Dependency dependency) {
        System.out.println("MyComponent's setDependency method is called.");
        this.dependency = dependency;
    }
	public void useDependency() {
        dependency.doWork();
    }
}

在上述代码中,Spring 会先调用 MyComponent 的无参构造器创建实例,接着调用 setDependency 方法将 Dependency 类型的 Bean 注入到 MyComponent 中。

2)使用基于字段的自动装配,Spring 会先调用无参构造器创建类的实例,然后通过反射机制直接给字段赋值,而不会调用 setter 方法。

代码示例:

	import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
	@Component
class Dependency {
    public void doWork() {
        System.out.println("Dependency is working.");
    }
}
	@Component
public class MyComponent {
    @Autowired
    private Dependency dependency;
	public MyComponent() {
        System.out.println("MyComponent's no-arg constructor is called.");
    }
	public void useDependency() {
        dependency.doWork();
    }
}

Spring 先调用 MyComponent 的无参构造器创建实例,之后通过反射将 Dependency 实例赋值给 dependency 字段,不会调用 setter 方法。

(3)当既有含参构造器,又有无参构造器时,Spring的版本不同,处理方式也就不同

Spring 4.3 及以后版本:

从 Spring 4.3 版本开始,如果一个类存在多个构造器,且没有使用 @Autowired 注解显式指定使用哪个构造器,Spring 会优先选择带有参数且参数都能在 Spring 容器中找到对应 Bean 的构造器;若不存在这样的构造器,则会选择无参构造器。

Spring 4.3 以前版本:

在 Spring 4.3 之前的版本,如果一个类存在多个构造器,且没有使用 @Autowired 注解显式指定使用哪个构造器,Spring 会选择无参构造器进行实例化。若要使用含参构造器,必须使用 @Autowired 注解来明确指定。

(4)被@Component修饰的类中有静态方法和静态代码块

静态代码块会在类加载时(注入ioc之前)自动执行,并且只执行一次;静态方法则需要被显式调用才会执行。

2.@Bean修饰方法,可对修饰的方法的返回值在项目启动时注入ioc容器之中

(1)在注入时如果相同类的对象只有一个被注入到容器,那么获取时可通过类获取该对象

代码示例:

@Configuration
public class AppConfig {
    @Bean
    public MyService myService1() {
        return new MyServiceImpl1();
    }
}
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        MyService myService = context.getBean(MyService.class);
        myService.doSomething();
        context.close();
    }
}

由于容器里只有一个 MyService 类型的 Bean,所以能顺利获取该 Bean 实例。

(2)在注入时如果相同类的对象有多个被注入到容器,那么获取时必须通过指定类名称获取该对象

代码示例:

@Configuration
public class AppConfig {
    @Bean
    public MyService myService1() {
        return new MyServiceImpl1();
    }
@Bean
    public MyService myService2() {
        return new MyServiceImpl2();
    }
}
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        MyService myService = context.getBean(MyService.class);
        myService.doSomething();
        context.close();
    }
}

当调用 context.getBean(MyService.class) 时,由于有两个 MyService 类型的 Bean(myService1 和 myService2),就会抛出异常。

(3)也可以使用@Primary注解来进行类的优先选择,这样即使多个相同类的对象在取出时也不会报错

代码示例:

@Configuration
public class AppConfig {
    @Bean
    public MyService myService1() {
        return new MyServiceImpl1();
    }
@Bean
    public MyService myService2() {
        return new MyServiceImpl2();
    }
}
@Service
@Primary
public class MyServiceImpl1 implements MyService {
    @Override
    public void doSomething() {
        System.out.println("MyServiceImpl1 is doing something.");
    }
}
@Service
public class MyServiceImpl2 implements MyService {
    @Override
    public void doSomething() {
        System.out.println("MyServiceImpl2 is doing something.");
    }
}

在这个例子中,MyServiceImpl1 被 @Primary 注解标注,当调用 context.getBean(MyService.class) 时,会返回 MyServiceImpl1 的实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值