Version of the agreement

Unless otherwise noted, this article is based on the following versions:

1.85.2.2. RELEASECopy the code

The body of the

Article introduces the proxy object two interceptor with the former, namely BeanFactoryAwareMethodInterceptor, it will intercept setBeanFactory () method to complete assigned to the proxy class attribute assignment. You’ve fooled a lot of interviewers with the first interceptor, but it still doesn’t explain one of our most common puzzles: why do you end up pointing to the same Bean by calling the @bean method?

With this question in mind, begin the statement of this article. Please fasten your seat belts and get ready to start…

Error in using Spring configuration classes

This section describes different configurations. From Lite mode to Full mode to solve the problem, finally explain why this effect is analyzed/source code analysis.

Lite mode: Wrong pose

The configuration class:

public class AppConfig {

    @Bean
    public Son son() {
        Son son = new Son();
        System.out.println("son created..." + son.hashCode());
        return son;
    }

    @Bean
    public Parent parent() {
        Son son = son();
        System.out.println("parent created... Holding Son is:" + son.hashCode());
        returnnew Parent(son); }}Copy the code

Run the program:

public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); AppConfig appConfig = context.getBean(AppConfig.class); System.out.println(appConfig); Son Son = context.getBean(son.class); Parent parent = context.getBean(Parent.class); System.out.println("Son instance in container:" + son.hashCode());
    System.out.println("Son instance held by Person in container:" + parent.getSon().hashCode());
    System.out.println(parent.getSon() == son);
}
Copy the code

Running results:

son created... 624271064 son created... 564742142 parent created... Hold of the Son is: 564742142 com. Yourbatman. Fullliteconfig. Config. The AppConfig @ 1 a38c59b container instances of Son: 624271064 container Person holding the Son of instances: 564742142false
Copy the code

Results analysis:

  • The Son instance was created twice. Obviously these two are not the same instance

In that case, there is a problem. The problem is manifested in these two aspects:

  1. The Son object was created twice, and the singleton pattern was broken
  2. For the Parent instance, the Son it depends on is no longer the Bean in the IoC container, but a very ordinary POJO object. So the Son object will not enjoy any of the “benefits” of Spring, which is generally problematic in real world scenarios

This situation must be avoided in production, how to break it? Here are the correct poses to use in Lite mode.

Lite mode: Correct posture

In fact, this problem, now so intelligent IDE (such as IDEA) can teach you how to do:

As indicated, dependency injection can be used instead to avoid this problem, as follows:

// @Bean
// public Parent parent() {
//     Son son = son();
//     System.out.println("parent created... Holding Son is:" + son.hashCode());
//     return new Parent(son);
// }

@Bean
public Parent parent(Son son){
    System.out.println("parent created... Holding Son is:" + son.hashCode());
    return new Parent(son);
}
Copy the code

Run the program again, and the result is:

son created... 624271064 parent created... Hold of the Son is: 624271064 com. Yourbatman. Fullliteconfig. Config. The AppConfig @ 667 a738 container instances of Son: 624271064 container Person holding the Son of instances: 624271064true
Copy the code

Bingo, perfect solution. If you insist on Lite mode, be aware of its pros and cons (Full mode vs. Lite mode, see this article).

If you haven’t read it carefully, you may ask: I wrote it in the first way, but it works fine. Say you are not careful indeed, do not believe you go back and look at the comparison. If you use the first method and can “work”, please check the @Configuration annotation on the class head.

Full mode:

Full mode is the most fault-tolerant mode. You can create anything you want.

Of course, the method cannot be private/final. But normally who would drop a final method ina configuration? You tell me

@Configuration
public class AppConfig {

    @Bean
    public Son son() {
        Son son = new Son();
        System.out.println("son created..." + son.hashCode());
        return son;
    }

    @Bean
    public Parent parent() {
        Son son = son();
        System.out.println("parent created... Holding Son is:" + son.hashCode());
        returnnew Parent(son); }}Copy the code

Run the program and the resulting output:

son created... 1797712197 parent created... Hold the Son is: 1797712197 com. Yourbatman. Fullliteconfig. Config. AppConfig $$EnhancerBySpringCGLIB$$8ef51461Son instance in container: 1797712197 Son instance held by Person in container: 1797712197true
Copy the code

