[Código fuente de Spring: FactoryBean One] Finalmente, comprenda cómo FactoryBean personaliza el proceso de creación de beans

Introducción

En nuestro desarrollo diario de JavaWeb, deberíamos haber visto o usado la clase FactoryBean. Muchas personas probablemente no entendieron la diferencia entre ella y BeanFactory, o en la entrevista, se les puede preguntar sobre la diferencia entre BeanFactory y FactoryBean en Spring. . Quizás muchos de nosotros no nos hemos personalizado para extender y usar FactoryBean, pero ¿puede revisar qué marcos se le han aplicado? Por ejemplo: FeignClientFactoryBean de Feign, MapperFactoryBean de mybatis-spring, SqlSessionFactoryBean, etc. se extienden para implementar la interfaz FactoryBean de Spring, personalizando el proceso de creación de Bean y generando objetos proxy para la interfaz Feign y la interfaz Mapper a través de un proxy dinámico, protegiendo una gran complejidad en la parte inferior. Para la lógica empresarial repetida, como la conexión Http y el empalme SQL, no es necesario escribir clases de implementación durante el desarrollo .

En general, Spring usa el atributo de clase para especificar la clase de implementación para instanciar el Bean a través del mecanismo de reflexión . En algunos casos, el proceso de instanciar el Bean es más complicado. Si sigue la forma tradicional, necesita proporcionar mucha información de configuración aquí. La flexibilidad del método de configuración es limitada, en este momento se puede obtener un esquema simple usando el método de codificación . Spring proporciona una interfaz de fábrica de org.springframework.bean.factory. FactoryBean para este propósito , y los usuarios pueden personalizar la lógica de instanciar Bean implementando esta interfaz .

  • FactoryBean es un Bean de fábrica que puede generar cierto tipo de instancia de Bean, una de sus funciones más importantes es permitirnos personalizar el proceso de creación de Bean .
  • BeanFactory es una clase básica en el contenedor Spring y también una clase muy importante. BeanFactory puede crear y administrar Beans en el contenedor Spring. Tiene un proceso unificado para la creación de Bean .

La interfaz FactoryBean se define de la siguiente manera:

public interface FactoryBean<T> {

	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    // 这个方法,我们可以自定义返回bean实例
	@Nullable
	T getObject() throws Exception;

    // 返回bean类型,可判断传入的class类型是否一致
	@Nullable
	Class<?> getObjectType();

    // 默认实现:true-单例,flase-原型
	default boolean isSingleton() {
		return true;
	}

}

Antes de entrar en el tema, tomemos un pequeño postre, escriba un ejemplo de prueba simple y luego buceemos lentamente en el código fuente de FactoryBean para analizar cómo personaliza el proceso de creación de Bean, ya que el espacio es un poco largo, este artículo se enfoca primero en el análisis Class <?> Método getObjectType (), el siguiente artículo analizará getObject () en detalle.

Definir una interfaz de servicio relacionada con pedidos

public interface IOrderService {

    void saveOrder();

}

Clase de implementación de servicio, no hay una anotación de bean de primavera: @Service, y no es necesario configurar el bean en xml, para probar cómo obtener el bean a través de un FactoryBean personalizado.

//@Service
public class OrderServiceImpl implements IOrderService {

    @Override
    public void saveOrder() {
        System.out.println("-----创建订单------");
    }
}

Implementación personalizada de FactoryBean: OrderFactoryBean, recuerde agregar la anotación @Component, este bean es administrado por el contenedor Spring ioc (orderFactoryBean)

/**
 * @description: 自定义FactoryBean实现
 * @author: stwen_gan
 * @date: 
 **/
@Component
public class OrderFactoryBean implements FactoryBean {

    /**
     * 自定义bean的创建过程
     */
    @Override
    public Object getObject() throws Exception {
        System.out.println("-----调用OrderFactoryBean.getObject----");
        // 1、直接new
        IOrderService orderService = new OrderServiceImpl();
        return orderService;

        // 2、通过动态代理,无需实现类,如 Mybatis的xxxMapper接口
//        OrderMapper bean = (OrderMapper) Proxy.newProxyInstance(OrderFactoryBean.class.getClassLoader(), new Class[]{OrderMapper.class}, new InvocationHandler() {
//            @Override
//            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                // todo
//                System.out.println(method.getName());
//                return null;
//            }
//        });
//        return bean;

    }

    /**
     * 返回bean的class类型
     */
    @Override
    public Class<?> getObjectType() {
        return IOrderService.class;

    }

