@Configuration和@Component区别
@Configuration详解
⼀、@Configuration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
可以看到在@Configuration注解中是包含@Component注解的,被@Configuration修饰的类被定义为⼀个Spring容器(应⽤上下⽂)@Configuration就相当于Spring配置⽂件中的<beans />标签,⾥⾯可以配置bean
⼆、@Bean
@Bean相当于Spring配置⽂件中的<bean />标签可以在Spring容器中注⼊⼀个bean
@Configuration
public class TestConfiguration {
@Bean
实例化bean的三种方式public TestBean testBean() {
return new TestBean();
}
}
上述代码相当于实例化⼀个TestBean并交给Spring容器管理
ps:
1、@Bean注解在返回实例的⽅法上,如果未通过@Bean指定bean的名称,则默认与⽅法名相同
2、@Bean注解默认作⽤域为单例singleton作⽤域,可通过@Scope(“prototype”)设置为多例
三、依赖注⼊
@Configuration
public class TestConfiguration {
@Bean
public TestBean testBean() {
return new TestBean();
}
@Bean
public DIBean diBean() {
return new DIBean(testBean());
}
}
如上述代码,通过在@Bean⽅法中调⽤其他@Bean注解的⽅法来实现依赖注⼊
ps:
当需要强制指定实例化bean的顺序,可以通过@Order或@DependsOn注解来实现
除此之外我们还能使⽤@Component声明Spring Bean
@Configuration和@Component区别
public class Car {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Driver {
private int id;
private String name;
private Car car;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
import t.annotation.Bean; import t.annotation.Configuration; @Configuration
public class MyTestConfig {
@Bean
public Driver driver() {
Driver driver = new Driver();
driver.setId(1);
driver.setName("driver");
driver.setCar(car());
return driver;
}
@Bean
public Car car() {
Car car = new Car();
car.setId(1);
car.setName("car");
return car;
}
}
import t.annotation.Bean; import t.annotation.Configuration; @Component
public class MyTestConfig {
@Bean
public Driver driver() {
Driver driver = new Driver();
driver.setId(1);
driver.setName("driver");
driver.setCar(car());
return driver;
}
@Bean
public Car car() {
Car car = new Car();
car.setId(1);
car.setName("car");
return car;
}
}
上⾯两段代码除MyTestConfig类上的注解不同之外其他都相同,但Spring对两者的处理⽅式是完全不⼀样的。
第⼀段代码会像我们期望的⼀样正常运⾏,因为driver()这段代码中driver.setCar(car())⽅法会由Spring代理执⾏,
Spring发现⽅法所请求的Bean已经在容器中,那么就直接返回容器中的Bean。所以全局只有⼀个Car对象的实例。
第⼆段代码在执⾏driver() 时driver.setCar(car())不会被Spring代理,会直接调⽤car()⽅法获取⼀个全新的Car对象实例,所以全局会有多个Car对象的实例
造成这种差异的原因如下:
概括就是 @Configuration 中所有带 @Bean 注解的⽅法都会被动态代理,因此调⽤该⽅法返回的都是同⼀个实例。
其⼯作原理是:如果⽅式是⾸次被调⽤那么原始的⽅法体会被执⾏并且结果对象会被注册到Spring上下⽂中,之后所有的对该⽅法的调⽤仅仅只是从Spring上下⽂中取回该对象返回给调⽤者。
在上⾯的第⼆段代码中,driver.setCar(car())只是纯JAVA⽅式的调⽤,多次调⽤该⽅法返回的是不同的对象实例。
要修正第⼆段代码中的问题,可以使⽤@Autowired如下所⽰:
import org.springframework.beans.factory.annotation.Autowired;
import t.annotation.Bean;
import t.annotation.Configuration;
import org.springframework.stereotype.Component;
//@Configuration
@Component
public class MyTestConfig2 {
@Autowired
Car car;
@Bean
public Driver driver() {
Driver driver = new Driver();
driver.setId(1);
driver.setName("driver");
driver.setCar(car);
return driver;
}
@Bean
public Car car() {
Car car = new Car();
car.setId(1);
car.setName("car");
return car;
}
}
验证
import t.ApplicationContext;
import t.annotation.AnnotationConfigApplicationContext;
public class TestMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
// @Configuration注解的spring容器加载⽅式,⽤AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(MyTestConfig.class);
// 获取bean
Driver driver = (Driver) Bean("driver");
// 获取bean
Car car = (Car) Bean("car");
boolean result = Car() == car;
System.out.println(result ? "同⼀个car" : "不同的car"); }
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论