BeanFactory и FactoryBean in Spring достаточно, чтобы прочитать эту статью

Spring

предисловие

Очень важно понимать FactoryBean, потому что одним из наиболее типичных применений FactoryBean в Spring является создание прокси-объектов AOP, и не только это, но и очень полезно для понимания основного исходного кода Mybatis! Если я готов халтурить и быть счастливым кодером, то я это сделаю...

BeanFactory и FactoryBean оба являются интерфейсами Spring, и названия выглядят похоже, но я думаю, что их все равно очень сложно спутать! Хотя автор книги «Весеннее раскрытие» любит писать эту фразу.

Пожалуйста, не путайте BeanFactory и FactoryBean.

1. Бобовая фабрика

BeanFactory, оканчивающийся на Factory, означает, что это фабрика (интерфейс), которая отвечает за производство и управление фабрикой бинов. В Spring BeanFactory является интерфейсом верхнего уровня фабрики и основным интерфейсом контейнера IOC, поэтому BeanFactory определяетОбщие методы управления бинами,Такие какgetBeanа такжеcontainsBeanи т. д. В его обязанности входит: создание экземпляров, размещение, настройка объектов в приложении и установление зависимостей между этими объектами. BeanFactory — это просто интерфейс, а не конкретная реализация контейнера IOC, поэтому контейнер Spring предоставляет множество реализаций, таких какDefaultListableBeanFactory,XmlBeanFactory,ApplicationContextИ т. д., из которых XmlBeanFactory является широко используемым, а реализация будет описывать объекты, составляющие приложение, и зависимости между ними в XML.

1.1 Исходный код BeanFactory

public interface BeanFactory {
	//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
	//如果需要得到工厂本身,需要转义
	String FACTORY_BEAN_PREFIX = "&";

	//根据bean的名字,获取在IOC容器中得到bean实例
	Object getBean(String name) throws BeansException;

	//根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。
	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

	Object getBean(String name, Object... args) throws BeansException;

	<T> T getBean(Class<T> requiredType) throws BeansException;

	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	//提供对bean的检索,看看是否在IOC容器有这个名字的bean
	boolean containsBean(String name);

	//根据bean名字得到bean实例,并同时判断这个bean是不是单例
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	//得到bean实例的Class类型
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	//得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
	String[] getAliases(String name);
}

1.2, сценарии использования BeanFactory

1. Получите Bean (по имени или по типу) из контейнера Ioc.

2. Узнать, содержится ли указанный bean-компонент в Ioc-контейнере. 3. Определите, является ли компонент одноэлементным

2. ФабрикаБин

Во-первых, FactoryBean — это Bean, но это не просто Bean, звучит противоречиво, но почему вы так говорите? На самом деле в Spring все bean-компоненты управляются BeanFactory (то есть IOC-контейнером). Но для FactoryBeanЭтот FactoryBean не просто Bean, а фабричный Bean, который может производить или модифицировать объекты Его реализация аналогична шаблону factory и шаблону декоратора в шаблоне проектирования.

2.1 Почему FactoryBean?

В общем, Spring использует атрибут класса механизма отражения, чтобы указать класс реализации для создания экземпляра компонента. Что касается того, почему существует FactoryBean? Есть две причины:

1, В некоторых случаях процесс создания экземпляра bean-компонента сложен, и большое количество информации о конфигурации необходимо предоставить традиционным способом. Гибкость метода конфигурации ограничена, и простое решение может быть получено с использованием метода кодирования. Весна обеспечиваетorg.springframework.bean.factory.FactoryBeanИнтерфейс фабричного класса, пользователи могут настраивать логику создания экземпляров bean-компонентов, реализуя этот интерфейс. Интерфейс FactoryBean занимает важное место в среде Spring, а сам Spring предоставляет более 70 реализаций FactoryBean. Они скрывают детали создания экземпляров некоторых сложных bean-компонентов и обеспечивают удобство для приложений верхнего уровня.

2, Поскольку сторонняя библиотека не может быть напрямую зарегистрирована в контейнере Spring, это может быть достигнутоorg.springframework.bean.factory.FactoryBeanинтерфейс, а затем укажите код создания вашего собственного объекта.

2.2, исходный код FactoryBean

public interface FactoryBean<T> {
	//从工厂中获取bean【这个方法是FactoryBean的核心】
	@Nullable
	T getObject() throws Exception;
	
	//获取Bean工厂创建的对象的类型【注意这个方法主要作用是:该方法返回的类型是在ioc容器中getbean所匹配的类型】
	@Nullable
	Class<?> getObjectType();
	
	//Bean工厂创建的对象是否是单例模式
	default boolean isSingleton() {
		return true;
	}
}

Введение метода:1, Метод getobject() вернет экземпляр объекта, «созданный» FactoryBean, нам нужно реализовать этот метод, чтобы дать нашу собственную логику создания объекта; 2, Метод getobjectTYype() возвращает только тип объекта, возвращаемый методом getobject(), или null, если он не может быть определен заранее; обратите особое внимание на основную функцию этого метода:тип возврата методанаходится в ioc-контейнеретип, соответствующий getbean, то есть в ioc есть много типов bean-компонентов.Чтобы найти этот bean-компонент, нужно использовать тип возвращаемого значения метода getobjectTYype()! хорошо, позвольте мне привести пример

public class XXX implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new YYY;
    }       
    @Override
    public Class<?> getObjectType() {  //注意这个方法主要作用是:该方法返回的类型是在ioc容器中getbean所匹配的类型
        return AAA.class;
    }
}

