allbet登陆官网:【String注解驱动开发】面试官让我说说:若何使用FactoryBean向Spring容器中注册bean?

admin 3周前 (06-19) 科技 6 0

写在前面

在前面的文章中,我们知道可以通过多种方式向Spring容器中注册bean。可以使用@ConfIGuratI.N连系@Bean向Spring容器中注册bean;可以根据条件向Spring容器中注册bean;可以使用@Import向容器中快速导入bean工具;可以在@Import中使用ImportBeanDefinitionRegistrar向容器中注册bean。

项目工程源码已经提交到GitHub:https://github.com/suNShinelyz/spring-annotation

FactoryBean概述

一样平常情况下,Spring通过反射机制行使bean的class属性指定实现类来实例化bean 。在某些情况下,实例化bean历程比较庞大,若是根据传统的方式,则需要在 标签中提供大量的设置息,设置方式的灵活性是受限的,这时接纳编码的方式可以获得一个加倍简朴的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。

FactoryBean接口对于Spring框架来说占有主要的职位,Spring 自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些庞大bean的细节,给上层应用来了便利。从Spring 3.0 最先, FactoryBean最先支持泛型,即接口声明改为FactoryBean 的形式:

在Spring 5.2.6版本中,FactoryBean接口的界说如下所示。

package org.springframework.beans.factory;
import org.springframework.lang.Nullable;

public interface FactoryBean<T> {

	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

	@Nullable
	T getObject() throws Exception;

	@Nullable
	Class<?> getObjectType();

	default boolean isSingleton() {
		return true;
	}
}
  • T getObject():返回由FactoryBean建立的bean实例,若是isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中。
  • boolean isSingleton():返回由FactoryBean建立的bean实例的作用域是singleton照样prototype。
  • Class getObjectType():返回FactoryBean建立的bean类型。

这里,需要注重的是:当设置文件中 标签的class属性设置的实现类是FactoryBean时,通过 getBean()方式返回的不是FactoryBean自己,而是FactoryBean#getObject()方式所返回的工具,相当于FactoryBean#getObject()代理了getBean()方式。

FactoryBean实例

首先,建立一个PersonFactoryBean,实现FactoryBean接口,如下所示。

package io.mykit.spring.plugins.register.bean;

import org.springframework.beans.factory.FactoryBean;
/**
 * @author binghe
 * @version 1.0.0
 * @description 商品的FactoryBean,测试FactoryBean
 */
public class PersonFactoryBean implements FactoryBean<Person> {

    //返回一个Person工具,这个工具会被注册到Spring容器中
    @Override
    public Person getObject() throws Exception {
        return new Person();
    }

    @Override
    public Class<?> getObjectType() {
        return Person.class;
    }

    //bean是否为单例;true:是;falSE:否
    @Override
    public boolean isSingleton() {
        return true;
    }
}

接下来,我们在PersonConfig2类中加入PersonFactoryBean的声明,如下所示。

@Bean
public PersonFactoryBean personFactoryBean(){
    return new PersonFactoryBean();
}

这里需要小伙伴们注重的是:我在这里使用@Bean注解向Spring容器中添加的是PersonFactory工具。那我们就来看看Spring容器中有哪些bean。接下来,运行SpringBeanTest类中的testAnnotationConfig7()方式,输出的效果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProCESsor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig2
io.mykit.spring.plugins.register.bean.Department
io.mykit.spring.plugins.register.bean.Employee
io.mykit.spring.plugins.register.bean.User
io.mykit.spring.plugins.register.bean.Role
person
binghe001
personFactoryBean
company

可以看到,效果信息中输出了一个personFactoryBean,我们看下这个personFactoryBean到底是个什么鬼!此时,我们对SpringBeanTest类中的testAnnotationConfig7()方式稍加改动,添加获取personFactoryBean的代码,并输出personFactoryBean实例的类型,如下所示。

@Test
public void testAnnotationConfig7(){
    APPlicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class);
    String[] names = context.getBeanDefinitionNames();
    Arrays.stream(names).forEach(System.out::println);

    Object personFactoryBean = context.getBean("personFactoryBean");
    System.out.println("personFactoryBean实例的类型为:" + personFactoryBean.getClass());
}

再次运行SpringBeanTest类中的testAnnotationConfig7()方式,输出的效果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig2
io.mykit.spring.plugins.register.bean.Department
io.mykit.spring.plugins.register.bean.Employee
io.mykit.spring.plugins.register.bean.User
io.mykit.spring.plugins.register.bean.Role
person
binghe001
personFactoryBean
company
personFactoryBean实例的类型为:class io.mykit.spring.plugins.register.bean.Person

可以看到,虽然我在代码中使用@Bean注解注入的PersonFactoryBean工具,然则,实际上从Spring容器中获取到的bean工具却是挪用PersonFactoryBean类中的getObject()获取到的Person工具。

看到这里,是不是有种豁然开朗的感受!!!

