Design Patterns in Spring Framework

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 decoupling design idea. Its main purpose is to use a third party (IoC container in Spring) to achieve decoupling between objects with dependencies (IoC is easy to manage objects, you just use it), thereby reducing the coupling between codes. It is not a pattern, but a design principle.
DI (Dependency Inject) is an implementation method of dependency injection to realize inversion of control. Dependency injection is to pass instance variables into an object.

What design patterns are used in the Spring framework?

(1) Factory mode : Spring uses the factory mode to create objects through BeanFactory and ApplicationContext

  • BeanFactory: Delayed injection (injected only when a bean is used), compared with BeanFactory, it will take up less memory and start the program faster.
  • ApplicationContext: When the container starts, whether you use it or not, create all beans at once. BeanFactory only provides the most basic dependency injection support, and ApplicationContext extends BeanFactory. In addition to the functions of BeanFactory, there are additional functions, so developers generally use ApplicationContext more.

(2) Singleton mode : The default scope of beans in Spring is singleton. In addition to the singleton scope, Spring beans also have the following scopes:

  • prototype : Each request will create a new bean instance.
  • request : Each HTTP request will generate a new bean, which is only valid within the current HTTP request.
  • session : Each HTTP request will generate a new bean, which is only valid within the current HTTP session.
  • global-session: The global session scope is only meaningful in portlet-based web applications, which is gone in Spring5. Portlets are small Java Web plug-ins capable of generating semantic code (eg: HTML) fragments. They are based on portlet containers and can handle HTTP requests like servlets. However, unlike servlets, each portlet has a different session.

The way Spring implements the singleton pattern:

xml格式:<bean id="userService" class="top.snailclimb.UserService" scope="singleton"/>
注解:@Scope(value = "singleton")

Spring implements the singleton pattern in a special way of implementing the singleton registry through ConcurrentHashMap. The core code of Spring implementing a singleton is as follows:

// 通过 ConcurrentHashMap(线程安全) 实现单例注册表  
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);  
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    
      
        Assert.notNull(beanName, "'beanName' must not be null");  
        synchronized (this.singletonObjects) {
    
      
            // 检查缓存中是否存在实例    
            Object singletonObject = this.singletonObjects.get(beanName);  
            if (singletonObject == null) {
    
      
                //...省略了很多代码  
                try {
    
      
                    singletonObject = singletonFactory.getObject();  
                }  
                //...省略了很多代码  
                // 如果实例对象在不存在,我们注册到单例注册表中。  
                addSingleton(beanName, singletonObject);  
            }  
            return (singletonObject != NULL_OBJECT ? singletonObject : null);  
        }  
    }  
    //将对象添加到单例注册表  
    protected void addSingleton(String beanName, Object singletonObject) {
    
      
            synchronized (this.singletonObjects) {
    
      
                this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));  
            }  
        }  
} 

(3) Strategy pattern : The resource access interface of the Spring framework is implemented based on the strategy design pattern. This interface provides stronger resource access capabilities, and the Spring framework itself uses the Resource interface extensively to access underlying resources. The Resource interface itself does not provide 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 types of resource access.

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.

(4) Proxy mode : Spring's AOP function uses JDK's dynamic proxy and CGLIB bytecode generation technology

Spring AOP is based on dynamic proxy. If the object to be proxied implements an interface, then Spring AOP will use JDK Proxy to create a proxy object. For objects that do not implement the interface, JDK Proxy cannot be used for proxying. , at this time Spring AOP will use Cglib, at this time Spring AOP will use Cglib to generate a subclass of the proxy object as a proxy.

What is the difference between Spring AOP and AspectJ AOP?

Spring AOP is a runtime enhancement, while AspectJ is a compile-time enhancement. Spring AOP is based on proxies while AspectJ is based on bytecode manipulation.

Spring AOP has integrated AspectJ, and AsectJ should be regarded as the most complete AOP framework in the Java ecosystem. AspectJ is more powerful than Spring AOP, but Spring AOP is relatively simpler. If we have fewer aspects, the performance difference between the two is not big. But when there are too many aspects, it is best to choose AspectJ, which is much faster than Spring AOP.

