getBean
-
This is the core logic of bean initialization. The source code is more complex, say separately. Take getBean(String Name) as an example. AbstractBeanFactory.getBean:
-
@Overridepublic Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
-
The second parameter indicates the bean’s Class type, the third parameter indicates the parameter needed to create the bean, and the last parameter indicates that no type checking is required.
BeanName transformation
-
final String beanName = transformedBeanName(name);
-
Here you remove the prefix and change the alias to the real name of the FactoryBean.
Manually register bean detection
-
As mentioned in the previous registration environment section, Spring actually registers some singleton beans manually. This step is to check if these beans are true. If so, it checks if it is a factory bean, if it returns an instance of its factory method, and if it does not return the bean itself.
-
Object sharedInstance = getSingleton(beanName);
if (sharedInstance ! = null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
Checking the parent container
-
If the parent container exists and the bean definition exists, it is initialized by the parent container:
-
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory ! = null && ! containsBeanDefinition(beanName)) {
// Not found -> check parent.
// This method does the reverse of the previous beanName conversion, because the parent container also does the conversion
String nameToLookup = originalBeanName(name);
if (args ! = null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
} else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
Dependency initialization
-
Beans can be configured by the Depends -on attribute. Spring first initializes the dependent beans.
-
String[] dependsOn = mbd.getDependsOn();
if (dependsOn ! = null) {
for (String dependsOnBean : dependsOn) {
// Check for loop dependencies
if (isDependent(beanName, dependsOnBean)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
“Circular depends-on relationship between ‘” + beanName + “‘ and ‘” + dependsOnBean + “‘”);
}
registerDependentBean(dependsOnBean, beanName);
getBean(dependsOnBean);
}
}
-
The registerDependentBean is registered because Spring will destroy the dependent bean first when the bean is destroyed. The saving of dependencies is done with a ConcurrentHashMap<String, Set>, where the key is the bean’s real name.
The Singleton initialization
-
Although the outline here is the Singleton initialization, the getBean method itself is the initialization of all scopes, as explained here at once.
-
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return createBean(beanName, mbd, args);
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
GetSingleton method
If there is a
-
First check if it already exists. If it does, return:
-
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
}
-
All singleton beans are stored in this data structure :ConcurrentHashMap<String, Object>.
Bean creation
- Source in AbstractAutowireCapableBeanFactory createBean, mainly is divided into several parts:
The lookup – method detection
-
This section is used to check whether the lookup-method tag configuration method exists:
-
RootBeanDefinition mbdToUse = mbd;
mbdToUse.prepareMethodOverrides();
-
prepareMethodOverrides:
-
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exists.
MethodOverrides methodOverrides = getMethodOverrides();
if (! methodOverrides.isEmpty()) {
Set<MethodOverride> overrides = methodOverrides.getOverrides();
synchronized (overrides) {
for (MethodOverride mo : overrides) {
prepareMethodOverride(mo);
}
}
}
}
-
prepareMethodOverride:
-
protected void prepareMethodOverride(MethodOverride mo) {
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
“Invalid method override: no method with name ‘” + mo.getMethodName() +
“‘ on class [” + getBeanClassName() + “]”);
} else if (count == 1) {
// Mark override as not overloaded, to avoid the overhead of arg type checking.
mo.setOverloaded(false);
}
}
InstantiationAwareBeanPostProcessor trigger
-
Here trigger its postProcessBeforeInitialization and postProcessAfterInstantiation method.
-
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean ! = null) {
return bean;
}
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
-
Continue to:
-
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (! Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<? > targetType = determineTargetType(beanName, mbd);
if (targetType ! = null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean ! = null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean ! = null);
}
return bean;
}
-
From here you can see, if InstantiationAwareBeanPostProcessor return is not empty, so will not continue with the rest of the Spring initialization process, this interface is used to initialize the custom bean, is mainly for internal use in the Spring.
doCreateBean
- Also divided into several parts.
Create (createBeanInstance)
-
Key code:
-
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
-
Create instance createBeanInstance createBeanInstance
-
The factory bean:
Call instantiateUsingFactoryMethod method:
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
Note that factory beans here refer to beans with factory-bean/factory-method attributes configured, not beans that implement the FacrotyBean interface. If the factory-bean property is not configured, then the method to which factory-method points must be static. This method does several things:
-
Initialize a BeanWrapperImpl object.
-
Use reflected methods to find the corresponding method object based on the set parameter list.
-
InstantiationStrategy:
The initialization of the bean is again drawn into the policy pattern here, class diagram:
InstantiateUsingFactoryMethod part source code:
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse);
GetInstantiationStrategy returns CglibSubclassingInstantiationStrategy object. Here to instantiate implementation is simple, it is call the factory Method the Method of object reflection calls the invoke can get the object, SimpleInstantiationStrategy.
Instantiate core source:
@Overridepublic Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner,
Object factoryBean, final Method factoryMethod, Object… args) {
return factoryMethod.invoke(factoryBean, args);
}
-
The constructor assembles automatically
CreateBeanInstance createBeanInstance
// Need to determine the constructor… Constructor<? >[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors ! = null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
// Child elements are configured
mbd.hasConstructorArgumentValues() || ! ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
DetermineConstructorsFromBeanPostProcessors source code:
protected Constructor\[\] determineConstructorsFromBeanPostProcessors(Class beanClass, String beanName) {
if (beanClass ! = null && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
Constructor<? >[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors ! = null) {
return ctors;
}
}
}
}
return null;
}
Is determined by the SmartInstantiationAwareBeanPostProcessor, is there is no such thing as configured by default.
Then it is to determine the automatic assembly mode of the bean, which can be configured as follows:
<bean id=”student” class=”base.Student” primary=”true” autowire=”default” />
Autowire has the following options:
-
“No” : by default, automatic assembly is not performed. In this case, other beans can only be referenced by ref.
-
ByName: Lookup and assembly in the BeanFactory based on the name of the property in the bean.
-
ByType: byType.
-
Constructor: finds the bean’s constructor parameter list byType.
-
Default: Determined by the parent bean.
-
Reference: The Autowire property of spring-bean (autowire)
-
AutowireConstructor is invoked ConstructorResolver autowireConstructor, this method is mainly did two things:
-
Get the appropriate constructor object.
-
Go to BeanFactory and find the corresponding bean based on the type of the constructor argument:
Entry method in ConstructorResolver. ResolveAutowiredArgument:
protected Object resolveAutowiredArgument(
MethodParameter param, String beanName, Set<String> autowiredBeanNames,
TypeConverter typeConverter) {
return this.beanFactory.resolveDependency(
new DependencyDescriptor(param, true), beanName,
autowiredBeanNames, typeConverter);
}
-
Final call or CglibSubclassingInstantiationStrategy. Instantiate method, the key source code:
-
@Overridepublic Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner,
final Constructor<? > ctor, Object… args) {
if (bd.getMethodOverrides().isEmpty()) {
// reflection calls
return BeanUtils.instantiateClass(ctor, args);
} else {
return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
}
}
-
You can see that if you configure the lookup-method tag, you actually get a proxy subclass of the target class generated with Cglib.
-
CglibSubclassingInstantiationStrategy.instantiateWithMethodInjection:
-
@Overrideprotected Object instantiateWithMethodInjection(RootBeanDefinition bd, String beanName, BeanFactory owner,Constructor<? > ctor, Object… args) {
// Must generate CGLIB subclass…
return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}
-
Default constructor
One line of code, very simple:
// No special handling: simply use no-arg constructor.return instantiateBean(beanName, mbd);
MergedBeanDefinitionPostProcessor
-
Trigger source code:
-
synchronized (mbd.postProcessingLock) {
if (! mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
-
This interface is also used internally by Spring, regardless.
Attribute resolution
-
Entry methods: AbstractAutowireCapableBeanFactory populateBean, its role is: according to autowire type autowire by name, by type or be set directly, after a brief source code:
-
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// All values
PropertyValues pvs = mbd.getPropertyValues();
if (mbd.getResolvedAutowireMode() \== RootBeanDefinition.AUTOWIRE\_BY\_NAME || mbd.getResolvedAutowireMode() \== RootBeanDefinition.AUTOWIRE\_BY\_TYPE) { MutablePropertyValues newPvs \= new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. if (mbd.getResolvedAutowireMode() \== RootBeanDefinition.AUTOWIRE\_BY\_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (mbd.getResolvedAutowireMode() \== RootBeanDefinition.AUTOWIRE\_BY\_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs \= newPvs; } // Set applyPropertyValues(beanName, MBD, bw, PVS); }Copy the code
-
AutowireByName source code:
-
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// Return the bean names of all references (ref=”XXX”)
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
// Get it from BeanFactory
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
registerDependentBean(propertyName, beanName);
}
}
}
-
AutowireByType follows the same pattern, so you can conclude that the autowireByName and autowireByType methods simply get the referenced bean first, and the real setting takes place in applyPropertyValues.
Attribute set
- Spring determines whether a property can be set (or not) through introspection of Java beans. That is, a property can be set if the property has a setter method that is public and the property name should be the name of the setter when it is injected.
Initialize the
-
Initialization here means that the bean has been constructed to perform operations such as calling its init method. Related source code:
-
// Initialize the bean instance.Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject ! = null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
-
initializeBean:
-
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() ! = null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean \= bean; if (mbd \== null || ! mbd.isSynthetic()) { wrappedBean \= applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } invokeInitMethods(beanName, wrappedBean, mbd); if (mbd \== null || ! mbd.isSynthetic()) { wrappedBean \= applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }Copy the code
-
The main operation steps are clear at a glance.
-
Aware method triggers:
Our bean may implement some XXXAware interfaces, and this is responsible for calling them:
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
-
BeanPostProcessor trigger, nothing to say
-
Call the init method:
In an XML configuration, a bean can have an init-method attribute that specifies the method to call when initialized. In principle, this is a reflection call. Notice, however, that there is a concept of an InitializingBean.
This interface has only one method:
void afterPropertiesSet() throws Exception;
If our bean implements this interface, this method will be called first. The point of this interface is to give the bean an opportunity to reorganize or examine its properties with existing properties once all of its properties have been set (injected). It feels a bit conflicted with the init method, but this interface is widely used in Spring.
getObjectForBeanInstance
- Located in AbstractBeanFactory, the purpose of this method is to return the bean created by its factory method, not itself, if the bean is a FactoryBean.
The Prototype initialization
-
AbstractBeanFactory. DoGetBean related source code:
-
else if (mbd.isPrototype()) {
// It’s a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
beforePrototypeCreation
- This method is used to ensure that only one bean can be initialized at a time.
createBean
- And singleton is the same, not to repeat.
afterPrototypeCreation
- BeforePrototypeCreation, you get the idea.
conclusion
- As you can see, the initialization is the same as the singleton, but with an extra check to see if the singleton already exists.
Other scopes are initialized
-
The others are request and session. This part of the source:
-
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException(“No Scope registered for scope name ‘” + scopeName + “‘”);
}
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
-
Scopes are a LinkedHashMap<String, Scope> whose value can be registered by calling the registerScope method defined by ConfigurableBeanFactory.
-
Scope interface inheritance system:
-
According to socpe.get’s comments, this method returns a bean called beanName if it finds one, or creates one by calling ObjectFactory if it doesn’t. Scope implementation reference class diagram.
This article is from: Song Wenchao Super, exclusive platform CSDN, SegmentFault, Jianshu, OSChina, please indicate the source of reprint.