The result was perfect. It ensures that you get an instance object from the IoC container by calling the @bean labeled method, rather than creating a new one. There is another difference between Lite mode and Lite mode: it generates a proxy subclass of CGLIB for the configuration class to put into the container, whereas Lite mode puts native objects into the container.

Everything has a price, everything is a trade-off. Native is the most efficient and the most friendly way to Cloud Native. However, in practical “recommended use”, business development usually only uses the Full mode. After all, the level of business development students is uneven, so fault tolerance is crucial.

If you’re a container developer, middleware developer… Lite mode configuration is recommended to prepare for containerization and Cloud Native

Full mode is the most common way to use the user side, so let’s take a look at what Spring did to make it possible to call the @bean method to the same instance without going into the method body.

BeanMethodInterceptor interceptor

Finally, the main course of the day. This article skips the previous process analysis and dives straight into the BeanMethodInterceptor, which is the latter of the two interceptors.

Tips: Make sure you understand the process analysis in the previous article, otherwise the following will easily cause mental problems

Compared to the last interceptor, this interceptor is not less complex. Its official role is to intercept calls to any method annotated with @Bean annotations to ensure proper handling of Bean semantics, such as scopes (don’t ignore it) and AOP proxies.

It’s complicated, but there’s nothing to be afraid of. Just take it one step at a time. Again, I get to know it in two steps: when to execute + what to do.

Execution time

Nonsense not to say, directly combined with the source code to explain.

Beaninterceptor: @override public Boolean isMatch(Method candidateMethod) {return(candidateMethod.getDeclaringClass() ! = Object.class && ! BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) && BeanAnnotationHelper.isBeanAnnotated(candidateMethod)); }Copy the code

Three lines of code, three conditions:

  1. This method cannot Bean Object method (even if your Object method annotates @bean).
  2. It cannot be the setBeanFactory() method. This is easy to understand, it can be left to the last interceptor
  3. Methods must be annotated with @bean annotations

In short, the @bean annotation method execution is intercepted **.

So it intercepts the son() and parent() methods in the following example, as well as the son() method called in parent()

A static Method or an ordinary Method participates in this logic

What do the

Here is the concrete interception logic, which will be much more complex than the first interceptor. Source code is not very much, but involved in things really many, such as AOP, such as Scope, such as the creation of beans and so on, it is quite laborious to understand.

This method intercepts the execution of the parent() method as an example, combined with source code to trace the explanation:

// beanMethod: parent() method // beanMethodArgs: // beanMethodArgs: Null // cglibMethodProxy: proxy. @override @Nullable Public Object Intercept (Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable {// Obtain the Bean factory through reflection. That is $$beanFactoryConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance); / / get the Bean's name String beanName = BeanAnnotationHelper. DetermineBeanNameFor (beanMethod); The parent() method is annotated with @scoped annotation ~~~if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
		String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
		if(beanFactory.isCurrentlyInCreation(scopedBeanName)) { beanName = scopedBeanName; }} / / = = = = = = = = here to deal with the situation of method reference between bean = = = = = = = = / / : first check whether the requested bean is FactoryBean. If so, create a proxy subclass that intercepts its getObject() method to return the instance in the container. // This ensures that the method returning a FactoryBean has the same semantics as @bean. Ensures that you do not create multiple beans repeatedlyif(factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) && factoryContainsBean(beanFactory, Object factoryBean = beanfactory.getBean (beanfactory.bean_prefix + beanName);if (factoryBean instanceof ScopedProxyFactoryBean) {
			// Scoped proxy factory beans are a special caseAnd should not be further proxied // if the FactoryBean is already a Scope proxy Bean, it should not be further enhanced // because it is already capable of delaying the initialization of beans by FactoryBean ~} // further enhancedelse {
			returnenhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName); }} // Check whether the given method corresponds to the factory method of the currently invoked container. // Compare the method name with the argument list to see if it is the same methodif(isCurrentlyInvokedFactoryMethod (beanMethod)) {/ / it's a small detail: If your @bean returns a BeanFactoryPostProcessor type // please use a static method, otherwise this log will be printed ~~~~ // because if it is a non-static method, some post-processing will fail to handle you, It may or may not affect your application, so it's just a suggestionif(logger.isInfoEnabled() && BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) { ... } // This means that the parent() method is the one being blocked, so there is nothing to say about it. // But, but, but, this is still the proxy classreturncglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs); } // The son() method called in the parent() method will be executed herereturn resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
