spring(四):spring中给bean的属性赋值

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)的功能

 

posted @ 2019-05-27 18:59  *青锋*  阅读(4223)  评论(0编辑  收藏  举报