Spring注解驱动开发 第十二节 @Autowired 实验

Spring注解驱动开发 第十二节 @Autowired 实验

首先先上代码。

@Service
public class BookService {
    public BookDao getBookDao() {
        return bookDao;
    }

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    @Autowired
    private BookDao bookDao;

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}
@Configuration
@ComponentScan({"com.meng.service","com.meng.dao","com.meng.controller"})
public class MainConfig6 {

}

配置类,扫描了三个包上标注注解的类全部注入到spring IOC容器。
上面的代码是BookService代码。

@Repository
public class BookDao {

}

上面的代码是BookDao代码,而在BookService中需要用到BookDao的代码,所以需要在BookService中声明BookDao的属性,然后在属性上标注@Autowired注解,最后BookDao就从spring容器中取出,然后赋值给这个属性,这就是spring的DI依赖注入。我们写一个注释类,测试一下在BookService用@Autowired获取的对象与getBean获取的对象是否是同一个对象。

	@Test
    public void test01(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig6.class);
        BookService bookService = context.getBean(BookService.class);

        BookDao bookDao = context.getBean(BookDao.class);
        System.out.println(bookService);
        System.out.println(bookDao);
    }

查看打印结果:

四月 24, 2019 11:47:42 上午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 11:47:42 GMT+08:00 2019]; root of context hierarchy
BookService{bookDao=com.meng.dao.BookDao@17c1bced}
com.meng.dao.BookDao@17c1bced

Process finished with exit code 0

看的出来,它们获取的是同一个对象。
@Autowirte的作用是这样的,首先它先在spring容器中按类型匹配对应的类,匹配到了,就赋值给属性,它类似于applicationContext.getBean(Class)按类型获取容器中组件的方式
如果在容器中找到多个同类型的组件,就按照属性的名称作为组件的id进行查找。类似于applicationContext.getBean(String) 根据id名称获取容器中的组件。
下面我们做一个小实验验证它。

@Configuration
@ComponentScan({"com.meng.service","com.meng.dao","com.meng.controller"})
public class MainConfig6 {

    @Bean("bookDao2")
    public BookDao bookDao(){
        BookDao bookDao = new BookDao();
        bookDao.setLabel("2");
        return bookDao;
    }
}

我们首先在配置类中不仅扫描一个BookDao,而且在配置类中也注入了一个,这样spring容器就有两个同类型组件。当然我还做了一个标注,如果label属性是2就是bookDao2,如果是1就是bookDao。

@Repository
public class BookDao {
    private String label = "1";

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return "BookDao{" +
                "label='" + label + '\'' +
                '}';
    }
}

上面是BookDao类

@Service
public class BookService {
    public BookDao getBookDao() {
        return bookDao;
    }

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    @Autowired
    private BookDao bookDao;

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}

上面是BookService类

 @Test
    public void test01(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig6.class);
        BookService bookService = context.getBean(BookService.class);
        System.out.println(bookService);
        //BookDao bookDao = context.getBean(BookDao.class);
        //System.out.println(bookDao);
        ((AnnotationConfigApplicationContext) context).close();
    }

主方法,然后运行,查看打印结果:

四月 24, 2019 2:11:06 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 14:11:06 GMT+08:00 2019]; root of context hierarchy
四月 24, 2019 2:11:06 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
BookService{bookDao=BookDao{label='1'}}

信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 14:11:06 GMT+08:00 2019]; root of context hierarchy

Process finished with exit code 0

结果打印的label属性是1,让我们来分析一下为什么是1,首先可以确定,现在的容器中有两个同类型的组件,一个label属性是1,一个是2,因为@Autowired默认首先按照类型查找,但是容器里又不止一个,所以就要开始按照名称查找,而BookService属性的名称正好是bookDao,所以属性label为1的被获取出来,下面我们试着修改BookService属性的名称,看看bookDao2是否可以被获取到。

@Service
public class BookService {
    public BookDao getBookDao() {
        return bookDao2;
    }

    public void setBookDao(BookDao bookDao2) {
        this.bookDao2 = bookDao2;
    }

