细说Spring——IoC详解(自动装配和加载外部配置文件)
一、自动装配
使用过Spring框架的都应该很经常的使用一个注解就就是@Autowired
,我们可以通过使用该注解为一个容器中的类自动装配需要的依赖,现在我们就来复习一下怎么使用@Autowired
注解为来自动装配依赖吧。
BookController
@Controller
public class BookController {
@Autowired
private BookService bookService;
}
BookService
@Service
public class BookService {
@Qualifier("bookDao")
@Autowired
private BookDao bookDao2;
public void print() {
System.out.println(bookDao2);
}
@Override
public String toString() {
return "BookService{" +
"bookDao=" + bookDao2 +
'}';
}
}
BookDao
@Repository
public class BookDao {
private String lable = "1";
public String getLable() {
return lable;
}
public void setLable(String lable) {
this.lable = lable;
}
@Override
public String toString() {
return "BookDao{" +
"lable='" + lable + '\'' +
'}';
}
}
我们可以看到controller中装配了service,service中装配了dao,现在看一下配置类:
@Configuration
@ComponentScan({"com.jiayifan.dao", "com.jiayifan.service", "com.jiayifan.bean"})
public class MainConfigOfAutowired {
}
然后是测试类:
public class IOCTest_Autowired {
@Test
public void test01() {
//1、创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
BookService bookService = applicationContext.getBean(BookService.class);
System.out.println(bookService);
}
}
测试结果:
这里写图片描述
上面就是@Autowired
注解的最基础的用法,可是大家可以考虑一下@Autowired
是按照什么样的规则来帮我们的组件装配依赖的吗,我们今天主要就来学习一下怎么控制@Autowired
帮我们装配依赖。
首先我们需要知道@Autowired
标注的依赖,Spring会先去容器中按照类型进行匹配,如果只找到一个,那么就把找到的组件注入到当前的目标组件中,如果没有找到的话就会报错,我们可以通过@Autowired(required = false)
将required
属性的值设置为false
来消除这种错误,因为@Autowired
注解默认当前的依赖是必须的。如果再容器中找到了两个同样类型的组件,那么Spring会如何选择呢,难道是剪刀石头布吗?
当然不是,Spring会按照在目标组件中依赖组件的属性名作为依赖组件的名字来选择,比如我们在service中依赖的dao属性名为private BookDao bookDao;
,所以Spring就会把名字为bookDao
的组件注入service,我们当然也可以自己制定这种选择的规则,下面我们就来看一下如何实现吧:
首先配置类:
@Configuration
@ComponentScan({"com.jiayifan.dao", "com.jiayifan.service", "com.jiayifan.bean"})
public class MainConfigOfAutowired {
@Bean("bookDao2")
public BookDao bookDao() {
BookDao bookDao = new BookDao();
bookDao.setLable("2");
return bookDao;
}
}
我们可以发现我们即使用了包扫描,又在配置类中使用@Bean
注解添加了一个dao组件,现在容器中有两个dao组件,一个名字是bookDao
,另一个名字是bookDao2
,而servcie中的属性名为bookDao
,现在我们就像使用bookDao2
,我们就可以通过在service中使用@Qualifier("bookDao2")
注解来指定我们想要那个组件当做依赖:
@Service
public class BookService {
@Qualifier("bookDao2")
@Autowired()
private BookDao bookDao;
public void print() {
System.out.println(bookDao);
}
@Override
public String toString() {
return "BookService{" +
"bookDao=" + bookDao +
'}';
}
}
测试一下:
我们看到两个不同的dao中的
lable
属性是不同的,现在service中的daoi是bookDao2
。我们同样可以使用一个
@Primary
注解来选择首要的组件:
@Configuration
@ComponentScan({"com.jiayifan.dao", "com.jiayifan.service", "com.jiayifan.bean"})
public class MainConfigOfAutowired {
@Primary
@Bean("bookDao2")
public BookDao bookDao() {
BookDao bookDao = new BookDao();
bookDao.setLable("2");
return bookDao;
}
}
@Qualifier("bookDao2")
注解的优先级是比@Primary
要高的。
通过上面的学习我们已经了解了在容器中有多个同类型组件的情况下怎么自己选择需要的依赖,其实感觉并不是很有用,因为感觉还是容器中只有一个组件的情况比较多。
我们通常会把@Autowired
注解标注到属性上面,其实@Autowired
还可以标注到其他的地方,我们来看一下:
- 通过将@Autowired标注到set方法上,可以实现自动装填
- 通过将@Autowired标注到相应的有参构造器上,可以实现自动装填,如果相应组件只有一个有参构造器,注解可以省略
- 通过将@Autowired标注到set方法和有参构造器的参数上,可以实现自动装填
二、加载外部配置文件
我们在使用Spring的过程中难免要使用到外部的配置文件,比如我们经常讲数据库的连接参数放到properties文件中,我们现在就来学习一下怎么使用注解加载外部配置文件,然后获取外部配置文件中的值吧,首先我们的配置类:
@PropertySource(value = {"classpath:person.properties"})
@Configuration
public class MainConfigOfPropertyValue {
@Bean
public Person person() {
return new Person();
}
}
我们使用了@PropertySource(value = {"classpath:person.properties"})
注解来加载外部的配置文件,然后我们看一下如何调用配置文件中的值,我们这里有一个组件类:
public class Person {
//使用@Value赋值
//1、基本数值 2、SpEL #{} 3、可以写${},取出配置文件(properties配置文件)中的值
@Value("张三")
private String name;
@Value("#{20 - 2}")
private Integer age;
@Value("${person.nickName}")
private String nickName;
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", nickName='" + nickName + '\'' +
'}';
}
}
我们使用@Value
注解来调用配置文件中的值。
测试类:
public class IOCTest_PropertyValue {
@Test
public void test01() {
//1、创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValue.class);
printBeans();
System.out.println("====================");
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
private void printBeans() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String name : beanDefinitionNames) {
System.out.println(name);
}
}
}
测试结果:
这里写图片描述