Spring official website notes 1

Spring容器
    容器是什么?
    容器如何工作?

Spring容器
容器是什么?
我们先看官网中的一句话:

Insert picture description here

翻译如下:
org.springframework.context。ApplicationContext接口表示Spring IoC容器,并负责实例化、配置和组装bean。
那么我们就可以说:
	从代码层次来看:Spring容器就是一个实现了ApplicationContext的接口的对象。
    从功能上来看:SPring容器是Spring框架的核心,是用来管理对象的。容器将创建对象,把它们连接在一起配置他们,并管理它们的整个生命周期从创建到销毁。
容器如何工作?
我们直接看官网上的一张图片,如下

Insert picture description here

The Spring container generates a fully configured and usable system through the pojo class and configuration metadata we submitted.
The original configuration data mentioned here is actually the XML configuration file we provide, or some configuration information provided through annotations


Spring Bean
how to instantiate a Bean?
From the official website of view, there are three main ways
``
Insert picture description here

1、构造方法
2、通过静态工厂方法
3、通过实例工厂方法

For these three examples, the official website has examples, so I won’t post them here. We check some of the source code by ourselves to verify the conclusions we reached on the official website, and then verify them through debug and other methods.

我们再从代码的角度分析一下,我们直接定位到
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance 具体定位后面再来分析,大家可以通过形如下面的这段代码

Insert picture description here

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd"
		>
		<bean id="myServiceImpl" class="com.phr.tx.MyServiceImpl">
		</bean>
</beans>
public static void main(String[] args) {
    
    
		ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("classpath:application.xml");
		MyServiceImpl myService = (MyServiceImpl) cc.getBean("myServiceImpl");
	}

Insert picture description here

Then hit a breakpoint in the position shown above. Run the main method directly. Then make a breakpoint at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance and debug it

Insert picture description here

The beanName at this time is what we need. Next we analyze this method, the code is as follows

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    
    
		// Make sure bean class is actually resolved at this point.
		//获取这个bean的class属性,确保BeanDefinition中的beanClass已经完成解析
		// 我们通过xml从<bean>标签中解析出来的class属性在刚刚开始的时候必定是个字符串
		Class<?> beanClass = resolveBeanClass(mbd, beanName);
		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
    
    
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}
		//2.通过beanDefinition中的supplier实例化这个bean
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
    
    
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		// 3.通过FactoryMethod实例化这个bean
		if (mbd.getFactoryMethodName() != null) {
    
    
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}
		// Shortcut when re-creating the same bean...
		// 4.下面这段代码都是在通过构造函数实例化这个Bean,分两种情况,一种是通过默认的无参构造,一种是通过推断出来的构造函数
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
    
    
			synchronized (mbd.constructorArgumentLock) {
    
    
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
    
    
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
    
    
			if (autowireNecessary) {
    
    
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
    
    
				return instantiateBean(beanName, mbd);
			}
		}
		// Candidate constructors for autowiring?
		//第二次调用后置处理器 作用:推断创建这个bean的构造方法
		//后置处理器和方法:
		//SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
    
    
			return autowireConstructor(beanName, mbd, ctors, args);
		}
		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
    
    
			return autowireConstructor(beanName, mbd, ctors, null);
		}
		// No special handling: simply use no-arg constructor.
		return instantiateBean(beanName, mbd);
	}
我们主要关注进行实例化的几个方法:
1、通过BeanDefinitionz中的instanceSupplier直接获取一个实例对象。这个instanceSupplier在org.springframework.context.support.GenericApplicationContext这个类里面

Insert picture description here

After the breakpoint debugging, the above method will be entered when the object is instantiated. Below is the test code.

public static void main(String[] args) {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
		ac.registerBean("service", Service.class,Service::new);
		ac.refresh();
		System.out.println(ac.getBean("service"));
	}

Insert picture description here

This method is generally not commonly used. I think it is an instantiation method provided by spring to the outside world. Not much discussion here.

1、接下来,我们通过不同的方式创建bean,来分别验证对象的实例化方法。
    通过@compent @service 等方式创建
@Component
public class ServiceTest {
    
    
}
@Configuration
@ComponentScan(value = {
    
    "com.phr.tx"})
public class Config {
    
    
}
public static void main(String[] args) {
    
    
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
		System.out.println(ac.getBean(ServiceTest.class));
}

​ Observation debug

Insert picture description here

看javadoc就知道,默认使用无参构造方法进行实例化。
通过普通xml方式和@component类似,这里就不赘述了
通过@configuration
	public static void main(String[] args) {
//		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
//		System.out.println(ac.getBean(ServiceTest.class));
		// 通过配置类扫描
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
		// 这里将测试对象换为config即可,同时记得将条件断点更改为beanName.equlas("config")
		System.out.println(ac.getBean(Config.class));
	}

View debug renderings

Insert picture description here

The same is through no-parameter construction, but looking at beanClass, you know that this is a cglib proxy. For this phenomenon, the author will analyze it later.

Via @Bean

	@Bean
	public Service service(){
    
    
		return new Service();
	}

	AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
	System.out.println(ac.getBean(Service.class));	

Insert picture description here

It can be found that when we create an object through the @Bean method, the bottom layer of Spring instantiates the object through the method of factoryMethod. Spring will record what factoryBeanName is in the corresponding Beandefinition we need to instantiate. As shown in the figure, this factoryBeanName is config. . Finally , an object is instantiated by factoryBeanNameobtaining a Bean and then calling reflection factoryMethod.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<!--	<bean id="myServiceImpl" class="com.dmz.official.service.Service"/>-->

	<!-- the factory bean, which contains a method called get() -->
	<bean id="myFactoryBean" class="com.phr.tx.MyFactoryBean">
		<!-- inject any dependencies required by this locator bean -->
	</bean>

	<!-- 测试实例工厂方法创建对象-->
<!--	<bean id="clientService"-->
<!--		  factory-bean="myFactoryBean"-->
<!--		  factory-method="get"/>-->

	<!--测试静态工厂方法创建对象-->
	<bean id="service"
		  class="com.phr.tx.MyFactoryBean"
		  factory-method="staticGet"/>
</beans>

public static void main(String[] args) {
		ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("classpath:application.xml");
		System.out.println(cc.getBean(Service.class));
	}

Insert picture description here

It can be found that this situation has also entered the instantiateUsingFactoryMethodmethod. The special feature of the static factory method is that the class containing this static method does not need to be instantiated and does not need to be managed by Spring. The calling logic of Spring is roughly:

  1. <bean>Get a Class object through the class attribute in the label
  2. Get the Method object of the corresponding method name through the Class object
  3. Last reflection callMethod.invoke(null,args)

Because it is a static method, an object is not needed when the method is executed.

  • By way of instance factory method

The test code (configuration file remains unchanged) is the same as @Bean, so I won’t go into details.

d` method. The special feature of the static factory method is that the class containing this static method does not need to be instantiated and does not need to be managed by Spring. The calling logic of Spring is roughly:

  1. <bean>Get a Class object through the class attribute in the label
  2. Get the Method object of the corresponding method name through the Class object
  3. Last reflection callMethod.invoke(null,args)

Because it is a static method, an object is not needed when the method is executed.

  • By way of instance factory method

The test code (configuration file remains unchanged) is the same as @Bean, so I won’t go into details.

In this way, only a Bean object is generated, and the life cycle of the bean has not been completed. Next, the author will analyze the life cycle of the Bean according to the rhythm of the official website.

Guess you like

Origin blog.csdn.net/jessionlist/article/details/108760745