This article has participated in the call for good writing activities, click to view: back end, big front end double track submission, 20,000 yuan prize pool waiting for you to challenge

A true master always has the heart of an apprentice

The introduction

Design patterns are coding paradigms developed by gurus to improve extensibility and elegance of code. As a developer, the ability to write good code depends largely on how we use design patterns. So for some beginners, what is the fastest way to learn and understand design patterns? I think the best way to learn is through a good open source framework, which makes extensive use of design patterns for functional extensions. This article mainly analyzes the design patterns and ideas contained in the most commonly used Spring framework.

A template model

As the name implies, the template mode is the process of creating strength objects according to the established template. It can be understood that the template is a seal, through which multiple seals can be formed. Let’s look at how Spring uses the template pattern.

Spring provides the database access template class JdbcTemplate, which uses the template design pattern. The core idea is to immobilize business processes, such as database connection acquisition, database connection closure, and so on, and then hand over the changes to subclasses or callback functions.

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {...@Nullable
    public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException {
        Assert.notNull(psc, "PreparedStatementCreator must not be null");
        Assert.notNull(action, "Callback object must not be null");
        if (this.logger.isDebugEnabled()) {
            String sql = getSql(psc);
            this.logger.debug("Executing prepared SQL statement"+ (sql ! =null ? "[" + sql + "]" : ""));
        }
		// Solidification process 1: Obtain connection
        Connection con = DataSourceUtils.getConnection(this.obtainDataSource());
        PreparedStatement ps = null;

        Object var13;
        try {
        	// Solidification process 2: Obtain the PrepareStatement
            ps = psc.createPreparedStatement(con);
            this.applyStatementSettings(ps);
            T result = action.doInPreparedStatement(ps);
            this.handleWarnings((Statement)ps);
            var13 = result;
        } catch (SQLException var10) {
            if (psc instanceof ParameterDisposer) {
                ((ParameterDisposer)psc).cleanupParameters();
            }

            String sql = getSql(psc);
            psc = null;
            // Process 3: Close Statement
            JdbcUtils.closeStatement(ps);
            ps = null;
            // Solidification process 4: Close Connection
            DataSourceUtils.releaseConnection(con, this.getDataSource());
            con = null;
            throw this.translateException("PreparedStatementCallback", sql, var10);
        } finally {
            if (psc instanceof ParameterDisposer) {
                ((ParameterDisposer)psc).cleanupParameters();
            }

            JdbcUtils.closeStatement(ps);
            DataSourceUtils.releaseConnection(con, this.getDataSource());
        }

        returnvar13; }... }Copy the code

Observer model

We all know that the observer pattern is one of the more common design patterns in practical work. Simply put, the design pattern that monitors the behavior of the subject of an object when its state changes is the observer pattern. For example, in everyday life, let’s say your girlfriend comes home from work, and we observe how her mood is. If we are in a good mood, we can relax and make jokes. If the girlfriend is in a bad mood, it is necessary to be cautious in words and deeds, to avoid the girlfriend to go to work on your own body. In four words, it’s to watch people’s faces.

So how is observing this pattern implemented in the Spring framework? Let’s take a look. The Observer pattern in Spring consists of three parts: Event, Listener, and Publisher sender. The relationship between them can be seen from the following figure. Event events correspond to girlfriend’s mood, Publisher sender to your girlfriend, Listener to weak you.

With this understanding of the observer pattern, let’s look at the code:


/ / the Event Event
public class GFMoodEvent extends ApplicationEvent 
{ 
	private String message; 
	public GFMoodEvent(Object source, String message) 
	{ 
		super(source); 
	}
 	public String getMessage(a) { 
 		return this.message; }}// Listener Listener
 @Component
 public class GFMoodListener implements ApplicationListener 
 { 
 	@Override 
 	public void onApplicationEvent(GFMoodEvent gFMoodEvent) 
 	{ 
 		String message = gFMoodEvent.getMessage(); 	
 		System.out.println(message); 
 		}}
 		
 // Publisher sender
 @Component
 public class GFMoodPublisher { 
 	@Autowired 
 	private ApplicationContext applicationContext; 
 		
 	public void publishEvent(GFMoodEvent gFMoodEvent) { 
 		this.applicationContext.publishEvent(gFMoodEvent); }}Copy the code

In the traditional design pattern, the observer needs to register with the observed in order to realize state change awareness. So in Spring’s observer mode above, we don’t seem to see where the observer is registered. So our observer is actually registered in the ApplicationContext ApplicationContext. ApplicationContext is Spring’s top-level interface that provides context information for application startup and runtime. AbstractApplicationContext is its specific implementation, the corresponding publish event related code as shown below:

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {...@Override
	public void publishEvent(ApplicationEvent event) {
		publishEvent(event, null);
	}

	@Override
	public void publishEvent(Object event) {
		publishEvent(event, null);
	}

	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
		Assert.notNull(event, "Event must not be null");

		// Decorate event as an ApplicationEvent if necessary
		ApplicationEvent applicationEvent;
		if (event instanceof ApplicationEvent) {
			applicationEvent = (ApplicationEvent) event;
		}
		else {
			applicationEvent = new PayloadApplicationEvent<>(this, event);
			if (eventType == null) {
				eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
			}
		}

		// Multicast right now if possible - or lazily once the multicaster is initialized
		if (this.earlyApplicationEvents ! =null) {
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		if (this.parent ! =null) {
			if (this.parent instanceof AbstractApplicationContext) {
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				this.parent.publishEvent(event); }}}... }Copy the code

Adapter mode

The adapter pattern, as I understand it, is actually a transformation interface that allows two incompatible interfaces to work together. As shown in the picture below, the points above the charging socket cannot directly charge the phone, but if we make a layer conversion between the phone and the charging socket through the charger, the electricity from the charging socket can be converted into the current and voltage of charging the phone.

Let’s take a look at how the adapter pattern is used in the Spring framework. We all know that SpringMVC is used to handle user requests, and in the SpringMVC framework, there are all kinds of controllers, what if there were no HandlerAdapter. Every time you have a new type of Controller you have to code hard code and add new Controller handling methods to deal with it. But this approach is not easy to maintain. Hence the need to introduce an adapter pattern that is open to extension.

public interface HandlerAdapter {
    boolean supports(Object var1);

    @Nullable
    ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;

    long getLastModified(HttpServletRequest var1, Object var2);
}

Copy the code

Each Controller that implements this interface has an adapter corresponding to it, so even if there is a corresponding new type of Controller, we only need to add the corresponding adPeter, which greatly enhances the code scalability.

conclusion

In fact, there are many more design patterns involved in the Spring framework, and this article has just picked out some of the more common ones. In the process of reading the source code of the Spring framework, we need to learn the design ideas of the framework on the one hand, and we need to see how the framework uses various design patterns to meet the design principle of open to extension, closed to modification.

I’m Mufeng. Thanks for your likes, favorites and comments. I’ll see you next time!

Wechat search: Mufeng technical notes, quality articles continue to update, we have learning punch group can pull you in, together with the impact of the big factory, in addition to a lot of learning and interview materials to provide you.