Copy the code

Steps summary:

  1. Get the current BeanFactory factory object. The factory object through the first interceptor BeanFactoryAwareMethodInterceptor have already completed the Settings
  2. Determine the Bean name. The default is the method name. If specified via @bean, the specified value prevails. If multiple values are specified, the first value prevails
  3. Determine whether the current method (for example, the parent() method) is a Scope domain proxy. That is, if the method has an @scope annotation on it, if the domain proxy class does that, then it does that. BeanName changes to scopedTarget.parent to determine if the Bean scopedtarget. parent is being created… If so, replace the current beanName with scopedtarget.parent and focus on the Bean with the name scopedtarget.parent. Parent Bean scopedTarget.parent Bean scopedTarget.parent Bean scopedTarget.parent
  4. Determines whether the requested Bean is a FactoryBean FactoryBean. In the case of a factory Bean, you need to enhance the Bean to intercept its getObject() method by turning getObject() to the -> getBean() method when it executes: To ensure that an instance of a FactoryBean is obtained from the getBean() container, rather than creating one of its own
  5. Determine if this beanMethod is the factory method currently being called. Super (XXX) {super(XXX) {super(XXX) {super(XXX) {super(XXX)}} This is illustrated with code examples below. Since this case is the most common mainline case, get it done first

This is the execution of the interceptor, leaving two answers :question: I’ll explain each one (in reverse order) below.

Why don’t multiple calls to the @bean method produce new instances?

This is the most common case. Sample code:

@Configuration
public class AppConfig {

    @Bean
    public Son son() {
        Son son = new Son();
        System.out.println("son created..." + son.hashCode());
        return son;
    }

    @Bean
    public Parent parent() {
        notBeanMethod();
        Son son = son();
        System.out.println("parent created... Holding Son is:" + son.hashCode());
        return new Parent(son);
    }

    public void notBeanMethod(){
        System.out.println("notBeanMethod invoked by 【" + this + "】"); }}Copy the code

There are three methods in this configuration class:

  • Son () : labeled @bean.

So it eventually to cglibMethodProxy. InvokeSuper (enhancedConfigInstance beanMethodArgs); Method directly executes the body of the parent (that is, the target) class:

It is important to note that the object is still in the proxy object, the body of the method is only through the proxy class called super(XXX) method

  • Parent () : marked with @bean. It also calls notBeanMethod() and son() internally

The notBeanMethod() and son() methods will be called in the body of the target class.

  1. Call the notBeanMethod() method, which will not be intercepted because it has no @bean annotation -> execute the method body directly
  2. Calling the son() method, since it is annotated with the @bean annotation, continues into the interceptor. But note that unlike the son() method invoked above, the method currently being invoked is the parent() method, not the son() method, so he is referred to the resolveBeanReference() method:
BeanMethodInterceptor:  private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs, ConfigurableBeanFactory beanFactory, String beanName) {// Whether the current bean (son) is being created... This place isfalse: / / behind this judge is to prevent the getBean error ~ ~ ~ Boolean alreadyInCreation. = the beanFactory isCurrentlyInCreation (beanName); Try {// If the Bean is actually being created, mark it first and place the following getBean to report an error ~if (alreadyInCreation) {
			beanFactory.setCurrentlyInCreation(beanName, false); } getBean(beanName) or getBean(beanName,args); Call getBean(beanName) Boolean useArgs =! ObjectUtils.isEmpty(beanMethodArgs);if (useArgs && beanFactory.isSingleton(beanName)) {
			for (Object arg : beanMethodArgs) {
				if (arg == null) {
					useArgs = false;
					break; } beanInstance = (useArgs?) {} beanInstance = (useArgs? beanFactory.getBean(beanName, beanMethodArgs) : beanFactory.getBean(beanName)); // The return type of the method is compared to the actual type of the Bean, since the type may be different. This can occur when the BeanDefinition defines that the information type is overriddenif(! ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {if (beanInstance.equals(null)) {
				beanInstance = null;
			} else{... throw new IllegalStateException(msg); }} / / current Method is called, is the parent () Method currentlyInvoked = SimpleInstantiationStrategy. GetCurrentlyInvokedFactoryMethod ();if(currentlyInvoked ! = null) { String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked); / / this step is to register dependencies, tell the container: / / parent instance initialization depends on the beanFactory son instance. RegisterDependentBean (beanName outerBeanName); } // return the instancereturnbeanInstance; } // return tag: the note is actually still being created ~~~~ finally {if (alreadyInCreation) {
			beanFactory.setCurrentlyInCreation(beanName, true); }}}Copy the code