那么要想在ioc中找到XXX这个类的bean(实际上是YYY) ,在getbean的时候写法如下

public class Demo1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = 
                new AnnotationConfigApplicationContext(Appconfig.class);
                
        annotationConfigApplicationContext.getBean( AAA.class ); // 【注意这里是AAA.class】

    }
}

3. Результат, возвращаемый методом isSingleton(), используется для указания того, что фабричный метод (getobject ()) должен ли «созданный» объект существовать в контейнере как синглтон. Возвращает true, если он существует как синглтон, в противном случае возвращает false;

FactoryBean представляет ответственность фабрики.То есть, если Bean A реализует интерфейс FactoryBean, то A становится фабрикой. Согласно имени A, на самом деле получается объект, возвращаемый фабрикой, вызывающей getObject(), а не сам A. Если вы хотите получить собственного экземпляра фабрики A, вам нужно добавить к имени префикс «&».Проще говоря, это

getObject('name') возвращает экземпляр на фабрике getObject(' &name ') возвращает экземпляр самой фабрики

Обычно бинам не нужно самим реализовывать шаблон фабрики, и контейнер Spring играет роль фабрики; но в некоторых случаях бины в контейнере сами являются фабриками, и их роль заключается в создании других экземпляров бина. Другие экземпляры bean-компонентов, созданные фабричным bean-компонентом, больше не создаются контейнером Spring, поэтому, в отличие от обычной конфигурации bean-компонента, элемент class больше не требуется.

2.3 、Пример кода FactoryBean

1. Создайте класс Appconfig для сканирования всех подпакетов в com.yichun.

@Configuration
@ComponentScan("com.yichun")
public class Appconfig {
}

2. Создайте класс StudentBean и реализуйте FactoryBean, а также перепишите два его метода.

@Component("studentBean")
public class StudentBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new TeacherBean();
    }
   
    @Override
    public Class<?> getObjectType() {  //注意这个方法主要作用是:该方法返回的类型是在ioc容器中getbean所匹配的类型
        return StudentBean.class;
    }
    //一个学生学习方法
    public void study(){
        System.out.println("学生学习。。。");
    }
}

3. Создайте еще один класс TeacherBean

public class TeacherBean {
    public void teacher(){
        System.out.println("老师教书。。。。");
    }
}

4. Протестируйте тип StudentBean

public class Demo1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);
        StudentBean studentBean = (StudentBean)annotationConfigApplicationContext.getBean("studentBean");
        studentBean.study();
    }
}

在这里插入图片描述Добавить "&"символ

public class Demo1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);
        //加上了“&”符号
        StudentBean studentBean = (StudentBean)annotationConfigApplicationContext.getBean("&studentBean");
        studentBean.study();
    }
}

在这里插入图片描述запустить успешно

5. Протестируйте тип TeacherBean

public class Demo1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);    
        TeacherBean teacherBean = (TeacherBean) annotationConfigApplicationContext.getBean("studentBean");       
        teacherBean.teacher();
    }
}

запустить успешно在这里插入图片描述

2.4 Сценарии использования FactoryBean

Сценарий первый:Одним из наиболее типичных применений FactoryBean в Spring является создание прокси-объектов АОП. Мы знаем, что АОП на самом деле создает прокси-объект Spring во время выполнения, а это означает, что этот объект создается нами во время выполнения, а не определяется в начале, что соответствует шаблону фабричного метода. Более наглядно, прокси-объект АОП создает прокси-объект во время выполнения с помощью механизма отражения Java и вплетает соответствующие методы в целевой метод прокси-объекта в соответствии с бизнес-требованиями. Этот объект в Spring -ProxyFactoryBean.

Итак, FactoryBean обеспечивает более гибкий способ для нас до создания фасоли, мы можем создать более сложный экземпляр бобов на FactoryBean.

Конечно, весной FactoryBean используется во многих местах внутри контейнера Spring. Вот некоторые из наиболее распространенных реализаций FactoryBean:

JndiobjectFactoryBean

LocalSessionFactoryBean SqlMapClientFactoryBean ProxyFactoryBean TransactionProxyFactoryBean

Используйте второй сценарий:в МибатисеSqlSessionFactoryBean

<bean id="tradeSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="trade" />
        <property name="mapperLocations" value="classpath*:mapper/trade/*Mapper.xml" />
        <property name="configLocation" value="classpath:mybatis-config.xml" />
        <property name="typeAliasesPackage" value="com.bytebeats.mybatis3.domain.trade" />
    </bean>

package org.mybatis.spring;

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);
        ......
}

Кроме того, платформа распределенных услуг Ali с открытым исходным кодомDubboПотребитель также использует FactoryBean,

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
    ">
     
    <!-- 当前应用信息配置 -->
    <dubbo:application name="demo-consumer" />
   
   <!-- 暴露服务协议配置 -->
    <dubbo:protocol name="dubbo" port="20813" />    

    <!-- 暴露服务配置 -->
    <dubbo:reference id="demoService" interface="com.alibaba.dubbo.config.spring.api.DemoService"  />
     
</beans>

<dubbo:referenceСоответствующий компонентcom.alibaba.dubbo.config.spring.ReferenceBeanДобрый.

Используйте третий сценарий: HibernateсерединаSessionFactoryBean. Это не будет изложено здесь.

В конце концов, в этой статье неизбежно будут неточности, прошу исправлять и судить! Поправки и оценки приветствуются! Поправки и оценки приветствуются! ! !

Ссылаться на: "Весенний секрет" Ван Фуцянzhuanlan.zhihu.com/p/87382038 Блог Woohoo.cn на.com/aspirant/afraid/…