    @Autowired
    private BookDao bookDao2;

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao2 +
                '}';
    }
}

查看打印结果:

四月 24, 2019 2:17:05 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 14:17:05 GMT+08:00 2019]; root of context hierarchy
BookService{bookDao=BookDao{label='2'}}
四月 24, 2019 2:17:06 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 14:17:05 GMT+08:00 2019]; root of context hierarchy

Process finished with exit code 0

看到label属性已经是2。
总结:@Autowired属性首先按照类型从spring容器中获取组件,如果spring容器中有多个组件,他会自动按照属性名称当作组件的id去spring容器查找相关的组件。
我们还可以专门指定属性被spring容器的那个组件赋值,不受属性名称的控制。

@Service
public class BookService {
    public BookDao getBookDao() {
        return bookDao2;
    }

    public void setBookDao(BookDao bookDao2) {
        this.bookDao2 = bookDao2;
    }

    @Autowired
    @Qualifier("bookDao")
    private BookDao bookDao2;

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao2 +
                '}';
    }
}

使用@Qualifier(“指定组件的id”),使用这个注解就可以不受属性名称的控制,直接指定spring容器中的组件id,并装配到属性上。查看打印结果:

四月 24, 2019 2:24:17 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 14:24:17 GMT+08:00 2019]; root of context hierarchy
四月 24, 2019 2:24:17 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 14:24:17 GMT+08:00 2019]; root of context hierarchy
BookService{bookDao=BookDao{label='1'}}

Process finished with exit code 0

可以看出,我们的属性名虽然是bookDao2,但是装配的却是bookDao。
如果容器中没有bookDao组件,会出现什么问题。

//@Bean("bookDao2")
    public BookDao bookDao(){
        BookDao bookDao = new BookDao();
        bookDao.setLabel("2");
        return bookDao;
    }
//@Repository
public class BookDao {
    private String label = "1";

    public String getLabel() {
        return label;
    }

我们注掉了部分注解,现在spring容器应该是没有对应的组件的,现在我们来试一下,看看会不会报错。

四月 24, 2019 3:10:03 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 15:10:03 GMT+08:00 2019]; root of context hierarchy
四月 24, 2019 3:10:03 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bookService': Unsatisfied dependency expressed through field 'bookDao2'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.meng.dao.BookDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=bookDao)}

果然抛异常了,是一个NoSuchBeanDefinitionException异常,表示我们spring容器没有这个组件,所以装配不上,要怎样才能在spring没有对应组件的情况下装配,而且还不报错。

@Autowired(required=false)
    @Qualifier("bookDao")
    private BookDao bookDao2;

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao2 +
                '}';
    }

@Autowired注解有一个属性是required,表示是否必须,如果spring容器有对应组件就装配,没有就返回null,不报错,我们运行一下,查看一下打印结果:

四月 24, 2019 3:16:17 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 15:16:17 GMT+08:00 2019]; root of context hierarchy
BookService{bookDao=null}
四月 24, 2019 3:16:18 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 15:16:17 GMT+08:00 2019]; root of context hierarchy

Process finished with exit code 0

可以看出不报错了,只是没有进行装配。
我们还有一种装配方式,注解@Primary,表示首选自动状态,但是有一点,只要@Primary指定后@Qualifier就不能用了,他表示明确指定。

@Configuration
@ComponentScan({"com.meng.service","com.meng.dao","com.meng.controller"})
public class MainConfig6 {
    @Primary
    @Bean("bookDao2")
    public BookDao bookDao(){
        BookDao bookDao = new BookDao();
        bookDao.setLabel("2");
        return bookDao;
    }
}

上面的代码就表示我们注入的bookDao在spring容器中有两个这样的类型,@Primary表示首选装配这个注解下的组件,我们查看一下打印结果:

四月 24, 2019 3:28:15 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 15:28:15 GMT+08:00 2019]; root of context hierarchy
四月 24, 2019 3:28:15 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Wed Apr 24 15:28:15 GMT+08:00 2019]; root of context hierarchy
BookService{bookDao=BookDao{label='2'}}

Process finished with exit code 0

可以看出,我们配置的首选装配起效果了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值