Design patterns involved in Spring

Posted by zeberdeee on Mon, 07 Mar 2022 18:51:15 +0100

Summary of design patterns involved in Spring

  • Simple factory implementation: BeanFactory. BeanFactory in Spring is a reflection of simple factory mode, which obtains Bean objects by passing in a unique identity, but whether this is created after or before the parameter is passed in depends on the situation.
  • Factory method implementation: FactoryBean interface.
  • The singleton mode Spring dependency injection Bean instance is singleton by default; The connection pool for the database is also singular.
  • Adapter mode implementation: Adapter HandlerAdatper in SpringMVC.
  • Decorator mode implementation: The wrapper mode used in Spring has two representations on the class name: one contains Wrapper in the class name, the other contains Decorator in the class name.
  • Agent mode implementation: AOP bottom level, is the implementation of dynamic agent mode.
  • Observer mode implementation: Spring's event-driven model uses the observer mode, whereas Observer mode in Spring is commonly used for the implementation of listener.
  • Policy mode implementation: Resource access Resource interface for Spring framework. This interface provides stronger access to resources, and the Spring framework itself makes extensive use of the Resource interface to access underlying resources.
  • Template method pattern implementation: JDBC abstraction and integration with Hibernate all adopt a concept or processing method that combines template method pattern with corresponding Callback interface.

1. Simple factory (not one of 23 design modes)

  • Implementation: BeanFactory. BeanFactory in Spring is a reflection of simple factory mode, which obtains Bean objects by passing in a unique identity, but whether this is created after or before the parameter is passed in depends on the situation.
  • Essential: A factory class dynamically determines which product class should be created based on the parameters passed in.
  • Implementation principle:
    • Startup phase of the bean container:

      • Reads the xml configuration file of a bean and converts the bean elements into one BeanDefinition object, respectively.
      • These beans are then registered with the beanFactory via the BeanDefinitionRegistry and saved in one of its ConcurrentHashMap s.
      • Once BeanDefinition has been registered with the beanFactory, Spring provides us with an extended notch where we can insert the code we define by implementing the interface BeanFactoryPostProcessor. A typical example is the PropertyPlaceholderConfigurer, which is the placeholder value that we typically use when configuring the dataSource of a database, into which it is injected.
    • The instantiation phase of a bean in a container:
      In the instantiation phase, bean s are mainly instantiated through reflection or CGLIB, and Spring exposes a lot of extensions to us in this phase:

      • Various Aware interfaces, such as BeanFactoryAware, Spring helps us inject instances of the corresponding BeanFactory when instantiating beans for beans that implement these Aware interfaces.
      • The BeanPostProcessor interface, which implements the beans of the BeanPostProcessor interface, enables Spring to call methods in the interface when instantiating beans.
      • The InitializingBean interface, which implements the beans of the InitializingBean interface, enables Spring to call methods in the interface when instantiating beans.
      • The DisposableBean interface, which implements the beans of the BeanPostProcessor interface, allows Spring to help us call methods in the interface when the bean dies.
    • Design Meaning:

      • Loose coupling. You can inject dependencies by Spring, the beanFactory worker, which was originally hard-coded. That is to say, only the relying party and the dependent party. Now we have introduced a third party, spring, which solves the dependency problem between beans and achieves a loosely coupled effect.
      • Extra processing of beans. Exposing the Spring interface allows us to do some additional processing during the instantiation phase of the bean, which only requires the bean to implement the corresponding interface, and then spring will call our implemented interface to process the bean during its life cycle. [very important]

2. Factory method

  • Implementation: FactoryBean interface.
  • Implementation principle:
    Beans that implement the FactoryBean interface are a class of beans called factories. spring automatically calls the getObject() method of a getBean when it gets it by using a getBean() call, so it does not return the factory bean, but the bean. The return value of the getOjbect() method.
  • Example:
    • Typical examples are the combination of spring and mybatis.
    • Code Samples
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:config/mybatis-config-master.xml"/>
<property name="mapperLocations" value="classpath:config/mappers/master/**/.xml"/>
</bean>
  • Explain:
    Let's look at the bean above, because we implemented the FactoryBean interface, so instead of returning an instance of SqlSessionFactoryBean, we returned her SqlSessionFactoryBean. Return value of getObject().

