1 introduction
InstantiationStrategy defines Spring’s InstantiationStrategy, which consists of three strategies
- Parameterless constructor
- The factory method
- Parameterized constructor
InstantiationStrategy interface has two categories: SimpleInstantiationStrategy and CglibSubclassingInstantiationStrategy. The SimpleInstantiationStrategy of above three methods are made a simple implementation
The source code in
Public interface InstantiationStrategy {/** * default constructor */ Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) throws BeansException; / / Instantiate (RootBeanDefinition bd, @nullable String beanName, BeanFactory owner, Constructor<? > ctor, @Nullable Object... args) throws BeansException; @instantiate (RootBeanDefinition bd, @nullable String beanName, BeanFactory Owner, @Nullable Object factoryBean, Method factoryMethod, @Nullable Object... args) throws BeansException; }Copy the code
2 son interfaceSimpleInstantiationStrategy
2.1 Factory Method
@Override public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Object factoryBean, final Method factoryMethod, Object... Args) {try {/ / set the Method to accessible, main is a kind of modifier, Method modifiers such as if (System. GetSecurityManager ()! = null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { ReflectionUtils.makeAccessible(factoryMethod); return null; }); } else { ReflectionUtils.makeAccessible(factoryMethod); } / / object to obtain the original Method, mainly to reply again behind the original value Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod. The get (); Try {/ / set the new Method, the object to the currentlyInvokedFactoryMethod currentlyInvokedFactoryMethod. Set (factoryMethod); Object result = factoryMethod.invoke(factoryBean, args); If (result == null) {result = new NullBean(); } return result; } the finally {/ / set the old Method of the object, to the currentlyInvokedFactoryMethod if (priorInvokedFactoryMethod! = null) { currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod); } else { currentlyInvokedFactoryMethod.remove(); }} catch (IllegalArgumentException ex) {}Copy the code
2.2 Parametric construction method
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, final Constructor<? > ctor, Object... Args) {// No override, just use reflection instantiation if (! bd.hasMethodOverrides()) { if (System.getSecurityManager() ! = null) {// Set the constructor, To access the AccessController. DoPrivileged ((PrivilegedAction < Object >) () - > {ReflectionUtils. MakeAccessible (ctor); return null; }); } / / use the constructor object instantiated directly by BeanUtils Bean object return BeanUtils. InstantiateClass (ctor, args); } else {/ / generates additional create a subclass of object return instantiateWithMethodInjection (bd, beanName, owner, ctor, args); }}Copy the code
2.4 No-parameter construction
Public Object Instantiate (RootBeanDefinition BD, @Nullable String beanName, BeanFactory Owner) { Use reflection directly to instantiate if (! bd.hasMethodOverrides()) { Constructor<? > constructorToUse; Synchronized (bd. ConstructorArgumentLock) {/ / Constructor constructorToUse constructorToUse = (Constructor <? >) bd.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { final Class<? > clazz = bd.getBeanClass(); // If it is an interface, Throw BeanInstantiationException exception if (clazz isInterface ()) {throw new BeanInstantiationException (clazz, "Specified class is an interface"); } the try {/ / from clazz, get the method to construct the if (System. GetSecurityManager ()! = null) {/ / safe mode constructorToUse = the AccessController. DoPrivileged ((PrivilegedExceptionAction < Constructor <? >>) clazz::getDeclaredConstructor); } else { constructorToUse = clazz.getDeclaredConstructor(); } / / tag resolvedConstructorOrFactoryMethod attribute bd. ResolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); }}} / / use the constructor object instantiated directly by BeanUtils Bean object return BeanUtils. InstantiateClass (constructorToUse); } else {/ / Must generate additional ttf_subclass. / / generates additional create a subclass of object return instantiateWithMethodInjection (bd, beanName. owner); }}Copy the code
3CglibSubclassingInstantiationStrategy
CglibSubclassingInstantiationStrategy SimpleInstantiationStrategy as part of the interface, mainly implements instantiateWithMethodInjection method, the source code is as follows
CglibSubclassingInstantiationStrategy instantiation strategy is implemented through its subclasses CglibSubclassCreator, finally is to call CglibSubclassCreator. Instantiate method
@Override protected Object instantiateWithMethodInjection(RootBeanDefinition bd, String beanName, BeanFactory owner) { return instantiateWithMethodInjection(bd, beanName, owner, null); } @Override protected Object instantiateWithMethodInjection(RootBeanDefinition bd, String beanName, BeanFactory owner, Constructor<? > ctor, Object... Return new CglibSubclassCreator(bd, owner).instantiate(ctor, args); } /** * An inner class created for historical reasons to avoid external CGLIB dependency * in Spring versions earlier */ Private static class CglibSubclassCreator {private static final class <? >[] CALLBACK_TYPES = new Class<? >[] {NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class}; private final RootBeanDefinition beanDefinition; private final BeanFactory owner; CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) { this.beanDefinition = beanDefinition; this.owner = owner; } public Object instantiate(Constructor<? > ctor, Object... Args) {// <x> Create a proxy Class with Cglib Class<? > subclass = createEnhancedSubclass(this.beanDefinition); Object instance; / / there is no constructor, through BeanUtils using the default constructor to create a bean instance if (ctor = = null) {instance = BeanUtils. InstantiateClass (ttf_subclass); } else {try {// Get the Constructor object corresponding to the proxy class and instantiate the bean Constructor<? > enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes()); instance = enhancedSubclassConstructor.newInstance(args); } catch (Exception ex) { throw new BeanInstantiationException(this.beanDefinition.getBeanClass(), "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex); } // Set the callback object Factory Factory = (Factory) instance directly on the bean instance; factory.setCallbacks(new Callback[] {NoOp.INSTANCE, new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner), new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)}); return instance; } private Class<? > createEnhancedSubclass(RootBeanDefinition beanDefinition) {// Create Enhancer object Enhancer = new Enhancer(); / / set the Bean class enhancer. SetSuperclass (beanDefinition. GetBeanClass ()); / / set the naming strategy of Spring enhancer. SetNamingPolicy (SpringNamingPolicy. INSTANCE); If (this.owner instanceof ConfigurableBeanFactory) {ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader(); enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl)); } enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition)); enhancer.setCallbackTypes(CALLBACK_TYPES); return enhancer.createClass(); }}Copy the code
4 the registryBeanDefinitionRegistry
BeanDefinitionRegistry parses the bean’s resource file into BeanDefinition and injects it into the container
4.1 General Interface for Alias ManagementAliasRegistry
public interface AliasRegistry {
void registerAlias(String name, String alias);
void removeAlias(String alias);
boolean isAlias(String name);
String[] getAliases(String name);
}
Copy the code
4.2 BeanDefinitionRegistry
BeanDefinitionRegistry is the only interface in Spring’s Bean factory package that encapsulates the BeanDefinition registry. This interface defines a series of operations on BeanDefinition registration, logout, and query.
Public interface BeanDefinitionRegistry extends AliasRegistry {// Registers a new BeanDefinition instance void in the registry registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException; / / remove the registry registered BeanDefinition instance void removeBeanDefinition (String beanName) throws NoSuchBeanDefinitionException; / / from registered specified BeanDefinition instance BeanDefinition getBeanDefinition (String beanName) throws NoSuchBeanDefinitionException; Boolean containsBeanDefinition(String beanName); String[] getBeanDefinitionNames(); // Get beanName for all BeanDefinition instances in the registry. Int getBeanDefinitionCount(); Boolean isBeanNameInUse(String beanName); }Copy the code
4.3 Interface Implementation
4.3.1 SimpleBeanDefinitionRegistry
SimpleBeanDefinitionRegistry BeanDefinitionRegistry is a simple implementation, only providing registration function, no factory function, BeanDefinition SimpleBeanDefinitionRegistry use ConcurrentHashMap to storage register.
public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry { /** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64); @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "'beanName' must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); this.beanDefinitionMap.put(beanName, beanDefinition); } @Override public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { if (this.beanDefinitionMap.remove(beanName) == null) { throw new NoSuchBeanDefinitionException(beanName); } } @Override public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { BeanDefinition bd = this.beanDefinitionMap.get(beanName); if (bd == null) { throw new NoSuchBeanDefinitionException(beanName); } return bd; } @Override public boolean containsBeanDefinition(String beanName) { return this.beanDefinitionMap.containsKey(beanName); } @Override public String[] getBeanDefinitionNames() { return StringUtils.toStringArray(this.beanDefinitionMap.keySet()); } @Override public int getBeanDefinitionCount() { return this.beanDefinitionMap.size(); } @Override public boolean isBeanNameInUse(String beanName) { return isAlias(beanName) || containsBeanDefinition(beanName); }}Copy the code
4.3.2DefaultListableBeanFactory
DefaultListableBeanFactory realized at the same time ConfigurableListableBeanFactory and BeanDefinitionRegistry is a BeanDefinition metadata based whole bean The factory. DefaultListableBeanFactory is the one which has the function of registration complete Bean plant. It also uses the ConcurrentHashMap data structure to store registered BeanDefinitions.
// Registry, Consists of the BeanDefinition identifier (beanName) and its instance private Final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, bean>(64); Private final List<String> beanDefinitionNames = new ArrayList<String>(64); public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // ... Omit other code // If there is no} else {// Check if the create Bean phase is enabled, If (hasbeandefinitionMap) {// beanDefinitionMap is a global variable, Synchronized (this.beandefinitionmap) {// Add beanDefinitionMap to beanDefinitionMap. this.beanDefinitionMap.put(beanName, beanDefinition); / / add beanName into beanDefinitionNames List < String > updatedDefinitions = new ArrayList < > (this) beanDefinitionNames) size () + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; / / removed from manualSingletonNames beanName if (this. ManualSingletonNames. The contains (beanName)) {Set < String > updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; }}} else {// Still in startup registration phase // Add BeanDefinition to beanDefinitionMap. this.beanDefinitionMap.put(beanName, beanDefinition); / / add beanName into beanDefinitionNames enclosing beanDefinitionNames. Add (beanName); / / removed from manualSingletonNames beanName this. ManualSingletonNames. Remove (beanName); } this.frozenBeanDefinitionNames = null; } // reset the beanName cache if (existingDefinition! = null || containsSingleton(beanName)) { resetBeanDefinition(beanName); }}Copy the code
- Register the core code when
this.beanDefinitionMap.put(beanName, beanDefinition);
- The core code of destruction is
beanDefinitionMap.remove(beanName)
4.4 GenericApplicationContext
GenericApplicationContext registration and destruction are commissioned DefaultListableBeanFactory
private final DefaultListableBeanFactory beanFactory;
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
@Override
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
this.beanFactory.removeBeanDefinition(beanName);
}
Copy the code