    /**
     * 是否单例,默认单例
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

Para mayor comodidad, puede directamente crear una nueva clase de implementación OrderServiceImpl en el método getObject () . Por supuesto , también es posible generar un objeto proxy a través de un proxy dinámico . No se analiza aquí, se ha comentado y puede probarlo usted mismo sin prestar atención.

Categoría de prueba:

/**
 * @description: 测试
 * @author: stwen_gan
 * @date: 
 **/
public class FactoryBeanTest {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext(MyConfig.class);

        //测试自定义FactoryBean实现getObject产生bean 
        IOrderService bean = context.getBean(IOrderService.class);
        System.out.println(bean);
        System.out.println("---------------------");

        System.out.println(context.getBean("orderFactoryBean"));// bean是OrderServiceImpl,并不是OrderFactoryBean
        System.out.println(context.getBean("orderFactoryBean"));// 测试是否单例
        System.out.println(context.getBean("orderFactoryBean"));// 测试是否单例
    }
}

Ejecutar salida:

Se puede encontrar que las instancias de bean obtenidas son todas iguales, porque el método isSingleton anterior devuelve verdadero (singleton).

Pregunta :

  1. Esta interfaz IOrderService y la clase de implementación OrderServiceImpl, no agregamos anotaciones de bean (solo interfaz / clase ordinaria), pero podemos obtenerla del contenedor IoC a través del método context.getBean.
  2. El objeto bean obtenido por context.getBean ("orderFactoryBean") no es el objeto OrderFactoryBean en sí, sino el objeto OrderServiceImpl devuelto en el método OrderFactoryBean.getObject. ¿Cómo se implementa?
  3. ¿Qué pasa si queremos obtener el objeto OrderFactoryBean en sí?

Para comprender el misterio de FactoryBean de Spring, comenzamos directamente con el método getBean, que es un método de  AbstractApplicationContext , y muchas subclases sobrecargan sus métodos, de la siguiente manera:

	// 根据Class类型获取bean
    @Override
	public <T> T getBean(Class<T> requiredType) throws BeansException {
		// 检查BeanFactory的激活状态
        assertBeanFactoryActive();
        //getBeanFactory()获取到的是一个DefaultListableBeanFactory的默认实例
		return getBeanFactory().getBean(requiredType);
	}

    // 根据beanName获取bean
	@Override
	public Object getBean(String name) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name);
	}

Aquí, solo analizamos el método getBean (Class <T> requiredType) para obtener beans de acuerdo con el tipo de Class, y lo que pasamos es el tipo IOrderService.class.

Entre ellos, getBeanFactory () obtiene una instancia predeterminada de DefaultListableBeanFactory , por lo que debemos ir a DefaultListableBeanFactory para ver la implementación específica del método getBean:

DefaultListableBeanFactory # getBean (Class <T> requiredType)

	@Override
	public <T> T getBean(Class<T> requiredType) throws BeansException {
		return getBean(requiredType, (Object[]) null);
	}

	@Override
	public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
		Assert.notNull(requiredType, "Required type must not be null");
        // 根据传入的Class类型、参数等解析bean
		Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
		if (resolved == null) {
			throw new NoSuchBeanDefinitionException(requiredType);
		}
		return (T) resolved;
	}

En el código anterior, nos centramos en el método resolveBean:

	@Nullable
	private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
        // 解析bean
		NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
		if (namedBean != null) {
			return namedBean.getBeanInstance();
		}
        //如果当前Spring容器获取不到相应的bean信息,则从父容器中获取
        //SpringMVC是一个很典型的父子容器
		BeanFactory parent = getParentBeanFactory();
		if (parent instanceof DefaultListableBeanFactory) {
			return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
		}
		else if (parent != null) {
			ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
			if (args != null) {
				return parentProvider.getObject(args);
			}
			else {
				return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
			}
		}
		return null;
	}