3. Single Case Mode

  • Spring Dependent Injection Bean instances are singleton by default.
  • Spring's dependency injection (including lazy-init) occurs in the getBean of AbstractBeanFactory. The getBean's doGetBean method calls getSingleton to create bean s.
  • Analyzing the getSingleton() method
public Object getSingleton(String beanName){
    //Parameter true setting identity allows early dependencies
    return getSingleton(beanName,true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //Check for instances in the cache
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        //If it is empty, the global variable is locked and processed.
        synchronized (this.singletonObjects) {
            //If this bean is loading, it will not be processed
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {  
                //When some methods need to be initialized in advance, the addSingleFactory method is called to store the corresponding ObjectFactory initialization policy in singletonFactories
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    //Call a preset getObject method
                    singletonObject = singletonFactory.getObject();
                    //earlysingletonObjects and singletonFactories are mutually exclusive when recorded in the cache
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

  • getSingleton() Process Diagram
    ps:spring dependent injection uses a double-judgment locking singleton mode

  • summary

  • Singleton schema definition: Ensures that a class has only one instance and provides a global access point to access it.

  • Spring's implementation of singletons: The singleton pattern in spring completes the last half sentence, which provides a global access point, BeanFactory. However, the singleton is not controlled from the constructor level because spring manages any java object.

4. Adapter mode

  • Implementation: Adapter HandlerAdatper in Spring MVC.
  • Implementation principle: Handler Adatper executes different handlers according to Handler rules.
  • Implementation process:
    Dispatcher Servlet makes a request to Handler Adatper to process the handler based on the handler returned by Handler Mapping. The Handler Adapter finds the corresponding Handler according to the rules and lets it execute. After execution, the Handler returns a ModelAndView to the Handler Adapter and a ModelAndView to the DispatchServelet by the Handler Adapter.
  • Implementing meaning:
    Handler Adatper makes it easy to extend a Handler by adding a new Handler and a corresponding Handler Adapter. So Spring defines an adapter interface so that each Controller has a corresponding adapter implementation class that allows the adapter to execute the appropriate method instead of the controller. This completes the SpringMVC extension by adding only one adapter class when extending Controller.

5. Decorator Mode

  • Implementation:
    The wrapper pattern used in Spring has two representations for class names: one containing Wrapper in the class name and the other containing Decorator in the class name.
  • Essential:
    • Dynamically add some extra responsibility to an object.
    • Decorator mode is more flexible in terms of added functionality than generating subclasses.

6. Agent mode

  • Implementation: AOP bottom level, is the implementation of dynamic proxy mode.
    • Dynamic proxy: built in memory, no need to manually write proxy classes
    • Static proxy: Proxy classes need to be written manually and reference the proxied objects.
  • Implementation principle:
    Cuts are woven at the moment the application is running. In general, when facets are woven in, the AOP container creates a dynamic proxy object for the target object. This is how SpringAOP weaves into facets.
    Weaving: The process of applying facets to the target object and creating new proxy objects.

7. Observer Mode

  • How to implement it: Spring's event-driven model uses the observer mode, whereas Observer mode in Spring is commonly used for the listener implementation.

  • Specific implementation:
    The implementation of event mechanism requires three parts, event source, event, event listener

    • Application Event Abstract Class [Event]

      • EventObject inherited from jdk, all events need to inherit ApplicationEvent and get event source through the constructor parameter source.
      • The class's implementation class ApplicationContextEvent represents container events for the ApplicaitonContext.
      • Code:
        public abstract class ApplicationEvent extends EventObject {
            private static final long serialVersionUID = 7099057708183571937L;
            private final long timestamp;
            public ApplicationEvent(Object source) {
            super(source);
            this.timestamp = System.currentTimeMillis();
            }
            public final long getTimestamp() {
                return this.timestamp;
            }
        }
        
        
    • ApplicationListener Interface [Event Listener]

      • EventListener inherited from jdk, all listeners implement this interface.
      • This interface has only one onApplicationEvent() method, which accepts an ApplicationEvent or its subclass object as a parameter and can be handled by different judgments on the Event class in the method body.
      • All listeners receive messages when the event triggers.
      • Code:
        public interface ApplicationListener<E extends ApplicationEvent> extends                EventListener {
                         void onApplicationEvent(E event);
        } 
        
        
    • ApplicationContext Interface [Event Source]

      • The ApplicationContext is a global container in spring, translated as an "application context".
      • The Application EventPublisher interface is implemented.
      • Responsibilities: Responsible for reading the configuration documents of beans, managing the loading of beans, maintaining the dependencies between beans, can be said to be responsible for the entire life cycle of beans, and more popular is what we usually call IOC containers.
      • Code:
        public interface ApplicationEventPublisher {
                void publishEvent(ApplicationEvent event);
        }   
        
        public void publishEvent(ApplicationEvent event) {
            Assert.notNull(event, "Event must not be null");
            if (logger.isTraceEnabled()) {
                 logger.trace("Publishing event in " + getDisplayName() + ": " + event);
            }
            getApplicationEventMulticaster().multicastEvent(event);
            if (this.parent != null) {
            this.parent.publishEvent(event);
            }
        }
        
        
    • ApplicationEventMulticaster abstract class [publishEvent method in event source needs to call its method getApplicationEventMulticaster]

      • It is an Event broadcaster that broadcasts events published by the Applicationcontext to all listeners.
      • Code:
        public abstract class AbstractApplicationContext extends DefaultResourceLoader
            implements ConfigurableApplicationContext, DisposableBean {  
            private ApplicationEventMulticaster applicationEventMulticaster;  
            protected void registerListeners() {  
            // Register statically specified listeners first.  
            for (ApplicationListener<?> listener : getApplicationListeners()) {  
            getApplicationEventMulticaster().addApplicationListener(listener);  
            }  
            // Do not initialize FactoryBeans here: We need to leave all regular beans  
            // uninitialized to let post-processors apply to them!  
            String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);  
            for (String lisName : listenerBeanNames) {  
            getApplicationEventMulticaster().addApplicationListenerBean(lisName);  
            }  
          }  
        }
        
        

8. Policy Patterns

  • Implementation: Resource access Resource interface for Spring framework. This interface provides stronger access to resources, and the Spring framework itself makes extensive use of the Resource interface to access underlying resources.
  • Introduction to Resource Interface
    • The source interface is the abstraction of a specific resource access policy and the interface implemented by all resource access classes.

    • The Resource interface provides the following main methods:

      • getInputStream(): Locate and open the resource and return the input stream corresponding to the resource. Each call returns a new input stream. The caller must be responsible for closing the input stream.
      • exists(): Returns whether the resource pointed to by Resource exists.
      • isOpen(): Returns whether the resource file is open or not, and if the resource file cannot be read multiple times, it should be explicitly closed at the end of each read to prevent resource leakage.
      • getDescription(): Returns a description of a resource, usually used to output the information when a resource processing error occurs, usually a fully qualified file name or actual URL.
      • getFile: Returns the File object corresponding to the resource.
      • getURL: Returns the URL object for the resource.
        The last two methods are usually unnecessary, and Resource provides traditional resource access only when simple access is unavailable.
    • The Resource interface itself does not provide implementation logic to access any underlying resources. For different underlying resources, Spring will provide different Resource implementation classes, which are responsible for different resource access logic.

    • Spring provides the following implementation classes for the Resource interface:

      • UrlResource: An implementation class that accesses network resources.
      • ClassPathResource: An implementation class that accesses the resources in the class load path.
      • FileSystemResource: An implementation class that accesses resources in the file system.
      • ServletContextResource: An implementation class that accesses resources relative to those in the ServletContext path.
      • InputStreamResource: An implementation class that accesses input stream resources.
      • ByteArrayResource: An implementation class that accesses byte array resources.
        These Resource implementation classes provide appropriate resource access logic for different underlying resources and provide convenient wrapping to facilitate resource access for client programs.

9. Template Method Mode

  • Classic template method definition:
    • The parent defines the skeleton (which methods and order to call), and some specific methods are implemented by subclasses
    • Maximum benefit: code reuse, reduce duplicate code. In addition to the specific methods implemented by the subclasses, other methods and method invocation sequences are pre-written in the parent class.
    • So there are two types of parent template methods:
      • Common approach: code used by all subclasses
      • Different methods: The methods to be overridden by subclasses are divided into two types:
        • Abstract methods: in the parent class is an abstract method, the child class must override
        • Hook method: an empty method in the parent class and a null method in the child class inheriting the default
          Note: Why is it called a hook? Subclasses can control the parent through this hook (method), because this hook is actually the parent's method (empty method)!
  • The Spring template method pattern essentially:
    It is a combination of template method mode and callback mode and is another implementation of Template Method that does not require inheritance. Almost all Spring's external extensions follow this pattern.
  • Specific implementation:
    The abstraction of JDBC and the integration with Hibernate all adopt the idea or approach of combining the template method pattern with the corresponding Callback interface.
  • The Template Method pattern is used to handle the acquisition and release of resources in a unified and centralized manner, taking JdbcTempalte as an example:
public abstract class JdbcTemplate {  
     public final Object execute(String sql){  
        Connection con=null;  
        Statement stmt=null;  
        try{  
            con=getConnection();  
            stmt=con.createStatement();  
            Object retValue=executeWithStatement(stmt,sql);  
            return retValue;  
        }catch(SQLException e){  
             ...  
        }finally{  
            closeStatement(stmt);  
            releaseConnection(con);  
        }  
    }   
    protected abstract Object executeWithStatement(Statement   stmt, String sql);  
}  

  • Callback reason introduced:

    • JdbcTemplate is an abstract class and cannot be used independently. Each time we access data, we need to give a corresponding subclass implementation, which is certainly inconvenient, so callbacks are introduced.

    • callback code

      public interface StatementCallback{  
          Object doWithStatement(Statement stmt);  
      }   
      
      
    • Rewrite JdbcTemplate method with callback method

      public class JdbcTemplate {  
          public final Object execute(StatementCallback callback){  
              Connection con=null;  
              Statement stmt=null;  
              try{  
                  con=getConnection();  
                  stmt=con.createStatement();  
                  Object retValue=callback.doWithStatement(stmt);  
                  return retValue;  
              }catch(SQLException e){  
                  ...  
              }finally{  
                  closeStatement(stmt);  
                  releaseConnection(con);  
              }  
          }  
      
          ...//Other Method Definitions  
      }   
      
      
    • The Jdbc is used as follows:

      JdbcTemplate jdbcTemplate=...;  
          final String sql=...;  
          StatementCallback callback=new StatementCallback(){  
          public Object=doWithStatement(Statement stmt){  
              return ...;  
          }  
      }    
      jdbcTemplate.execute(callback);  
      
      
  • Why does JdbcTemplate not use inheritance?
    Because there are too many methods for this class, but we still want to use the stable, common database connection that JdbcTemplate already has, what do we do? We can pull out the changes and pass them into the JdbcTemplate method as a parameter. But what changes is a piece of code that uses variables in JdbcTemplate. What should I do? Let's use the callback object. Define a way to manipulate variables in the JdbcTemplate in this callback object, and let's implement this way to focus on what's changed here. We then pass in the callback object to JdbcTemplate and complete the call.

    Reference resources:
    https://www.cnblogs.com/digdeep/p/4518571.html
    https://www.cnblogs.com/tongkey/p/7919401.html
    https://www.cnblogs.com/fingerboy/p/6393644.html
    https://blog.csdn.net/ovoo_8/article/details/51189401
    https://blog.csdn.net/z69183787/article/details/65628166