What design patterns are used in the JDK? What design patterns does Spring use? These two questions are common in the interview. I did a web search on design patterns in Spring and almost all of them are the same, and most of them are old. Therefore, I spent a few days to summarize myself. Due to my limited personal ability, you can point out any mistakes in the article. In addition, I have only scratched the surface of design patterns and some interpretation of the source code because of the limited space in this article. The main purpose of this article is to review design patterns in Spring.

Design Patterns represent the best computer programming practices in object-oriented software development. Different types of design patterns are widely used in the Spring framework. Let’s take a look at what are some of them?

Inversion of Control (IoC) and Dependency Injection (DI)

IoC(Inversion of Control) is a very important concept in Spring. It is not a technology, but a decoupled design idea. Its main purpose is to decouple dependent objects (IOC objects are easy to manage, you just use) with the help of a “third party” (the IOC container in Spring), thus reducing the coupling between code. IOC is a principle, not a pattern, and the following patterns (but not limited to) implement the IOC principle.

  


The Spring IOC container is like a factory. When we need to create an object, we just need to configure the configuration file/annotations, regardless of how the object was created. The IOC container is responsible for creating objects, wiring them together, configuring them, and handling them throughout their life cycle from creation until they are completely destroyed.

In a real project, if a Service class has hundreds or even thousands of classes as its underlying class and we need to instantiate the Service, you might have to figure out the constructors of all the underlying classes of the Service every time, which can drive people crazy. With IOC, all you need to do is configure it and then reference it where you need it, which makes your project much more maintainable and easier to develop. Understanding Spring IOC

How do you understand the flip control? For example: “Object A depends on object B, and when object A needs object B, it must create it itself. However, when the system introduced the IOC container, object A and object B lost their direct connection. At this point, when object A needs to use object B, we can specify the IOC container to create an object B to inject into object A. The process by which object A acquires a dependent object B changes from an active behavior to a passive behavior, a reversal of control, hence the name inversion of control.

DI(Dependecy Inject) is a design pattern to implement inversion of control. Dependency injection is to Inject instance variables into an object.

Factory design pattern

Spring uses the factory pattern to create bean objects through either the BeanFactory or ApplicationContext.

Comparison between the two:

BeanFactory: Lazy injection (injected when a bean is used) takes up less memory and starts faster than a BeanFactory.

ApplicationContext: When the container starts, create all the beans at once, whether you use them or not. BeanFactory provides only the most basic dependency injection support. ApplicationContext extends BeanFactory to include additional functions. So the average developer will use ApplicationContext more.

ApplicationContext’s three implementation classes:

ClassPathXmlApplication: Treat the context file as a classpath resource.

FileSystemXmlApplication: Loads context definition information from XML files in the file system.

XmlWebApplicationContext: Loads context definition information from an XML file in the Web system.

Example:

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

public class App {

public static void main(String[] args) {

ApplicationContext context = new FileSystemXmlApplicationContext(

C:/work/IOC Containers/springframework.applicationcontext/src/main/resources/bean-factory-config.xml);

HelloApplicationContext obj = (HelloApplicationContext) context.getBean(helloApplicationContext);

obj.getMsg();

}

}

Singleton design pattern

There are some objects in our system that we really only need one: thread pools, caches, dialogs, registries, log objects, objects that act as drivers for printers, graphics cards, and other devices. In fact, there can only be one instance of this class of objects, and creating more than one instance can lead to problems such as abnormal program behavior, excessive resource usage, or inconsistent results.

Benefits of using the singleton pattern:

For frequently used objects, you can omit the time it takes to create them, which can be a significant overhead for heavy objects.

As the number of new operations is reduced, the system memory is used less frequently, which reduces GC stress and reduces GC pause times.

The default scope of a bean in Spring is that of a singleton. In addition to the Singleton scope, Spring beans have the following scopes:

Prototype: Each request creates a new bean instance.

Request: Each HTTP request generates a new bean that is valid only within the current HTTP Request.

Session: Each HTTP request generates a new bean that is valid only for the current HTTP session.

Global-session: the global session scope, which is only meaningful in portlet-based web applications, is no longer available in Spring5. Portlets are small Java Web plug-ins that can generate snippets of semantic code, such as HTML. They are based on portlet containers and can handle HTTP requests like servlets. However, unlike servlets, each portlet has a different session

Spring implements singletons in this way:

xml :

@scope (value = singleton)

Spring implements the singleton pattern in a special way by implementing the singleton registry through ConcurrentHashMap. The core code for Spring’s singleton implementation is as follows

// Implement the singleton registry with ConcurrentHashMap(thread-safe)

private final MapsingletonObjects = new ConcurrentHashMap(64);

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {

Assert.notNull(beanName, ‘beanName’ must not be null);

synchronized (this.singletonObjects) {

// Check if there is an instance in the cache

Object singletonObject = this.singletonObjects.get(beanName);

if (singletonObject == null) {

/ /… A lot of code is omitted

try {

singletonObject = singletonFactory.getObject();

}

/ /… A lot of code is omitted

// If the instance object does not exist, we register it in the singleton registry.

addSingleton(beanName, singletonObject);

}

return (singletonObject ! = NULL_OBJECT ? singletonObject : null);

}

}