This way, after executing the son() method in the parent() body, we actually get the instance in the container, ensuring that we don’t have any problems writing this way.

  • NotBeanMethod () : Because it does not have the @bean annotation, it is not called by the container, but by the parent() method above, and is not intercepted.

The results of the above program are as follows:

son created... 347978868 notBeanMethod invoked by 【. Com. Yourbatman fullliteconfig. Config. AppConfig $$EnhancerBySpringCGLIB$$ec611337@ 12591 ac8 】 the parent created... Hold the Son is: 347978868 com. Yourbatman. Fullliteconfig. Config. AppConfig $$EnhancerBySpringCGLIB$$ec611337Son instance in container: 347978868 Son instance held by Person in container: 347978868true
Copy the code

As you can see, there is only one instance of Son throughout, which is what we expect.

How does it perform in Lite mode?

The same code, in Lite mode (without the @Configuration annotation), does not have “so complex” agent logic, so the result of the above example is:

son created... 624271064 notBeanMethod invoked by the com. Yourbatman. Fullliteconfig. Config. 21 a947fe AppConfig @ 】 son created... 90205195 parent created... Hold of the Son is: 90205195 com. Yourbatman. Fullliteconfig. Config. The AppConfig @ the Son of 21 a947fe container instance: 624271064 container Person holding the Son of instances: 90205195false
Copy the code

The result is easy to understand, but I won’t bore you here. Anyway, you can’t use it this way

FactoryBean pattern profiling

Factorybeans are also a way to provide beans to containers, such as the most common SqlSessionFactoryBean, which is a good example because it is common and is a separate execution branch of the interceptor, so it is worth investigating.

This branch logic is performed if the &beanname and beanName beans already exist in the container. This is done by enhancing the FactoryBean with the enhanceFactoryBean() method.

ConfigurationClassEnhancer: / / create a subclass agent, intercept the getObject () call, entrusted to the current the BeanFactory / / instead of creating a new instance. These agents only create FactoryBean when they call it. // FactoryBean: the existing FactoryBean instance taken out of the container (which is the FactoryBean instance) // exposedType: Private Object enhanceFactoryBean(Object factoryBean, Class<? > exposedType, ConfigurableBeanFactory beanFactory, String beanName) {try { See if there is a final Class<? > clazz = factoryBean.getClass(); boolean finalClass = Modifier.isFinal(clazz.getModifiers()); boolean finalMethod = Modifier.isFinal(clazz.getMethod("getObject").getModifiers()); // If one of the classes or methods is final, we'll see if we can use the interface proxyif(finalClass | | finalMethod) {/ / @ Bean annotation method return value if the interface type The JDK dynamic proxy to try out a based on the interfaceif(exposedType.isInterface()) {// JDK based dynamic proxyreturn createInterfaceProxyForFactoryBean(factoryBean, exposedType, beanFactory, beanName);
			} else{// Classes or methods are final, but return types are notreturnfactoryBean; }}} catch (NoSuchMethodException ex) {// Without getObject() {// Generate a dynamic proxy for CGLIB with final and not yet interface type // classes and methods that are not finalreturn createCglibProxyForFactoryBean(factoryBean, beanFactory, beanName);
}
Copy the code

Steps summary:

  1. Get the type of the factory Bean that already exists in the container and see if the getObject() method on the class is final
  2. If only one of them is final and you can’t use a CGLIB proxy, try using the interface based JDK dynamic proxy: FactoryBean
  3. If none of the above conditions is met, then CGLIB is used to generate a proxy subclass. In most cases, this branch is where the proxy is generated through CGLIB

