Spring - Several classic design patterns used in Spring

foreword

A summary of the design patterns involved in Spring, and questions about design patterns in Spring are often asked in interviews. This paper briefly introduces several design models applied in Sping based on the structure of implementation method, essence and implementation principle. The detailed analysis will be published in the following articles!

1. Simple Factory

Method to realize:

BeanFactory. The BeanFactory in Spring is the embodiment of the simple factory pattern. The Bean object is obtained by passing in a unique identifier, but whether to create it after passing in the parameters or before passing the parameters depends on the specific situation.

substance:

A factory class dynamically decides which product class should be created according to the incoming parameters.

Implementation principle:

The startup phase of the bean container:

  • Read the xml configuration file of the bean, and convert the bean element into a BeanDefinition object respectively.

  • These beans are then registered in the beanFactory through the BeanDefinitionRegistry and stored in one of its ConcurrentHashMaps.

  • After registering the BeanDefinition with the beanFactory, Spring provides us with an extended cutout that allows us to insert the code we define here by implementing the interface BeanFactoryPostProcessor.

    A typical example is: PropertyPlaceholderConfigurer, the value of the placeholder that we generally use when configuring the dataSource of the database is injected into it.

The instantiation phase of the bean in the container:

The instantiation phase is mainly to instantiate beans through reflection or CGLIB. In this phase, Spring exposes a lot of extension points to us:

  • Various Aware interfaces , such as BeanFactoryAware, for beans that implement these Aware interfaces, Spring will help us inject an instance of the corresponding BeanFactory when instantiating the bean.

  • The BeanPostProcessor interface is a bean that implements the BeanPostProcessor interface. Spring will help us call the methods in the interface when instantiating the bean.

  • The InitializingBean interface is a bean that implements the InitializingBean interface. Spring will help us call the methods in the interface when instantiating the bean.

  • The DisposableBean interface is a bean that implements the BeanPostProcessor interface. When the bean dies, Spring will help us call the methods in the interface.

Design meaning:

Loose coupling: The original hard-coded dependencies can be injected into the dependencies through the Spring beanFactory, which means that there were only the relying party and the dependent party. Now we have introduced a third party, the spring beanFactory, which solves the bean The dependency problem between them achieves the effect of loose coupling.

Additional processing of beans: Through the exposure of the Spring interface, we can perform some additional processing in the stage of instantiating the bean. These additional processing only need to make the bean implement the corresponding interface, then spring will call it during the bean's life cycle We implement the interface to handle that bean.

2. Factory method

Method to realize:

FactoryBean interface.

Implementation principle:

A bean that implements the FactoryBean interface is a class of beans called factory. Its characteristic is that when spring uses the getBean() call to obtain the bean, it will automatically call the getObject() method of the bean, so the returned value is not the factory bean, but the return value of the bean.getOjbect() method.

example:

A typical example is the combination of spring and mybatis.

Code example:

picture

illustrate:

We look at the bean above, because it implements the FactoryBean interface, it returns not the instance of SqlSessionFactoryBean, but the return value of its SqlSessionFactoryBean.getObject().

3. Singleton mode

Spring Dependency Injection Bean instances are singletons by default.

Spring's dependency injection (including the lazy-init method) happens in the getBean of the AbstractBeanFactory.

The doGetBean method of getBean calls getSingleton to create a bean.

Analyze the getSingleton() method