Concéntrese en seguir el método resolveNamedBean, cómo resolver beanName:

	@Nullable
	private <T> NamedBeanHolder<T> resolveNamedBean(
			ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {

		Assert.notNull(requiredType, "Required type must not be null");
        //这个方法是根据传入的Class类型来获取BeanName,因为一个接口可以有多个实现类的情况(多态),
        //所以这里返回的是一个String数组,这个过程也比较复杂。
        //这里需要注意的是,我们调用getBean方法传入的type为com.example.demo.spring.factorybean.IOrderService类型,但是我们没有在Spring容器中注入IOrderService类型的Bean
        //正常来说我们在这里是获取不到beanName的,但是事实是不是这样呢?看下面我们对getBeanNamesForType的分析
		String[] candidateNames = getBeanNamesForType(requiredType);

        // 如果有多个BeanName,则筛选合适的BeanName
        // 自动注入相关的判断
		if (candidateNames.length > 1) {
            // 自动注入的bean候选者
			List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
			for (String beanName : candidateNames) {
				if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
					autowireCandidates.add(beanName);
				}
			}
			if (!autowireCandidates.isEmpty()) {
                // list 转 String 数组,放入候选的beanNames中
				candidateNames = StringUtils.toStringArray(autowireCandidates);
			}
		}

        //如果BeanName只有一个, 我们调用getBean方法来获取Bean实例来放入到NamedBeanHolder中
        //这里getBean是根据beanName,bean的Class类型和参数来获取bean
		if (candidateNames.length == 1) {
			String beanName = candidateNames[0];
			return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
		}
		else if (candidateNames.length > 1) {
            // 将候选bean放入一个map
			Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
			for (String beanName : candidateNames) {
                //从单例池中根据beanName获取该bean对象
				if (containsSingleton(beanName) && args == null) {
                    // 根据beanName获取bean
					Object beanInstance = getBean(beanName);
					candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
				}
				else {
                    //单例池中没有获取到该bean,则通过getType方法继续获取Bean实例
					candidates.put(beanName, getType(beanName));
				}
			}
            //有多个Bean实例的话 则取带有Primary注解或者带有Primary信息的Bean
			String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
			if (candidateName == null) {
                //如果没有Primary注解或者Primary相关的信息,则取优先级高的Bean实例
				candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
			}
            // 最终获取到一个合适的beanName后,就可以根据Class类型,继续调用getBean方法获取Bean实例
			if (candidateName != null) {
				Object beanInstance = candidates.get(candidateName);
				if (beanInstance == null || beanInstance instanceof Class) {
					beanInstance = getBean(candidateName, requiredType.toClass(), args);
				}
				return new NamedBeanHolder<>(candidateName, (T) beanInstance);
			}
            // 如果都没有获取到,则抛异常
			if (!nonUniqueAsNull) {
				throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
			}
		}

		return null;
	}

En el método anterior, el tipo que pasamos es el tipo de interfaz com.example.demo.spring.factorybean.IOrderService, pero no hemos configurado el bean de esta interfaz o clase de implementación en el contenedor Spring, entonces, ¿cómo lo obtenemos de getBeanNamesForType ¿Qué pasa con beanName?
A continuación, analizamos getBeanNamesForType:

	@Override
	public String[] getBeanNamesForType(ResolvableType type) {
		return getBeanNamesForType(type, true, true);
	}

	@Override
	public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
		Class<?> resolved = type.resolve();
        // type解析不为空
		if (resolved != null && !type.hasGenerics()) {
			return getBeanNamesForType(resolved, includeNonSingletons, allowEagerInit);
		}
		else {
			return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
		}
	}

	@Override
	public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
		if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
			return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
		}
        //先从缓存中获取:根据Class类型获取符合的beanNames
		Map<Class<?>, String[]> cache =
				(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
		String[] resolvedBeanNames = cache.get(type);
        // 获取到直接返回
		if (resolvedBeanNames != null) {
			return resolvedBeanNames;
		}
        // 获取不到,则调用doGetBeanNamesForType方法获取符合的beanNames
        // 下面会详细分析此方法
		resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
        //判断我们传入的类能不能被当前类加载加载
		if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
            //放入到缓存中,方便下次直接从缓存中获取
            //key:IOrderService,Value:orderFactoryBean
			cache.put(type, resolvedBeanNames);
		}
		return resolvedBeanNames;
	}

Sigue a través de la depuración y el análisis encontrado, caché de caché, la clave es que pasamos com.example.demo.spring.factorybean.IOrderService de Class , pero es nuestra implementación de FactoryBean de valor personalizado OrderFactoryBean correspondiente beanName --orderFactoryBean (nosotros La anotación @Component se agrega a la clase OrderFactoryBean y se agrega a la administración de Spring IoC), este beanName no es orderService . Este es también el tema central de este artículo. Es muy importante comprender este problema. ¿Cómo asocia el beanName correspondiente a OrderFactoryBean con IOrderService.class?