在PersonFactoryBean类中,我们将Person工具设置为单实例bean,接下来,我们在SpringBeanTest类中的testAnnotationConfig7()方式多次获取Person工具,并输出多次获取的工具是否为统一工具,如下所示。

@Test
public void testAnnotationConfig7(){
    ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class);
    String[] names = context.getBeanDefinitionNames();
    Arrays.stream(names).forEach(System.out::println);

    Object personFactoryBean1 = context.getBean("personFactoryBean");
    Object personFactoryBean2 = context.getBean("personFactoryBean");
    System.out.println(personFactoryBean1 == personFactoryBean2);
}

运行testAnnotationConfig7()方式输出的效果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig2
io.mykit.spring.plugins.register.bean.Department
io.mykit.spring.plugins.register.bean.Employee
io.mykit.spring.plugins.register.bean.User
io.mykit.spring.plugins.register.bean.Role
person
binghe001
personFactoryBean
company
true

可以看到,在PersonFactoryBean类的isSingleton()方式中返回true时,每次获取到的Person工具都是统一个工具,说明Person工具是单实例bean。

这里,可能就会有小伙伴要问了,若是将Person工具修改成多实例bean呢?别急,这里我们只需要在PersonFactoryBean类的isSingleton()方式中返回false,即可将Person工具设置为多实例bean,如下所示。

//bean是否为单例;true:是;false:否
@Override
public boolean isSingleton() {
    return false;
}

再次运行SpringBeanTest类中的testAnnotationConfig7()方式,输出的效果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig2
io.mykit.spring.plugins.register.bean.Department
io.mykit.spring.plugins.register.bean.Employee
io.mykit.spring.plugins.register.bean.User
io.mykit.spring.plugins.register.bean.Role
person
binghe001
personFactoryBean
company
false

可以看到,最终效果返回了false,说明此时Person工具是多实例bean。

如何在Spring容器中获取到FactoryBean工具?

之前,我们使用@Bean注解向Spring容器中注册的PersonFactoryBean,获取出来的确实Person工具。那么,小伙伴们可能会问:我就想获取PersonFactoryBean实例,该怎么办呢?

实在,这也很简朴, 只需要在获取bean工具时,在id前面加上&amp;符号即可

打开我们的测试类SpringBeanTest,在testAnnotationConfig7()方式中添加获取PersonFactoryBean实例的代码,如下所示。

@Test
public void testAnnotationConfig7(){
    ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class);
    String[] names = context.getBeanDefinitionNames();
    Arrays.stream(names).forEach(System.out::println);

    Object personFactoryBean1 = context.getBean("personFactoryBean");
    Object personFactoryBean2 = context.getBean("personFactoryBean");
    System.out.println("personFactoryBean1类型:" + personFactoryBean1.getClass());
    System.out.println("personFactoryBean2类型:" + personFactoryBean2.getClass());
    System.out.println(personFactoryBean1 == personFactoryBean2);

    Object personFactoryBean3 = context.getBean("&personFactoryBean");
    System.out.println("personFactoryBean3类型:" + personFactoryBean3.getClass());
}

运行SpringBeanTest类中的testAnnotationConfig7()方式,输出的效果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig2
io.mykit.spring.plugins.register.bean.Department
io.mykit.spring.plugins.register.bean.Employee
io.mykit.spring.plugins.register.bean.User
io.mykit.spring.plugins.register.bean.Role
person
binghe001
personFactoryBean
company
personFactoryBean1类型:class io.mykit.spring.plugins.register.bean.Person
personFactoryBean2类型:class io.mykit.spring.plugins.register.bean.Person
false
personFactoryBean3类型:class io.mykit.spring.plugins.register.bean.PersonFactoryBean

可以看到,在获取bean时,在id前面加上&符号就会获取到PersonFactoryBean实例工具。

问题又来了!!为什么在id前面加上&符号就会获取到PersonFactoryBean实例工具呢?

接下来,我们就揭开这个神秘的面纱,打开BeanFactory接口,

package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

public interface BeanFactory {
	String FACTORY_BEAN_PREFIX = "&";
    /**************以下省略n行代码***************/
}

看到这里,是不是明了了呢?没错,在BeanFactory接口中界说了一个&前缀,只要我们使用bean的id来从Spring容器中获取bean时,Spring就会知道我们是在获取FactoryBean自己。

好了,咱们今天就聊到这儿吧!别忘了给个在看和转发,让更多的人看到,一起学习一起提高!!

项目工程源码已经提交到GitHub:https://github.com/sunshinelyz/spring-annotation

写在最后

若是以为文章对你有点辅助,请微信搜索并关注「 冰河手艺 」微信民众号,跟冰河学习Spring注解驱动开发。民众号回复“spring注解”关键字,领取Spring注解驱动开发焦点知识图,让Spring注解驱动开发不再渺茫。

,

AllbetGmAIng下载

欢迎进入AllbetGmaing下载(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。

网友评论

  • (*)

最新评论

站点信息

  • 文章总数:950
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1967
  • 评论总数:52
  • 浏览总数:5308