// Add objects to the singleton registry

protected void addSingleton(String beanName, Object singletonObject) {

synchronized (this.singletonObjects) {

this.singletonObjects.put(beanName, (singletonObject ! = null ? singletonObject : NULL_OBJECT));

}

}

}

Agent design pattern

Application of proxy pattern in AOP

AOP(aspect-oriented Programming: section-oriented Programming) can encapsulate the logic or responsibility (such as transaction processing, log management, permission control, etc.) that has nothing to do with business but is called jointly by business modules, so as to reduce the repeated code of the system and reduce the coupling degree between modules. And is conducive to the future scalability and maintainability.

Spring AOP is based on dynamic proxies. If you want to Proxy an object that implements an interface, Spring AOP uses JDK Proxy to create Proxy objects. If you don’t implement an interface, you can’t use JDK Proxy to Proxy objects. Spring AOP will use Cglib to generate a subclass of the proxied object as the proxy, as shown in the following figure:

  


You can also use AspectJ, which is already integrated with Spring AOP and is arguably the most complete AOP framework in the Java ecosystem.

With AOP, we can abstract out some common functions and use them where needed, which greatly simplifies the amount of code. It is also convenient when we need to add new features, which also improves system scalability. Logging capabilities, transaction management, and other scenarios use AOP.

What is the difference between Spring AOP and AspectJ AOP?

Spring AOP is runtime enhancement, while AspectJ is compile-time enhancement. Spring AOP is based on Proxying, while AspectJ is based on Bytecode Manipulation.

Spring AOP already integrates with AspectJ, which is arguably the most complete AOP framework in the Java ecosystem. AspectJ is more powerful than Spring AOP, but Spring AOP is relatively simple,

If we have fewer cuts, there is not much difference in performance. However, when there are too many facets, AspectJ is the best choice, which is much faster than Spring AOP.

Template method

The template method pattern is a behavior design pattern that defines the skeleton of an algorithm in an operation while deferring some steps to subclasses. The template approach allows subclasses to redefine how specific steps of an algorithm are implemented without changing the structure of that algorithm.

  


public abstract class Template {

// This is our template method

public final void TemplateMethod(){

PrimitiveOperation1();

PrimitiveOperation2();

PrimitiveOperation3();

}

protected void PrimitiveOperation1(){

// The current class implementation

}

// The method implemented by the subclass

protected abstract void PrimitiveOperation2();

protected abstract void PrimitiveOperation3();

}

public class TemplateImpl extends Template {

@Override

public void PrimitiveOperation2() {

// The current class implementation

}

@Override

public void PrimitiveOperation3() {

// The current class implementation

}

}

Spring’s jdbcTemplate, hibernateTemplate, and other classes that end in Template for database operations use the Template mode. Instead of using inheritance to implement the template pattern, Spring uses the Callback pattern in conjunction with the template method pattern to achieve code reuse and increase flexibility.

Observer model

The observer pattern is an object behavior pattern. It represents a dependency relationship between objects. When an object changes, the object it depends on will also react. The Spring event-driven model is a classic application of the Observer pattern. The Spring event-driven model is very useful in decoupling our code in many scenarios. For example, if we need to update the index every time we add an item, we can use the Observer pattern to solve this problem.

There are three roles in the Spring event-driven model

The event character

ApplicationEvent (org. Springframework. Context package) ACTS as the role of events, this is an abstract class, it inherits the Java. Util. EventObject and implements the Java IO. The Serializable interface.

Spring has the following events by default, which are implementations of ApplicationContextEvent (inherited from ApplicationContextEvent) :

ContextStartedEvent: event emitted when ApplicationContext is started;

ContextStoppedEvent: event triggered when ApplicationContext stops;

ContextRefreshedEvent: An event triggered after ApplicationContext has been initialized or refreshed;

ContextClosedEvent: Event triggered when ApplicationContext is closed.

  


Event listener role

ApplicationListener acts as an event listener. It is an interface where only one onApplicationEvent() method is defined to handle ApplicationEvent. The ApplicationListener interface class is provided as follows: So in Spring we simply implement the ApplicationListener interface and implement the onApplicationEvent() method to listen for events

package org.springframework.context;

import java.util.EventListener;

@FunctionalInterface

public interface ApplicationListenerextends EventListener {

void onApplicationEvent(E var1);

}

Event publisher role

ApplicationEventPublisher served for the publisher of the event, it is also an interface.

@FunctionalInterface

public interface ApplicationEventPublisher {

default void publishEvent(ApplicationEvent event) {

this.publishEvent((Object)event);

}

void publishEvent(Object var1);

}

ApplicationEventPublisher interface publishEvent () this method is implemented in the AbstractApplicationContext class, read the implementation of this method, You will find that the event actually is broadcast by ApplicationEventMulticaster out. The specific content is too much, I will not analyze it here, and I may write a separate article later.