Por lo tanto, necesitamos analizar el método doGetBeanNamesForType, cómo obtiene el beanName de OrderFactoryBean a través del tipo IOrderService.Class entrante :

	private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
		List<String> result = new ArrayList<>();

		// Check all bean definitions.
        //循环检查IoC中所有的beanName,这个是在Spring容器启动解析Bean的时候放入到这个List中的
		for (String beanName : this.beanDefinitionNames) {
			// Only consider bean as eligible if the bean name
			// is not defined as alias for some other bean.
            // 只有当bean名称没有定义为其他bean的别名时,才是符合要求的
			if (!isAlias(beanName)) {
				try {
                    //根据beanName获取RootBeanDefinition
					RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
					// Only check bean definition if it is complete.
                    // 这里检查beanDefinition信息的完整性
					if (!mbd.isAbstract() && (allowEagerInit ||
							(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
									!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
                        // 根据beanName与RootBeanDefinition 判断是否FactoryBean的子类
						boolean isFactoryBean = isFactoryBean(beanName, mbd);
						BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();

                        // 类型、beanName等信息是否匹配
						boolean matchFound = false;
						boolean allowFactoryBeanInit = allowEagerInit || containsSingleton(beanName);
						boolean isNonLazyDecorated = dbd != null && !mbd.isLazyInit();
						// 普通bean(非FactoryBean子类)
                        if (!isFactoryBean) {
							if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
								matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
							}
						}
                        // FactoryBean 子类
						else  {
							if (includeNonSingletons || isNonLazyDecorated ||
									(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
                                // 下面会重点分析此isTypeMatch方法
								matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
							}
                            // matchFound=false时
							if (!matchFound) {
								// In case of FactoryBean, try to match FactoryBean instance itself next.
                                //如果不匹配,需要给beanName添加一个统一的前缀&,&beanName 表示这是FactoryBean子类对应的beanName
								beanName = FACTORY_BEAN_PREFIX + beanName;
								matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
							}
						}
                        // matchFound=true,则表示符合,添加此beanName到result返回
						if (matchFound) {
							result.add(beanName);
						}
					}
				}

			}
		}
        // 省略部分无关代码。。。。

		return StringUtils.toStringArray(result);
	}

En el método anterior, primero recorra todos los beanNames en Spring, obtenga la RootBeanDefinition correspondiente de acuerdo con beanName, y luego  juzgue si coincide con el beanName actual de acuerdo con el tipo ResolvableType (es decir, IOrderService.class ) que pasamos en : matchFound = isTypeMatch ( beanName, tipo, allowFactoryBeanInit) .

Al atravesar el beanName correspondiente a nuestro OrderFactoryBean , se encuentra que es una subclase de FactoryBean , e ingresará el else, y luego usará el método isTypeMatch para determinar si coincide con el IOrderService.class que pasamos . Como sigue, la depuración encontró que coincide. Es decir, matchFound = true, y finalmente este beanName se agregará al resultado devuelto:

Entre ellos, beanName = FACTORY_BEAN_PREFIX + beanName; (FACTORY_BEAN_PREFIX = "&") , aquí cuando matchFound = false, ¿por qué agregar un prefijo & al beanName correspondiente a la subclase FactoryBean?

-> Para obtener el bean de objeto de la subclase FactoryBean, puede pasar  context.getBean (" & orderFactoryBean"), puede probarlo usted mismo y generar:

com.example.demo.spring.factorybean.OrderFactoryBean@1f0f1111

El siguiente es un pequeño truco para depurar, agregando puntos de interrupción condicionales:

Entonces, aquí analizaremos el método isTypeMatch , que es cómo hacer coincidir el tipo de juicio, ¿cómo se asociarán OrderFactoryBean correspondiente beanName e IOrderService ?

	protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)
			throws NoSuchBeanDefinitionException {

        //转换beanName,这里只探讨beanName为orderFactoryBean时isTypeMatch返回的结果
		String beanName = transformedBeanName(name);
		boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);

        //这里是用AbstractApplicationContext的子类来从Spring容器中获取Bean,
        //获取beanName为orderFactoryBean的Bean实例 (IoC是可以获取到的,因为我们有在OrderFactoryBean类上添加@Component注解)
		Object beanInstance = getSingleton(beanName, false);// beanName:orderFactoryBean-->OrderFactoryBean
		if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
            //判断获取到的OrderFactoryBean是否是FactoryBean的实例
			if (beanInstance instanceof FactoryBean) {
                //这里判断beanName是不是以&开头,这里明显不是(“orderFactoryBean”),这里可以想一下什么情况下会有&开头的Bean,上面也有说明
				if (!isFactoryDereference) {
                    //这里就是从OrderFactoryBean实例中获取type类型,下面会分析一下这个方法
					Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
                    //从OrderFactoryBean中获取到的type类型和我们传入的类型是不是同一种类型,是则直接返回true
					return (type != null && typeToMatch.isAssignableFrom(type));
				}
				else {
					return typeToMatch.isInstance(beanInstance);
				}
			}
        // 省略。。。

Entre ellos, Object beanInstance = getSingleton (beanName, false) , para obtener el bean correspondiente del contenedor Spring, aquí hay una pregunta:

