开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情
本篇内容主要介绍如何一次性拿多个Bean、拿到所有自定义注解标注的Bean、bean的延迟查找等内容。
一次性拿多个Bean
主要讲的是如何一次讲同一个类型的bean都拿出来。
首先,我们需要把用到的bean注册到xml里面。如下我们注册了三个bean,这三个对象都是实现DemoDao这个接口的。
<bean id="demoMySQLDao" class="com.lyz.basic_dl.c_oftypy.dao.impl.DemoMySQLDao"></bean>
<bean id="demoOracle" class="com.lyz.basic_dl.c_oftypy.dao.impl.DemoOracleDao"></bean>
<bean id="demoPostgreDao" class="com.lyz.basic_dl.c_oftypy.dao.impl.DemoPostgreDao"></bean>
我们要一次性去除所有DemoDao类型的bean使用BeanFactory已经不可取,我们将该接口换成ApplicationContext接口,它是它是 BeanFactory 的子接口,具有更强大的功能。接着我们加载xml配置文件如下:
ApplicationContext ctx = new ClassPathXmlApplicationContext("basic_dl/quickstart-oftype.xml");
一次性取bean的时候使用getBeansOfType(DemoDao.class);就可以将所有类型的bean放到Map容器中,然后遍历map就可以取出来。
获取容器中所有Bean
ApplicationContext中还有一个方法getBeanDefinitionNames这个方法可以获取到容器中所有的bean的名字,它获取的是所有bean的id,我们可以用一个字符串数组接收,再打印出来就OK。
String[] beanNames = ctx.getBeanDefinitionNames();
Stream.of(beanNames).forEach(System.out::println);
取自定义注解标注的Bean
讲这部分内容的时候我会穿插着讲一些关于注解的知识,以方便大家理解这部分内容。
首先我们要先有自定义的注解,如下:
- 创建自定义注解的方式是创建一个接口interface,将interface换成@interface即可,这个自定义接口实际上是继承了Annotation(它是所有注解类型的父接口)这个注解接口。
- @Decumented、@Retention、@Target等这些是java里面的元注解。
- @Decumented,被这个注解修饰的注解类会被JavaDoc工具提取成文档。
- @Retention这个是用来描述注解的生命周期的,里面的value值用来设置保留策略。这个value是RetentionPolicy枚举类型,主要有三个:
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在 class 文件中有效(即 class 保留)
- RUNTIME:在运行时有效(即运行时保留)
- @Target注解主要用来指明注解的使用范围,代码中Element.Type指明注解用于类、接口或enum生命上。当然还有用于方法、成员、构造方法等位置的枚举常量。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Color {
}
走到这里,我们就可以用@Color这个自定义注解来修饰我们的类来。可以通过getBeansWithAnnotation这个方法来获取所有被@Color修饰的Bean,这个方法的参数是自定义注解对应的class类,如Color.class。关于注解的内容挺多的,需要详细了解到小伙伴可以去专门学一下这部分的内容,这里就不详细去讲了。
延迟查找
有这么一个情形,我们有两个Bean,但是只有一个被注册到了IOC容器中,那当我们调用getBean去拿没有注册到IOC容器中的那个Bean的时候就会直接抛出NoSuchBeanDefinitionException的异常。针对这种情况,Spring设计了一种策略,延时查找,就是获取的时候不做检查,先给你,使用的时候再做检查。
我们个人针对这种情况可能会想到:获取的时候先判断是否存在,存在就直接拿,不存在会new一个。如下:
Dog dog = ctx.containsBean("dog") ? (Dog) ctx.getBean("dog") : new Dog();
但这种方法只能查id不能查类型,有点点缺陷。Spring在解决这个问题的时候是新引入了一个API:ObjectProvider,来实现延迟查找。
ApplicationContext 中有一个方法叫 getBeanProvider 你可以先通过这个方法拿到Bean
。。如果直接 getBean ,那如果容器中没有对应的 Bean ,就会报 NoSuchBeanDefinitionException;如果使用这种方式,运行 main 方法后发现并没有报错,只有调用 dogProvider 的 getObject ,真正要取包装里面的 Bean 时,才会报异常。
ObjectProvider<Dog> dogProvider = ctx.getBeanProvider(Dog.class);
当然我们也可以使用另一个方法getIfAvailable来取Bean:
dogProvider.getIfAvailable(()->{new Dog();})
如果这个bean没注册,我们就会执行这个供给者(四大函数式接口之一)接口返回默认实现,如果注册了我们就直接拿来用。不了解函数式接口的小伙伴,可以看一下我这篇文章:juejin.cn/post/717171…