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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM