重点标记
本篇记录了学习Spring中,使用Java注入容器的方式,主要内容有,Bean的注入,生命周期,钩子函数以及Bean相互依赖等。
Bean的注入
首先,还是要先加入依赖,如下。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.4</version>
</dependency>
然后,创建一个Moel类,用于测试注入参数。
public class User {
private String id;
private String username;
private String address;
//省略get set方法
}
再创建一个配置类,这里注意下一下,如果只是为了注入Bean,实际上是不需要使用@Configuration注解的。
public class JavaConfig {
@Bean()
User user (Book book){
User user = new User();
user.setAddress("西安");
user.setId("1");
user.setUsername("同舟");
return user;
}
}
接下来,测试一下。
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(JavaConfig.class);
User user = annotationConfigApplicationContext.getBean(User.class);
System.out.println(user);
}
结果自然是ok的。
Bean的互相依赖问题
如下,有个人,他有一本书,那我们只需要增加一个书的类,然后将书这个类作为一个属性,放到User类中,如下:
public class Book {
private String publish;
private String info;
//省略,get set以及toString方法
}
public class User {
private String id;
private String username;
private String address;
private Book book;
}
接下来,在JavaConfig中进行配置注入,这里我们需要注意,使用如下的方法,看似是User类拿到了Book的属性,注入成功,但实际上,User拿到的和Spring容器中注入的Book类并不是同一个:
@Bean(autowireCandidate = false)
User user (){
User user = new User();
user.setAddress("西安");
user.setId("1");
user.setUsername("同舟");
user.setBook(book());
return user;
}
@Bean
Book book(){
Book book = new Book();
book.setInfo("说文解字");
book.setPublish("清华出版社");
return book;
}
测试如下
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(JavaConfig.class);
User user = annotationConfigApplicationContext.getBean(User.class);
System.out.println(user);
Book book = annotationConfigApplicationContext.getBean("book", Book.class);
System.out.println(user.getBook() == book);
annotationConfigApplicationContext.close();
}
结果自然是false。
要解决这个,也很简单,有两种方式:
1,使用@Configuration,这也是比较推荐的,注入相应的Bean的,直接去问Spring容器拿。
2,则是换一种写法,如下:
@Bean()
User user (Book book){
User user = new User();
user.setAddress("西安");
user.setId("1");
user.setUsername("同舟");
user.setBook(book);
return user;
}
这样,也可以达到我们的目的,再次测试,结果就是true了。
Bean的其他属性
进入bean注解后,我们可以看到如下图
value和name大家都知道,取别名,但是要注意,这两个属性是不能共存的。
autowireCandidate 则是定义候选者,这个在使用类型获取bean的时候可以用得到。
initMethod 初始化前调用
destroyMethod 销毁之前调用
我们先看autowireCandidate 这个怎么用,实际上,对于用类型来获取bean的时候,如果有多个相同类型的bean,Spring容器并不知道你想要的是哪一个,就会报错,这个时候,如果我们使用autowireCandidate的值为false,让其中一个bean不作为候选者被注入,就可以解决这个问题了。
@Bean(value = )
User user (Book book){
User user = new User();
user.setAddress("西安");
user.setId("1");
user.setUsername("同舟");
user.setBook(book);
return user;
}
@Bean(autowireCandidate = false)
User user2 (Book book){
User user = new User();
user.setAddress("西安2");
user.setId("2");
user.setUsername("同舟1");
user.setBook(book);
return user;
}
除此之外呢,我们还可以使用@Primary注解,来解决这个问题,加上这个注解的bean优先级会高一点,优先被调用。
@Bean(value = )
User user (Book book){
User user = new User();
user.setAddress("西安");
user.setId("1");
user.setUsername("同舟");
user.setBook(book);
return user;
}
@Bean()
@Primary
User user2 (Book book){
User user = new User();
user.setAddress("西安2");
user.setId("2");
user.setUsername("同舟1");
user.setBook(book);
return user;
}
initMethod 和destroyMethod 的使用,则是通过子bean中编写相应的方法,然后在配置类中进行配置,就可以调用了。
public class User {
private String id;
private String username;
private String address;
private Book book;
public void init(){
System.out.println("User init");
}
public void destroy(){
System.out.println("User destroy");
}
}
@Bean(initMethod = "init",destroyMethod = "destroy",autowireCandidate = false)
// @Primary
User user2 (Book book){
User user = new User();
user.setAddress("西安2");
user.setId("2");
user.setUsername("同舟1");
user.setBook(book);
return user;
}
实际上,也可以通过实现InitializingBean和DisposableBean来显示相同的目的。
public class User implements InitializingBean, DisposableBean {
@Override
public void destroy(){
System.out.println("User destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("User afterPropertiesSet ");
}
}