An in-depth understanding of the IOC container _java in the Java Spring Framework

Source: Internet
Author: User
Tags object object reflection wrapper java spring framework

The prototype of Spring IOC
the foundation core and starting point of the spring framework is undoubtedly the core technology that IOC,IOC as a spring container, successfully completing a dependency reversal: from the main class's dependency active management to the spring container's global control of dependencies.

What are the benefits of doing so?

Of course it's called decoupling, can make the relationship between the modules of the program more independent, only need spring to control the dependencies between these modules and in the process of container startup and initialization will be based on these dependencies to create, manage and maintain these modules, if you need to change the dependencies between modules, There is no need to change the program code, just change the dependencies of the changes can be, spring will start and initialize the container in the process of these new dependencies to re-establish the new requirements of the module, in the process, It should be noted that the code itself does not need to embody the declaration of the specific dependencies of the module and only needs to define the interface of its required modules, so this is a typical interface-oriented idea, and it is best to express dependencies in the form of configuration files or annotations, The related spring processing classes can complete the IOC process based on these external configuration file assembly modules, or scan the annotations to call the internal annotation Processor assembly module.

The IOC's goal is called Di's dependency injection, and through IOC technology, the final container will help us complete the dependency injection between modules.

In addition, the final point is that in the spring IOC process, we must always be aware of the above main line, the immediate syntax and the structure of the class again complex, but its role and purpose is the same: through the dependency of the description of the configuration file this Assembly "drawing" to complete the module "assembly", Complex grammar is just the means to accomplish this.

The so-called IOC prototype, in order to show the simplest IOC schematic, we might as well do a completely simple prototype to illustrate this process:

First, we define a few modules, including the main module and the two-interface-defined dependency modules:

Class mainmodule{
  private Dependmodulea Modulea;
  Private Dependmoduleb Moduleb;
  Public Dependmodulea Getmodulea () {return
    Modulea;
  }
  public void Setmodulea (Dependmodulea modulea) {
    This.modulea = Modulea;
  }
  Public Dependmoduleb Getmoduleb () {return
    moduleb;
  }
  public void Setmoduleb (Dependmoduleb moduleb) {
    This.moduleb = Moduleb;
  }
  
}

Interface dependmodulea{public
  void Funcfrommodulea ();
}

Interface dependmoduleb{public
  void Funcfrommoduleb ();
}