Spring event flow summary

Define an event: Implement an inherited ApplicationEvent and write the corresponding constructor;

Define an event listener: Implement the ApplicationListener interface and override the onApplicationEvent() method;

Can use event publishers publish news: through ApplicationEventPublisher publishEvent () method.

Example:

// Define an event that inherits from ApplicationEvent and writes the corresponding constructor

public class DemoEvent extends ApplicationEvent{

private static final long serialVersionUID = 1L;

private String message;

public DemoEvent(Object source,String message){

super(source);

this.message = message;

}

public String getMessage() {

return message;

}

// Define an event listener, implement the ApplicationListener interface, override the onApplicationEvent() method;

@Component

public class DemoListener implements ApplicationListener{

// Use onApplicationEvent to receive messages

@Override

public void onApplicationEvent(DemoEvent event) {

String msg = event.getMessage();

System.out.println(+ MSG);

}

}

/ / publishing events, can through ApplicationEventPublisher publishEvent () method.

@Component

public class DemoPublisher {

@Autowired

ApplicationContext applicationContext;

public void publish(String message){

// Publish events

applicationContext.publishEvent(new DemoEvent(this, message));

}

}

When DemoPublisher’s publish() method is called, for example, demopublisher.publish (hello), the console prints: Hello.

Adapter mode

The Adapter Pattern translates one interface into another that the customer wants. The Adapter Pattern enables classes with incompatible interfaces to work together, nicknamed wrappers.

Adapter patterns in Spring AOP

We know that The implementation of Spring AOP is based on the proxy pattern, but Spring AOP enhancements or Advice use the adapter pattern and the associated interface is AdvisorAdapter. Common types of Advice include: BeforeAdvice(before target method invocation), AfterAdvice(after target method invocation), AfterReturningAdvice(after target method execution ends, before return), and so on. Each type of Advice (inform) have corresponding interceptor: MethodBeforeAdviceInterceptor, AfterReturningAdviceAdapter, AfterReturningAdviceInterceptor. Spring predefined notification to go through the corresponding adapter, adapter into the MethodInterceptor interface interceptor (method) types of objects (such as: MethodBeforeAdviceInterceptor adapter MethodBeforeAdvice).

The adapter pattern in Spring MVC

In Spring MVC, the DispatcherServlet invokes HandlerMapping based on the request information and resolves the Handler corresponding to the request. After parsing to the corresponding Handler(commonly known as the Controller Controller), it is processed by the HandlerAdapter adapter. The HandlerAdapter acts as the desired interface, the specific adapter implementation class is used to adapt the target class, and the Controller acts as the class to be adapted.

Why use the adapter pattern in Spring MVC? There are many different types of Controllers in Spring MVC, and different types of controllers handle requests in different ways. If the adapter mode is not used, the DispatcherServlet directly fetches the corresponding Controller type, as shown in the following code:

if(mappedHandler.getHandler() instanceof MultiActionController){

((MultiActionController)mappedHandler.getHandler()).xxx

}else if(mappedHandler.getHandler() instanceof XXX){

.

}else if(…) {

.

}

If we add another Controller type, we have to add another line of judgment statements to the code above, which makes the program difficult to maintain and violates the open and closed principle of design pattern-open for extension, closed for modification.

Decorator pattern

The decorator pattern can dynamically add additional properties or behaviors to an object. The decorator pattern is more flexible than using inheritance. To put it simply, design a Decorator on top of the existing code when we need to modify the existing functionality, but we don’t want to modify the existing code directly. In fact, there are many places in the JDK that use decorator patterns, such as the InputStream family, The InputStream subclasses FileInputStream (reads files) and BufferedInputStream (increases the cache and reads files faster) extend the functionality of InputStream without modifying the InputStream code.

  


When configuring a DataSource in Spring, the DataSource may be a different database and DataSource. Can we dynamically switch between different data sources according to customer needs with less modification of the original class code? This is where decorator mode comes in (which I don’t quite understand myself). The Wrapper pattern used in Spring has a Wrapper or Decorator on the class name. These classes basically add extra responsibilities to an object on the fly

conclusion

What design patterns are used in the Spring framework?

Factory Design pattern: Spring uses the factory pattern to create bean objects from the BeanFactory, ApplicationContext.

Proxy design pattern: Implementation of Spring AOP functionality.

Singleton design pattern: Beans in Spring are singleton by default.

Template method pattern: Spring’s jdbcTemplate, hibernateTemplate, and other classes that end in Template for database operations use the Template pattern.

Wrapper design pattern: Our project needs to connect to multiple databases, and different customers need to access different databases on each visit. This pattern allows us to dynamically switch between different data sources based on customer needs.

Observer Pattern: The Spring event-driven model is a classic application of the Observer pattern.

Adapter pattern: The adapter pattern is used in Spring AOP enhancements or Advice, and is used in Spring MVC to adapt controllers.