public Object getSingleton(String beanName){
    //参数true设置标识允许早期依赖
    return getSingleton(beanName,true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //检查缓存中是否存在实例
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        //如果为空,则锁定全局变量并进行处理。
        synchronized (this.singletonObjects) {
            //如果此bean正在加载,则不处理
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                //当某些方法需要提前初始化的时候则会调用addSingleFactory 方法将对应的ObjectFactory初始化策略存储在singletonFactories
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    //调用预先设定的getObject方法
                    singletonObject = singletonFactory.getObject();
                    //记录在缓存中,earlysingletonObjects和singletonFactories互斥
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

getSingleton() process diagram

ps: When spring dependency injection, the singleton mode of double judgment and locking is used

picture

 Summarize

Singleton pattern definition: guarantees that a class has only one instance and provides a global access point to it.

Spring's implementation of singleton: The singleton pattern in spring completes the second half of the sentence, that is, provides a global access point BeanFactory. But there is no singleton control from the constructor level, this is because spring manages arbitrary java objects.

4. Adapter mode

Method to realize:

Adapter HandlerAdatper in SpringMVC.

Implementation principle:

HandlerAdatper executes different Handlers according to Handler rules.

Implementation process:

According to the handler returned by HandlerMapping, DispatcherServlet initiates a request to HandlerAdatper to process the Handler.

The HandlerAdapter finds the corresponding Handler according to the rules and lets it execute. After the execution, the Handler returns a ModelAndView to the HandlerAdapter, and finally the HandlerAdapter returns a ModelAndView to the DispatchServelet.

Implementation meaning:

HandlerAdatper makes it easy to extend Handler, just add a new Handler and a corresponding HandlerAdapter.

Therefore, Spring defines an adaptation interface, so that each controller has a corresponding adapter implementation class, allowing the adapter to execute the corresponding method instead of the controller. In this way, when extending the Controller, you only need to add an adapter class to complete the SpringMVC extension.

5. Decorator pattern

Method to realize:

The wrapper pattern used in Spring has two manifestations in the class name: one is that the class name contains Wrapper, and the other is that the class name contains Decorator.

substance:

Dynamically add some additional responsibilities to an object.

In terms of adding functionality, the Decorator pattern is more flexible than subclassing.

6. Proxy mode

Method to realize:

The bottom layer of AOP is the implementation of the dynamic proxy mode.

Dynamic proxy:

Built in memory, no need to manually write proxy classes

Static proxy:

The proxy class needs to be written manually, and the proxy class refers to the proxied object.

Implementation principle:

Aspects are woven in when the application runs. Typically, when weaving an aspect, the AOP container dynamically creates a proxy object for the target object. Spring AOP is woven into aspects in this way.

Weaving: The process of applying an aspect to a target object and creating a new proxy object.

7. Observer mode

Method to realize:

Spring's event-driven model uses the observer pattern, and the most common use of the Observer pattern in Spring is the implementation of the listener.

Implementation:

The implementation of the event mechanism requires three parts, the event source, the event, and the event listener.

ApplicationEvent abstract class[事件]

Inherited from jdk's EventObject, all events need to inherit ApplicationEvent, and get the event source through the constructor parameter source.

The implementation class ApplicationContextEvent of this class represents the container event of 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[事件监听器]

Inherited from jdk's EventListener, all listeners must implement this interface.

This interface has only one onApplicationEvent() method, which accepts an ApplicationEvent or its subclass object as a parameter. In the method body, the corresponding processing can be performed by different judgments of the Event class.

All listeners will receive a message when the event fires.

Code:

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
     void onApplicationEvent(E event);
}

ApplicationContext interface[事件源]

ApplicationContext is the global container in spring, which translates to "application context".

Implements the ApplicationEventPublisher interface.

Responsibilities:

It is responsible for reading the configuration documents of beans, managing the loading of beans, and maintaining the dependencies between beans. It can be said that it is responsible for the entire life cycle of beans. More popularly, it is what we usually call the IOC container.

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方法需要调用其方法getApplicationEventMulticaster]

It belongs to the event broadcaster, and its function is to broadcast the Event 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. Strategy mode

Method to realize:

The resource access Resource interface of the Spring framework. This interface provides stronger resource access capabilities. The Spring framework itself uses the Resource interface extensively to access underlying resources.

Introduction to the Resource interface

The source interface is an abstraction of specific resource access strategies, and it is also the interface implemented by all resource access classes.

The Resource interface mainly provides the following 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. 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 the description information of the resource, which is usually used to output the information when there is an error in resource processing, usually the fully qualified file name or the actual URL.

  • getFile: Returns the File object corresponding to the resource.

  • getURL: Returns the URL object corresponding to the resource.

The last two methods are usually not used, and Resource provides traditional resource access functions only when simple access cannot be achieved.

The Resource interface itself does not provide the implementation logic for accessing any underlying resources. For different underlying resources, Spring will provide different Resource implementation classes, and different implementation classes are responsible for different resource access logics.

Spring provides the following implementation classes for the Resource interface:

  • UrlResource: The implementation class for accessing network resources.

  • ClassPathResource: The implementation class for accessing resources in the class loading path.

  • FileSystemResource: The implementation class for accessing resources in the file system.

  • ServletContextResource: The implementation class for accessing resources relative to the ServletContext path.

  • InputStreamResource: The implementation class for accessing input stream resources.

  • ByteArrayResource: The implementation class for accessing byte array resources.

These Resource implementation classes provide corresponding resource access logic for different underlying resources, and provide convenient packaging to facilitate the resource access of client programs.

9. Template method mode

Classic template method definition:

The parent class defines the skeleton (which methods are called and in what order), and some specific methods are implemented by the child class.

The biggest benefit: code reuse, reducing duplication of code. Except for the specific methods to be implemented by the subclass, other methods and method invocation order are pre-written in the parent class.

So there are two types of methods in the parent class template method:

Common method: code used by all subclasses

Different methods: The methods to be covered by subclasses are divided into two types:

  • Abstract method: the abstract method in the parent class must be overridden by the child class

  • Hook method: It is an empty method in the parent class, and the subclass inherits it and is also empty by default

Note: Why is it called a hook? Subclasses can control the parent class through this hook (method), because this hook is actually a method (empty method) of the parent class!

The essence of the Spring template method pattern:

It is a combination of template method mode and callback mode, and it is another implementation method of Template Method that does not require inheritance. Almost all of Spring's add-in extensions use this pattern.

Implementation:

The abstraction of JDBC and the integration of Hibernate adopt a concept or processing method, that is, the combination of the template method pattern and the corresponding Callback interface.

The template method pattern is used to handle the acquisition and release of resources in a unified and centralized way. Take 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);
}

Reason for introducing callback:

JdbcTemplate is an abstract class and cannot be used independently. We must give a corresponding subclass implementation every time we access data, which is definitely inconvenient, so callbacks are introduced.

callback code

public interface StatementCallback{
    Object doWithStatement(Statement stmt);
}

Override 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);
        }
    }

    ...//其它方法定义
}

Jdbc is used as follows:

JdbcTemplate jdbcTemplate=...;
    final String sql=...;
    StatementCallback callback=new StatementCallback(){
    public Object=doWithStatement(Statement stmt){
        return ...;
    }
}
jdbcTemplate.execute(callback);

Why is JdbcTemplate not using inheritance?

Because there are too many methods in this class, but we still want to use the existing stable and public database connection of JdbcTemplate, what should we do?

We can extract the changed things as a parameter and pass it into the method of JdbcTemplate. But the changed thing is a piece of code, and this code will use the variables in the JdbcTemplate. How to do?

Then let's use the callback object. In this callback object, define a method for manipulating variables in JdbcTemplate. We implement this method and concentrate the changes here. Then we pass this callback object to JdbcTemplate to complete the call.

refer to

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
"In-depth analysis of spring source code"

Guess you like

Origin blog.csdn.net/qq_34272760/article/details/121122750