Class Dependmoduleaimpl implements dependmodulea{

  @Override public
  void Funcfrommodulea () {
    System.out.println ("This are func from Module A");
  }

Class Dependmodulebimpl implements dependmoduleb{

  @Override public
  void Funcfrommoduleb () {
    System.out.println ("This are func from Module B");
  }
  


If we do not adopt the IOC but rely on the main module itself to control the creation of its dependent modules, this is the case:

public class Simpleiocdemo {public
  static void Main (string[] args) throws classnotfoundexception {
    Mainmodule ma Inmodule = new Mainmodule ();
    Mainmodule.setmodulea (New Dependmoduleaimpl ());
    Mainmodule.setmoduleb (New Dependmodulebimpl ());
    Mainmodule.getmodulea (). Funcfrommodulea ();
    Mainmodule.getmoduleb (). Funcfrommoduleb ();
  }

This is our simplified definition of the IOC container prototype, which will read the user-written configuration file when initialized after startup, and here we take the simple properties profile as an example, and only when the user takes the Getbean method does it actually load the appropriate bean according to the configuration file , a map is maintained inside our defined container prototypes for storing the assembled bean, and there is no need to create a new one if there is a bean that satisfies the requirement:

Class simpleioccontainer{Private Properties Properties = new properties ();
  Private map<string, object> modulemap = new hashmap<> ();
    {try {properties.load FileInputStream (new File ("Simpleioc.properties"));
    catch (Exception e) {e.printstacktrace ();
    The public Object Getbean (String modulename) throws classnotfoundexception {object instanceobj;
      if (Modulemap.get (modulename)!=null) {System.out.println ("return old Bean");
    Return Modulemap.get (ModuleName);
    } System.out.println ("Create New Bean");
    String FullClassName = Properties.getproperty (modulename);
    if (FullClassName = null) throw new ClassNotFoundException ();
      else{Class&lt extends object> clazz = Class.forName (FullClassName);
        try {instanceobj = Clazz.newinstance ();
        Instanceobj = Buildattachedmodules (modulename,instanceobj);
        Modulemap.put (ModuleName, instanceobj); Return Instanceobj
      catch (Instantiationexception e) {e.printstacktrace ();
      catch (Illegalaccessexception e) {e.printstacktrace ();
  } return null; Private Object Buildattachedmodules (String modulename, Object instanceobj) {set<string> Propertieskeys = P
    Roperties.stringpropertynames ();
    field[] fields = Instanceobj.getclass (). Getdeclaredfields ();
          for (String Key:propertieskeys) {if (Key.contains (modulename) &&!key.equals (modulename)) {try { class<?
          Extends object> clazz = Class.forName (Properties.getproperty (key)); for (Field field:fields) {if (Field.gettype (). IsAssignableFrom (Clazz)) Field.set (Instanceobj,
          Clazz.newinstance ());
        } catch (Exception e) {e.printstacktrace ();
  }} return instanceobj;
 }
}

This is the dependency profile we wrote using the properties configuration file, which is the "drawing" of our Assembly module, and the syntax here is exactly what we define, and in the real spring IOC container, in order to express more complex dependency logic, Using a more developed XML format configuration file or an updated annotation configuration, rely on the annotation processor to complete the drawing resolution:

Mainmodule=com.rocking.demo.mainmodule
Mainmodule.modulea=modulea
Mainmodule.moduleb=moduleb
Modulea=com.rocking.demo.dependmoduleaimpl
Moduleb=com.rocking.demo.dependmodulebimpl

This is the test code, we can see that we can complete through our definition of the IOC container to meet the requirements of the module, but also we can find that our definition of the container can maintain these beans for us, when a bean has been assembled to create after the need not to create.

public class Simpleiocdemo {public
  static void Main (string[] args) throws ClassNotFoundException {
    Simpleioccontainer container = new Simpleioccontainer ();
    Dependmodulea Modulea = (Dependmodulea) container.getbean ("Modulea");
    Modulea.funcfrommodulea ();
    Dependmoduleb Moduleb = (Dependmoduleb) container.getbean ("Moduleb");
    Moduleb.funcfrommoduleb ();
    Mainmodule mainmodule = (mainmodule) container.getbean ("Mainmodule");
    Mainmodule.getmodulea (). Funcfrommodulea ();
    Mainmodule.getmoduleb (). Funcfrommoduleb ();
    Container.getbean ("Mainmodule");
  }

This is the IOC container prototype that I created based on the basic ideas of the IOC, although the spring IOC has a complex syntax, but in the end the task is the same at the core, the so-called "same".

The specific process of Spring IOC
on the last demonstration of the prototype of the IOC's general implementation, how do you implement the process of loading Pojo in the spring framework based on the metadata meta information configuration? Throughout the spring IOC container, there are many places that are designed to be quite flexible, providing users with a lot of space to do their jobs rather than simply completing the mechanical process of the container.

This is the process diagram of the entire IOC container working process:

1. Container Start-up stage
(1) Load configuration file information
(2) Parsing profile information
(3) Assembling beandefinition
(4) Post-processing
First, the metadata and JavaBean class information such as configuration files or annotations are loaded into the IOC container, and the container reads the XML-formatted configuration file, which is a user-declared dependency and a particular concern in the Assembly, and is an early "external drawing" of the assembly Bean. The parsing engine in the container can parse the metacharacters information of the text form we write into the beandefinition that can be recognized inside the container, and can interpret beandefinition as a class structure with similar reflection mechanism, This is achieved by analyzing the JavaBean and configuration files of Beandefinition to obtain the basic structure of assembling a javabean that meets the requirements. If you need to modify this beandefinition after beandefinition, then perform this post processing, which is typically handled through the beanfactorypostprocessor within the spring framework.

We still use the example we used last time to illustrate how this beandefinition works: There are three beans, the main module mainmodule and the dependent module Dependmodulea,dependmoduleb, the former dependent on the following two modules, In the configuration file we typically do this by relying on the statement:

<?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-3.0.xsd ">

  <bean id= "Mainmodule" class= "Com.rocking.demo.MainModule" >
    <property name= "Modulea" >
      <ref bean= "Modulea"/> </property> <property name= "Moduleb"
    >
      <ref bean= "Moduleb" />
    </property>
  </bean>
  <bean id= "Modulea" class= " Com.rocking.demo.DependModuleAImpl "></bean>
  <bean id=" Moduleb "class=" Com.rocking.demo.DependModuleBImpl "></bean>
</beans>

This is our program to demonstrate the assembly of a standard beanfactory container (one of the implementation of the Spring IOC container) for the above configuration file:

Class Mainmodule {private Dependmodulea Modulea;

  Private Dependmoduleb Moduleb;
  Public Dependmodulea Getmodulea () {return modulea;
  public void Setmodulea (Dependmodulea modulea) {This.modulea = Modulea;
  Public Dependmoduleb Getmoduleb () {return moduleb;
  public void Setmoduleb (Dependmoduleb moduleb) {This.moduleb = Moduleb;

} interface Dependmodulea {public void Funcfrommodulea ();}

Interface Dependmoduleb {public void Funcfrommoduleb ();} Class Dependmoduleaimpl implements Dependmodulea {@Override public void Funcfrommodulea () {System.out.println ("
  This is func from Module A "); Class Dependmodulebimpl implements Dependmoduleb {@Override public void Funcfrommoduleb () {System.out.pri
  Ntln ("This is func from Module B"); } public class Simpleiocdemo {public static void main (string[] args) throws ClassNotFoundException {Defaultlis Tablebeanfactory beanfactory = new DefaultlistablebeanfactOry ();
    Xmlbeandefinitionreader reader = new Xmlbeandefinitionreader (beanfactory);
    Reader.loadbeandefinitions ("Beans.xml");
    Mainmodule mainmodule = (mainmodule) beanfactory.getbean ("Mainmodule");
    Mainmodule.getmodulea (). Funcfrommodulea ();
  Mainmodule.getmoduleb (). Funcfrommoduleb ();

 }
}

Here our configuration files and JavaBean are loaded and parsed, where the beandefinition generation process is hidden, which is actually an approximate process occurring within the IOC:

public class Simpleiocdemo {public static void main (string[] args) throws ClassNotFoundException {defaultlistable
    Beanfactory beanfactory = new Defaultlistablebeanfactory ();
    Abstractbeandefinition mainmodule = new Rootbeandefinition (mainmodule.class);
    Abstractbeandefinition Modulea = new Rootbeandefinition (dependmoduleaimpl.class);
    
    Abstractbeandefinition Moduleb = new Rootbeandefinition (dependmodulebimpl.class);
    Beanfactory.registerbeandefinition ("Mainmodule", mainmodule);
    Beanfactory.registerbeandefinition ("Modulea", Modulea);
    
    Beanfactory.registerbeandefinition ("Moduleb", Moduleb);
    Mutablepropertyvalues propertyvalues = new Mutablepropertyvalues ();
    Propertyvalues.add ("Modulea", Modulea);
    Propertyvalues.add ("Moduleb", Moduleb);
    
    Mainmodule.setpropertyvalues (propertyvalues);
    Mainmodule module = (mainmodule) beanfactory.getbean ("Mainmodule");
    Module.getmodulea (). Funcfrommodulea (); Module.getmoduleb (). FuncfrommoduleB ();
 }
}

After loading and reading the meta information of XML, the IOC parsing engine beandefinition the modules mentioned therein according to their true type, and this beandefinition can be regarded as a reflection or proxy process, The purpose is to let the IOC container clear the bean structure of the instance objects to be created later, then register the bean structures in beanfactory, and then add the dependency of the main module to the properties of the main module in the form of setter injection. (This depends on whether the main module provides a setter method or initialization method), after which the beanfactory has been formed after registering all the definition of the bean defined on the "drawing" at the end of the process. Then just call the Getbean method to produce the required bean, which is the next stage of the process, we'll talk about it later.

After registering the information on the "drawing" of beandefinition to Beanfactory, we can still make changes to the registered Beandefinition, which is one of the flexible places that spring has been designed for users. Not all the process is not controllable, but in many places left a lot of users can play the room. The specific approach is to use the Beanfactory processor beanfactorypostprocessor to intervene in the beanfactory process to further rewrite the beandefinition part that we need to modify. This process corresponds to the "post processing" process in the process.
One of the common processors: the attribute placeholder configuration processor, for example, is processed after the completed beanfactory has been built, so that the contents of the beandefinition corresponding properties are modified to the information in the configuration processor specified configuration file:

Defaultlistablebeanfactory beanfactory = new Defaultlistablebeanfactory ();
Xmlbeandefinitionreader reader = new Xmlbeandefinitionreader (beanfactory);
Reader.loadbeandefinitions (New Classpathresource ("Beans.xml"));
Propertyplaceholderconfigurer Configurer = new Propertyplaceholderconfigurer ();
Configurer.setlocation (New Classpathresource ("About.properties"));
Configurer.postprocessbeanfactory (beanfactory);

Beanfactorypostprocessor will treat beanfactory, the result of which is to change some of the attributes defined in Beandefinition to beanfactorypostprocessor some information at the defined location.

2, the Bean instantiation phase
with the guidance of the "internal drawings" of the processed beandefinition, the container can further translate the beandefifnition into an active instance object that exists in memory by means of reflection or cglib of dynamic bytecode production. The Beandefinition-dependent objects are then assembled into the newly created instance object through setter injection or initialization injection, which is a real way to assign a reference to a dependent object to an object attribute that needs to be relied upon.
But note that the creation of an instance is not just an instance of a simple bean definition, but rather a beanwrapper instance of a spring wrapper, why wrap the bean in a beanwrapper way? Because Beanwrapper provides a unified interface for accessing bean properties, setting the properties of the base bean after it has been created, each bean's setter method is different, so it can be very complex if you set it directly with reflection. So spring provides this wrapper to simplify the property settings:

Beanwrapper beanwrapper = new Beanwrapperimpl (Class.forName ("Com.rocking.demo.MainModule"));
Beanwrapper.setpropertyvalue ("Modulea", Class.forName ("Com.rocking.demo.DepModuleAImpl"). newinstance ();
Beanwrapper.setpropertyvalue ("Moduleb", Class.forName ("Com.rocking.demo.DepModuleBImpl"). newinstance ();
Mainmodule mainmodule= (Mainmodule) beanwrapper.getwrappedinstance ();
Mainmodule.getmodulea (). Funcfroma ();
Mainmodule.getmoduleb (). Funcfromb ();

The above process shows that within spring, by getting the reflection container of the class to understand the structure of the future packaged instance bean and wrapping it, use the Uniform property setting method setPropertyValue to set properties on the instance of this wrapper. The resulting bean instance is obtained by getwrappedinstance and can be found to have successfully assigned its properties.

This time the bean instance is actually fully available, but spring also provides us with a flexible strategy to complete the user's involvement in this phase in the instantiation phase, Similar to the Beanfactorypostprocessor control beandefinition in the container startup phase, Spring provides the Beanpostprocessor processor to operate on an already assembled instance during the instantiation phase, To complete the changes that may be required:,

Here's an example to illustrate, to define a Beanpostprocessor implementation class, Implement the methods Postprocessafterinitialization and postprocessbeforeinitialization to define the actions that are performed on and before the bean instance is assembled. When Beanfactory adds this processor, each time the Getbean method assembly is invoked, the two methods are invoked by passing in the bean instance that is assembled from the "drawing", including the dependent instance bean created during the assembly process. These methods can make modifications to these bean instances.

Here is an example (Mainmodule and its dependencies are the same as the previous examples in this article):

Class Modulec {private String x;
  Public String GetX () {return x;
  public void SetX (String x) {this.x = x; Class Modulepostprocessor implements beanpostprocessor{@Override public Object Postprocessafterinitializatio
    N (Object object, String string) throws Beansexception {System.out.println (string);
      If (object instanceof Modulec) {System.out.println (string);
    ((Modulec) object). SetX ("after");
  return object; 
    @Override public Object Postprocessbeforeinitialization (Object object, String string) throws Beansexception {
    If (object instanceof Modulec) {(Modulec) object). SetX ("before");
  return object; } public class Verysimpleiockernal {public static void main (string[] args) throws ClassNotFoundException, Beansex Ception, Instantiationexception, illegalaccessexception {defaultlistablebeanfactory beanFactory = new DefaultListable
    Beanfactory (); Xmlbeandefinitionreader Reader = new Xmlbeandefinitionreader (beanfactory);
    Reader.loadbeandefinitions (New Classpathresource ("Beans.xml"));
    Modulepostprocessor postprocessor = new Modulepostprocessor ();
    Beanfactory.addbeanpostprocessor (postprocessor);
    Mainmodule module = (mainmodule) beanfactory.getbean ("Mainmodule");  
    Modulec Modulec = (Modulec) beanfactory.getbean ("Modulec");
  System.out.println (Modulec.getx ());

 }
}

This is the bean's dependency configuration file:

<?xml version= "1.0" encoding= "UTF-8"?> <beans "xmlns=" 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=" mainmodule "class=" Com.rocking.demo.MainModule "> <property name=" Modulea "> <ref bean=" Modulea "/> &LT;/PROPERTY&G
    T <property name= "Moduleb" > <ref bean= "Moduleb"/> </property> </bean> <bean id= "mod Ulea "class=" Com.rocking.demo.DepModuleAImpl "> <property name=" Infoa "> <value>${modulea.infoa}&lt
    ;/value> </property> </bean> <bean id= "Moduleb" class= "Com.rocking.demo.DepModuleBImpl" > <property name= "Infob" > <value>info of moduleb</value> </property> </bean> ; Bean id= "Modulec" class= "Com.rocking.demo.ModuleC" &GT
 </bean> </beans>

From the final results we can see that each time the Getbean method is invoked, the bean instance (including the dependency generated) will be beanpostprocessor fetched for both the predecessor and the post processing.

In addition to processing the assembled beans in a way that resembles the beanpostprocessor above, spring can also configure Init-method and Destroy-method to set the callback function for the bean initialization and destruction process. These callback functions also provide the flexibility to give the opportunity to change the bean instance.

The whole spring IOC process is essentially the same as our own IOC prototypes, but with a complex design that allows the IOC process to be more flexible and efficient in providing more space to the user, spring's IOC is also secure, container stability, The metadata to the high efficiency of the bean conversion has been beautifully designed, making the foundation of the IOC spring container solid.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.