¿Cuál es la diferencia entre usar una subclase de AbstractApplicationContext para obtener un Bean del contenedor Spring y usar una subclase de BeanFactory para obtener un Bean del contenedor?

El primero obtiene la instancia de bean correspondiente a beanName (orderFactoryBean: OrderFactoryBean), y el segundo obtiene el objeto de instancia devuelto por el método personalizado getObject () en nuestra subclase BeanFactory (es decir, orderFactoryBean: OrderServiceImpl).

A continuación, analice getTypeForFactoryBean

	@Nullable
	protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
		try {
			if (System.getSecurityManager() != null) {
				return AccessController.doPrivileged((PrivilegedAction<Class<?>>)
						factoryBean::getObjectType, getAccessControlContext());
			}
			else {
                //看到这是不是很熟悉了,实际调用FactoryBean实例的getObjectType()方法
				return factoryBean.getObjectType();
			}
		}
        // 省略。。。
	}

A través de las capas del análisis anterior, la llamada finalmente encontró nuestra costumbre OrderFactoryBean de GetObjectType método para obtener el valor: com.example.demo.spring.factorybean.IOrderService , y pasamos tipo es del mismo tipo. Así que aquí devuelve verdadero, de acuerdo con nuestro análisis: si isTypeMatch devuelve verdadero, el beanName que devolvemos es orderFactoryBean . Entonces, finalmente entendemos: llamamos context.getBean ( IOrderService .class), coloca OrderFactoryBean correspondiente beanName y IOrderService asociado a.

para resumir

No configuramos IOrderService / OrderServiceImpl como Spring beans, es decir, no hay BeanDefinition correspondiente en el contenedor Spring, y los beans correspondientes no se pueden obtener a través de IOrderService.class , pero hemos personalizado un Bean de fábrica (OrderFactoryBean) y El tipo de IOrderService se relaciona de la siguiente manera:

Cuando obtenemos el bean de acuerdo con el tipo a través de   IOrderService bean = context.getBean (IOrderService.class) , el Spring subyacente primero obtendrá el beanName correspondiente:

Primero recorra todos los beanNames en el contenedor Spring, y luego obtenga la BeanDefinition correspondiente de acuerdo con el beanName. Si el bean actual es del tipo FactoryBean , la instancia de Bean correspondiente se obtendrá del contenedor Spring de acuerdo con el beanName, y luego llame al método getObjectType de la instancia de Bean obtenida para obtener Vaya al tipo de clase para determinar si este tipo de clase y la clase que pasamos son del mismo tipo. Si es así, devuelva este beanName, correspondiente a nuestro ejemplo: obtenga la instancia OrderFactoryBean de acuerdo con orderFactoryBean, llame al método getObjectType de OrderFactoryBean para obtener el valor de retorno IOrderService.class . Es consistente con el tipo que pasamos, por lo que el beanName obtenido aquí es orderFactoryBean . En otras palabras, aquí orderFactoryBean beanName este orden de mapeo : tipo IOrderService , es decir , IOrderService correspondiente al tipo de beanName orderFactoryBean . A través de este artículo, entiendo el rol de getObjectType en los tres métodos de Factory. El siguiente artículo analizará: getBean (String name, Class requiredType, Object ... args) Este método, cómo FactoryBean finalmente devuelve nuestro bean personalizado.

Finalmente, dibujé una versión simple del diagrama de flujo de FactoryBean, describiendo cómo el tipo de clase que pasamos (IOrderService.calss) y nuestra subclase FactoryBean personalizada están relacionados, es decir, llamamos getBean (IOrderService.class) , La capa inferior eventualmente llamará a factoryBean.getObjectType () para ayudarnos a aclarar el contexto como un todo (haga clic para ampliar la imagen):

Referencia: https://blog.csdn.net/zknxx/article/details/79572387

● La optimización de rendimiento de Tomcat8 más sólida de la historia

¿Por qué Alibaba puede resistir 10 mil millones en 90 segundos? - La evolución de la arquitectura distribuida de alta concurrencia del lado del servidor

Plataforma de comercio electrónico B2B: función de pago electrónico ChinaPay UnionPay

Aprenda el candado distribuido de Zookeeper, deje que los entrevistadores lo miren con admiración

Solución de bloqueo distribuido de Redisson con microservicio de pico de comercio electrónico de SpringCloud

Vea más artículos buenos, ingrese a la cuenta oficial, por favor, excelente en el pasado

Una cuenta pública profunda y conmovedora 0.0

 

Supongo que te gusta

Origin blog.csdn.net/a1036645146/article/details/111661211
Recomendado
Clasificación