(5) Template mode : You can put the same part of the code in the parent class, and put different codes in different subclasses to solve the problem of code duplication. Such as RestTemplate, JmsTemplate, JpaTemplate. For example:

public abstract class Template {
    
      
    //这是我们的模板方法  
    public final void TemplateMethod(){
    
      
        PrimitiveOperation1();    
        PrimitiveOperation2();  
        PrimitiveOperation3();  
    }  
    protected void  PrimitiveOperation1(){
    
      
        //当前类实现  
    }  
    //被子类实现的方法  
    protected abstract void PrimitiveOperation2();  
    protected abstract void PrimitiveOperation3();  
}  
public class TemplateImpl extends Template {
    
      
    @Override  
    public void PrimitiveOperation2() {
    
      
        //当前类实现  
    }  
    @Override  
    public void PrimitiveOperation3() {
    
      
        //当前类实现  
    }  
} 

Spring中jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到模板模式。In general, we use inheritance to implement the template mode, but Spring does not use this method, but uses the Callback mode to cooperate with the template method, which not only achieves the effect of code reuse, but also increases flexibility.

(6) Adapter mode : The enhancement or advice (Advice) of Spring AOP uses the adapter mode, and the adapter mode is also used in Spring MVC to adapt the Controller.

The adapter design pattern converts one interface into another interface that the client wants. The adapter pattern enables those classes with incompatible interfaces to work together, and its alias is a wrapper. In Spring MVC, DispatcherServlet calls HandlerMapping according to the request information, parses the Handler corresponding to the request, and after parsing to the corresponding Handler (that is, the Controller controller we often say), it starts to be processed by the HandlerAdapter adapter.

Why use Adapter pattern in Spring MVC?
There are many types of Controllers in Spring MVC. Different types of Controllers process requests through different methods, which is conducive to code maintenance and expansion.

(7) Observer pattern : The observer design pattern is an object behavior pattern. It means that there is a dependency relationship between objects. When an object changes, the object that the object lock depends on will also respond. The Spring event-driven model is a classic application of the observer pattern.

Event role: ApplicationEvent (under the org.springframework.context package) acts as an event role, which is an abstract class.

Event listener role: ApplicationListener acts as an event listener. It is an interface that only defines an onApplicationEvent() method to handle ApplicationEvent.

Event publisher role: ApplicationEventPublisher acts as an event publisher, which is also an interface.

Spring event flow summary:

  1. Define an event: implement one that inherits from ApplicationEvent, and write the corresponding constructor;
  2. Define an event listener: implement the ApplicationListener interface and rewrite the onApplicationEvent() method;
  3. Publish messages using event publishers: You can publish messages through the publishEvent() method of ApplicationEventPublisher.

For example:

// 定义一个事件,继承自ApplicationEvent并且写相应的构造函数  
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;  
          }  
// 定义一个事件监听者,实现ApplicationListener接口,重写 onApplicationEvent() 方法;  
@Component  
public class DemoListener implements ApplicationListener<DemoEvent>{
    
      
    //使用onApplicationEvent接收消息  
    @Override  
    public void onApplicationEvent(DemoEvent event) {
    
      
        String msg = event.getMessage();  
        System.out.println("接收到的信息是:"+msg);  
    }  
}  
// 发布事件,可以通过ApplicationEventPublisher  的 publishEvent() 方法发布消息。  
@Component  
public class DemoPublisher {
    
      
    @Autowired  
    ApplicationContext applicationContext;  
    public void publish(String message){
    
      
        //发布事件  
        applicationContext.publishEvent(new DemoEvent(this, message));  
    }  
} 

(8) Bridge mode : Different data sources can be dynamically switched according to customer needs. For example, our project needs to connect to multiple databases, and customers will access different databases according to their needs during each visit

おすすめ

転載: blog.csdn.net/qq_39756007/article/details/128927515