Description: Both the JDK dynamic proxy and CGLIB’s proxy implementation are very simple, simply proxy the getObject() method to use beanfactory.getBean (beanName) to get the instance. The new instance will be created.

To be clear, the purpose of this interceptor’s branch of FactoryBean logic is to make sure that once you get a FactoryBean through a method call, calling its getObject() method (even multiple times) gets the same example (a singleton inside the container). So you need to intercept the getObject() method so that it points to getBean(), always from the container.

This intercepting logic only makes sense when the @bean method is called, such as when son() is called from parent(), otherwise you can ignore it

In view of this, the following code examples under different cases are given to strengthen understanding.

Code examples (Important)

Prepare a SonFactoryBean to generate an instance of Son:

public class SonFactoryBean implements FactoryBean<Son> {
    @Override
    public Son getObject() throws Exception {
        returnnew Son(); } @Override public Class<? >getObjectType() {
        returnSon.class; }}Copy the code

And put it in the configuration class:

@Configuration
public class AppConfig {

    @Bean
    public FactoryBean<Son> son() {
        SonFactoryBean sonFactoryBean = new SonFactoryBean();
        System.out.println("I define sonFactoryBean with @bean:" + sonFactoryBean.hashCode());
        System.out.println("I define sonFactoryBean identityHashCode with @bean." + System.identityHashCode(sonFactoryBean));
        returnsonFactoryBean; } @bean public Parent Parent (Son Son) throws Exception { SonFactoryBean = Son (); sonFactoryBean <Son> sonFactoryBean = Son (); System.out.println("SonFactoryBean used by parent process:" + sonFactoryBean.hashCode());
        System.out.println("SonFactoryBean identityHashCode:" + System.identityHashCode(sonFactoryBean));
        System.out.println("SonFactoryBean used by parent process:"+ sonFactoryBean.getClass()); SonFromFactory1 = sonFactoryBean.getobject (); sonFromFactory1 = sonFactoryBean.getobject (); Son sonFromFactory2 = sonFactoryBean.getObject(); System.out.println("SonFromFactory1 used by the parent process: + sonFromFactory1.hashCode());
        System.out.println("SonFromFactory1 used by the parent process: + sonFromFactory2.hashCode());
        System.out.println("Is the son used by the parent process equal to the son in the container?" + (son == sonFromFactory1));

        returnnew Parent(sonFromFactory1); }}Copy the code

Run the program:

@Bean
public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

    SonFactoryBean sonFactoryBean = context.getBean("&son", SonFactoryBean.class);
    System.out.println(SonFactoryBean in Spring container: + sonFactoryBean.hashCode());
    System.out.println(SonFactoryBean in Spring container: + System.identityHashCode(sonFactoryBean));
    System.out.println(SonFactoryBean in Spring container: + sonFactoryBean.getClass());

    System.out.println("Son in Spring container:" + context.getBean("son").hashCode());
}
Copy the code

Output result:

SonFactoryBean identityHashCode: 313540687 Parent sonFactoryBean 313540687 sonFactoryBean identityHashCode: 70807318 sonFactoryBean class com.yourbatman.fullliteconfig.config.SonFactoryBean$$EnhancerBySpringCGLIB$$1ccec41dIs the sonFromFactory1:910091170 used by the parent process equal to the son in the container?trueIn the Spring container SonFactoryBean: the 313540687 Spring container SonFactoryBean: 313540687 Spring container SonFactoryBean: Class com. Yourbatman. Fullliteconfig. Config. SonFactoryBean Spring container Son: 910091170Copy the code

Results analysis:

It does what it’s supposed to do: When parent calls son(), it gets a CGLIB bytecode enhanced instance of the SonFactoryBean that already exists in the container, intercepts it, and getObject() actually gets the object from the container.

Through this example, the following small details need to be pointed out:

