spring中给bean的属性赋值
- xml文件properties标签设置
<bean id="student" class="com.enjoy.study.cap10.Student" > <property name="id" value="18"/> <property name="name" value="wxf"/> </bean>
- 注解
- @Autowired
- @Value
- @Resource JSR250
- @Inject JSR330
本章博客重点介绍注解赋值的使用
@Autowired
自动装配:Spring利用依赖注入完成对IOC容器中各个组件的依赖关系赋值
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
可以在构造方法、方法、参数、属性以及注解上使用,最常用的就是在属性上使用
不管使在什么地方使用,都是从IOC容器中获取bean
基本使用
@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig {
}
@Repository
public class TestDao {
public void test(){
System.out.println("---------TestDao test()--------");
}
}
@Service
public class TestService {
@Autowired
private TestDao testDao;
public void test() {
System.out.println("---------TestService test()--------"+testDao);
}
public TestDao getTestDao() {
return testDao;
}
public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
}
测试
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
TestDao testDao = (TestDao) context.getBean("testDao");
TestService service = (TestService) context.getBean("testService");
TestDao testDao1 = service.getTestDao();
System.out.println(testDao==testDao1);
}
}
结果
true
结论:
- @Autowired注解先按照类型去IOC容器中找到相应组件,再将id为testDao的bean取出并注入TestService的testDao属性中
- 如果没有找到该id对应的bean,就将相同类型的bean注入,不会报错
优先级
当容器中有多个相同类型的bean,使用@Autowired注解注入哪一个?
@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig {
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag(2);
return testDao;
}
}
@Repository
public class TestDao {
private int flag = 1;
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
@Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
@Service
public class TestService {
@Autowired
private TestDao testDao2;
public TestDao getTestDao() {
return testDao2;
}
public void setTestDao(TestDao testDao) {
this.testDao2 = testDao;
}
}
测试类
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
TestService service = context.getBean(TestService.class);
TestDao testDao1 = service.getTestDao();
System.out.println(testDao1);
}
}
结果
TestDao{flag=2}
结论:
TestService中注入的是testDao2;另外,如果TestService中定义private TestDao testDao;那么结果是TestDao{flag=1},也就是TestService中注入的是testDao
指定注入哪个bean
如果TestService中定义private TestDao testDao;还是想要注入testDao,那么可以使用@Qualifier+@Autowired
@Service
public class TestService {
@Qualifier("testDao")
@Autowired
private TestDao testDao2;
public TestDao getTestDao() {
return testDao2;
}
public void setTestDao(TestDao testDao) {
this.testDao2 = testDao;
}
}
结果
TestDao{flag=1}
required属性
当容器中不存在该类型的bean时:
将配置类中的@Bean和TestDao类的@Repository注释掉
@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig {
//@Bean("testDao")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag(2);
return testDao;
}
}
//@Repository
public class TestDao {
private int flag = 1;
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
@Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
@Service
public class TestService {
@Autowired
private TestDao testDao2;
public TestDao getTestDao() {
return testDao2;
}
public void setTestDao(TestDao testDao) {
this.testDao2 = testDao;
}
}
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
TestService service = context.getBean(TestService.class);
TestDao testDao1 = service.getTestDao();
System.out.println(testDao1);
}
}
结果
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'com.enjoy.study.cap11.dao.TestDao' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true)}
结论:
启动容器,两个TestDao类型的bean都不会被加载,并且提示异常报错;原因是@Autowired注解的required属性默认为true,即要求容器中必须存在bean,否则抛出异常
使用@Autowired(required=false)即可解决
@Service
public class TestService {
@Autowired(required = false)
private TestDao testDao2;
public TestDao getTestDao() {
return testDao2;
}
public void setTestDao(TestDao testDao) {
this.testDao2 = testDao;
}
}
结果
null
结论:
因为容器中没有TestDao类型的bean,所以打印结果为null
验证@Qualifier和@Primary加载顺序
@Primary的作用是使得该bean默认优先被使用
应用场景:多个类都需要注入一个bean时,如果每个类都使用@Qualifier指定注入相同的bean会导致代码冗余,这时可以使用@Primary直接在该bean上作用即可
@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig {
@Primary
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag(2);
return testDao;
}
}
@Repository
public class TestDao {
private int flag = 1;
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
@Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
@Service
public class TestService {
@Qualifier("testDao")
@Autowired(required = false)
private TestDao testDao2;
public TestDao getTestDao() {
return testDao2;
}
public void setTestDao(TestDao testDao) {
this.testDao2 = testDao;
}
}
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
TestDao testDao = context.getBean(TestDao.class);
System.out.println("context.getBean(TestDao.class) = " + testDao);
TestService service = context.getBean(TestService.class);
TestDao testDao1 = service.getTestDao();
System.out.println("service.getTestDao() = " + testDao1);
}
}
结果
context.getBean(TestDao.class) = TestDao{flag=2}
service.getTestDao() = TestDao{flag=1}
结论1:
- TestService中注入的是testDao,直接从容器中获取时取到的是testDao2
- 说明@Qualifier是根据bean的id获取的bean,不受@Primary影响
修改TestService类
@Service
public class TestService {
// @Qualifier("testDao")
@Autowired(required = false)
private TestDao testDao;
public TestDao getTestDao() {
return testDao;
}
public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
}
结果
context.getBean(TestDao.class) = TestDao{flag=2}
service.getTestDao() = TestDao{flag=2}
结论2:
- 注入的都是@Primary指定的testDao2
- 通过@Primary标记的bean,默认首先被使用
@Value
@Configuration
public class CapMainConfig {
@Bean
public Student student(){
return new Student();
}
}
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
Student student = (Student) context.getBean("student");
System.out.println("student = " + student);
}
}
字符形式@Value("")
public class Student {
@Value("12")
private Integer id;
@Value("wxf")
private String name;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
结果
student = Student{id=12, name='wxf'}
@Value("#{}")
@Value("#{}") 表示SpEl表达式,通常用来获取bean的属性,或者调用bean的某个方法
容器中bean类:
public class TestBean {
@Value("qf")
private String name;
@Value("12")
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Student {
@Autowired
private TestBean testBean;
//表达式,或者字符形式#{1}
@Value("#{12-1}")
private String sex;
//bean属性
@Value("#{testBean.id}")
private Integer id;
//bean方法
@Value("#{testBean.getName()}")
private String name;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"sex='" + sex + '\'' +
", id=" + id +
", name='" + name + '\'' +
'}';
}
}
配置类
@Configuration
public class CapMainConfig {
@Bean
public TestBean testBean(){
return new TestBean();
}
@Bean
public Student student(){
return new Student();
}
}
测试类
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
Student student = (Student) context.getBean("student");
System.out.println("student = " + student);
}
}
结果
student = Student{sex='11', id=12, name='qf'}
@Value("${}")
通过@Value("${}") 可以获取对应属性文件中定义的属性值
想要使用${}方式获取值
首先通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值
@Configuration
@PropertySource(value={"classpath:test.properties","classpath:test2.properties"})
public class MainConfig {
@Bean
public Person person(){
return new Person();
}
}
测试
配置文件
test.properties文件
TestStr=12345
test2.properties文件
TestStr1=123456789
bean类
public class Person {
@Value("${TestStr}")
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
测试
public class TestCap {
@Test
public void testM(){
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = context.getBean(Person.class);
System.out.println("person.getId() = " + person.getId());
}
}
结果
person.getId() = 12345
@Resource
基本使用
@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig {
@Primary
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag(2);
return testDao;
}
}
@Repository
public class TestDao {
private int flag = 1;
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
@Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
@Service
public class TestService {
@Resource
private TestDao testDao;
public TestDao getTestDao() {
return testDao;
}
public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
}
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
TestDao testDao = context.getBean(TestDao.class);
System.out.println("context.getBean(TestDao.class) = " + testDao);
TestService service = context.getBean(TestService.class);
TestDao testDao1 = service.getTestDao();
System.out.println("service.getTestDao() = " + testDao1);
}
}
结果
context.getBean(TestDao.class) = TestDao{flag=2}
service.getTestDao() = TestDao{flag=1}
结论:
- @Primary对@Resource并不生效
- @Resource和@Autowired一样可以装配bean
name属性
可以指定注入哪个bean
@Service
public class TestService {
@Resource(name = "testDao2")
private TestDao testDao;
public TestDao getTestDao() {
return testDao;
}
public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
}
结果
context.getBean(TestDao.class) = TestDao{flag=2}
service.getTestDao() = TestDao{flag=2}
bean为null的情况
将TestDao上的@Repository和配置类中的@Bean都注释掉,再测试会抛出异常
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'testDao2' available
所以@Resource并不支持类似@Autowired(required=false)的功能
@Inject
基本使用
需要导入javax.inject的包
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
测试
@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig {
@Primary
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag(2);
return testDao;
}
}
@Repository
public class TestDao {
private int flag = 1;
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
@Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
@Service
public class TestService {
@Inject
private TestDao testDao;
public TestDao getTestDao() {
return testDao;
}
public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
}
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
TestDao testDao = context.getBean(TestDao.class);
System.out.println("context.getBean(TestDao.class) = " + testDao);
TestService service = context.getBean(TestService.class);
TestDao testDao1 = service.getTestDao();
System.out.println("service.getTestDao() = " + testDao1);
}
}
结果
context.getBean(TestDao.class) = TestDao{flag=2}
service.getTestDao() = TestDao{flag=2}
结论:
@Inject支持@Primary
bean为null的情况
将TestDao上的@Repository和配置类中的@Bean都注释掉,再测试会抛出异常
org.springframework.beans.factory.NoSuchBeanDefinitionException
@Inject并不支持类似@Autowired(required=false)的功能