  1. The.hashcode () and.equals() methods of primitive objects are identical to those of proxy/enhanced instances (whether CGLIB or JDK dynamic proxies), but the values of identityHashCode() are different. Please be aware of this
  2. It is still the native factory Bean object that ends up in the container, not the proxied factory Bean instance. After all, the interceptor simply intercepts a call to the @bean method
  3. If you add the final keyword to SonFactoryBean, the proxy object will be generated using JDK dynamic proxies, like this:
public final class SonFactoryBean implements FactoryBean<Son> { ... }
Copy the code

Run the program again, and the output is the same, but the proxy is different. You can also see Spring’s preference for proxy implementation from this small detail: the CGLIB proxy is preferred, and the JDK dynamic proxy is used as a backstop.

. // sonFactoryBean: class com.sun.proxy is used by JDK dynamic proxy parent process.$Proxy11.Copy the code

Tip: If you annotate the final keyword, make sure the @bean method returns the FactoryBean interface, not the SonFactoryBean implementation class, otherwise it will not be proxied and output as is. JDK dynamic proxy and CGLIB can’t handle it

On the basis of the above example, I “add some spice” to it, and then look at the effect:

Use BeanDefinitionRegistryPostProcessor in advance is put in a known as the son of instances:

// Add a singleton bean to the container in either of the following ways: I'm going to put in the BeanFactory, Name is son oh ~ ~ ~ don't written & son @ Component public class SonBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { // registry.registerBeanDefinition("son", BeanDefinitionBuilder.rootBeanDefinition(SonFactoryBean.class).getBeanDefinition());
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        SonFactoryBean sonFactoryBean = new SonFactoryBean();
        System.out.println("At initialization, register the container's sonFactoryBean:" + sonFactoryBean);
        beanFactory.registerSingleton("son", sonFactoryBean); }}Copy the code

Run the program again and output:

IdentityHashCode: 2027775614 Parent sonFactoryBean used by the process: 2027775614 sonFactoryBean identityHashCode: 1183888521 sonFactoryBean class com.yourbatman.fullliteconfig.config.SonFactoryBean$$EnhancerBySpringCGLIB$$1ccec41dIs the sonFromFactory1:2041605291 son used by the parent process the same as the son in the container?trueIn the Spring container SonFactoryBean: the 2027775614 Spring container SonFactoryBean: 2027775614 Spring container SonFactoryBean: Class com. Yourbatman. Fullliteconfig. Config. SonFactoryBean Spring container Son: 2041605291Copy the code

There is no difference in effect, as you can see from the log: the son() method body on your configuration class that uses the @bean annotation is not executed, but instead uses the original registered instance, and that’s the difference.

Why is this so? This does not belong to the content of this article, is the Spring container of Bean instantiation, initialization logic, this public number will still use column type explanation, let you thoroughly understand it. Currently interested to self reference DefaultListableBeanFactory# preInstantiateSingletons content ~

How does it perform in Lite mode?

These enhancements are not available in Lite mode, so run the above program in Lite mode (remove the @Configuration annotation) and the output is:

I define sonFactoryBean with @bean: 477289012. I define sonFactoryBean with @bean identityHashCode: 477289012. I define sonFactoryBean with @bean: 2008966511 I define sonFactoryBean identityHashCode: 2008966511 Parent sonFactoryBean 2008966511 Parent process sonFactoryBean identityHashCode: 2008966511 Parent process sonFactoryBean identityHashCode: Class com. Yourbatman. Fullliteconfig. Config. SonFactoryBean the parent process USES sonFromFactory1: 433874882 sonFromFactory1:572191680 Is the son used by the parent process equal to the son in the container:falseSonFactoryBean in Spring container: 477289012 SonFactoryBean in Spring container: 477289012 SonFactoryBean in Spring container: 477289012 SonFactoryBean in Spring container: 477289012 SonFactoryBean in Spring container: 477289012 SonFactoryBean Class com. Yourbatman. Fullliteconfig. Config. SonFactoryBean Spring container Son: 211968962Copy the code

As a result I will not be verbose, with the previous foundation is too easy to understand.

Why not handle @scope domain proxy?

To explain this, it has a lot to do with the @Scope proxy approach. Limited to space, this article will sell a secret ~

As for @scope, I personally think it is enough to explain more than 5 articles. Although it is rarely used in the Spring Framework, it is very necessary to understand the implementation of the custom extension of Spirng Cloud. Therefore, you can follow my official account and relevant columns will be launched in the near future.

conclusion

This column on The Spring configuration class is 99% complete, and it is not too rude to say that this part of the knowledge can really achieve a “clean sweep”, as far as I know there are no problems that can’t be solved.