The design pattern we talked about in Spring in the previous article involved creating the pattern three musketeers and one behavior pattern (the interpreter pattern). This time we will focus more on structural and behavioral design patterns.

In this article, we’ll look at two patterns for each type. The first focus will be on types as structural design patterns. It will contain both proxy and composition. The next section covers behavior patterns: policy and template methods.

The proxy pattern

Object Oriented programming (OOP) is probably the most popular concept in programming. Spring, however, introduces another coding specification, faceted Programming (AOP). To simplify the definition, AOP is programming for specific points in the system, such as exception throwing, execution of a specific class of methods, and so on. AOP allows complementary actions to be performed before or after executing these specific points. How is this done? It can be done by listeners. But in this case, we should define listeners to listen wherever calls are possible (such as at the beginning of a method). This is why Spring does not adopt this idea. Instead, Spring implements a design pattern that can accomplish tasks through additional method calls – the proxy design pattern.

A proxy is like a mirror image of an object. Because of this, proxy objects can not only override real objects, but also extend their functionality. So, for objects that only print some text on the screen, we can add another object to filter the words displayed. The invocation of the second object can be defined by proxy. A proxy is an object that encapsulates a real object. For example, if you try to invoke the Waiter Bean, you will invoke the bean’s proxy, which behaves exactly the same way.

A good example of the proxy design pattern is org. Springframework. Aop) framework. ProxyFactoryBean. The factory builds AOP proxies based on Spring Beans. This class implements the FactoryBean interface that defines the getObject() method. This method is used to return an instance of the requirement Bean to the Bean Factory. In this case, it is not a returned instance, but an AOP proxy. Before perform the proxy object method, by calling the add method to further “modification” proxy objects (in fact, the so-called static agent but is in decorative patterns and add a want you to do actions, not decorative pattern adds clothes, do nothing and other authorized by you to finish).

An example of a ProxyFactory is:

public class TestProxyAop {

  @Test
  public void test(a) {
    ProxyFactory factory = new ProxyFactory(new House());
    factory.addInterface(Construction.class);
    factory.addAdvice(new BeforeConstructAdvice());
    factory.setExposeProxy(true);

    Construction construction = (Construction) factory.getProxy();
    construction.construct();
    assertTrue("Construction is illegal. "
      + "Supervisor didn't give a permission to build "
      + "the house", construction.isPermitted()); }}interface Construction {
  public void construct(a);
  public void givePermission(a);
  public boolean isPermitted(a);
}

class House implements Construction{

  private boolean permitted = false;

  @Override
  public boolean isPermitted(a) {
    return this.permitted;
  }

  @Override
  public void construct(a) {
    System.out.println("I'm constructing a house");
  }

  @Override
  public void givePermission(a) {
    System.out.println("Permission is given to construct a simple house");
    this.permitted = true; }}class BeforeConstructAdvice implements MethodBeforeAdvice {

  @Override
  public void before(Method method, Object[] arguments, Object target) throws Throwable {
    if (method.getName().equals("construct")) { ((Construction) target).givePermission(); }}}Copy the code

This test should pass because we don’t operate directly on the House instance, but rather broker it. The proxy calls the before method of the first BeforeConstructAdvice (pointing to execution before execution of the target method, in our case construct()) through which it gives a “permission” to construct the object’s field (house). The proxy layer provides an additional new capability because it can simply be assigned to another object. To do this, we can only modify the filter before the before method.

Composite patterns

Another structural pattern is the composite pattern. In our first article on design patterns in Spring, we used a builder to construct complex objects. Another approach is to use the composite pattern. This pattern is based on the existence of multiple objects with common behavior and is used to build larger objects. Larger objects still have the same characteristics as the smallest objects. So use it to define the same behavior.

A non-Spring example of a composite object could be a text object written to HTML, consisting of a paragraph containing a SPAN or em tag:

public class CompositeTest {

  @Test
  public void test(a) {
    TextTagComposite composite = new PTag();
    composite.addTag(new SpanTag());
    composite.addTag(new EmTag());

    // sample client code
    composite.startWrite();
    for (TextTag leaf : composite.getTags()) {
      leaf.startWrite();
      leaf.endWrite();
    }
    composite.endWrite();
    assertTrue("Composite should contain 2 tags but it contains "+composite.getTags().size(), composite.getTags().size() == 2); }}interface TextTag {
  public void startWrite(a);
  public void endWrite(a);
}

interface TextTagComposite extends TextTag {
  public List<TextTag> getTags(a);
  public void addTag(TextTag tag);
}

class PTag implements TextTagComposite {
  private List<TextTag> tags = new ArrayList<TextTag>();

  @Override
  public void startWrite(a) {
    System.out.println("<p>");
  }

  @Override
  public void endWrite(a) {
    System.out.println("</p>");
  }

  @Override
  public List<TextTag> getTags(a) {
    return tags;
  }

  @Override
  public void addTag(TextTag tag) { tags.add(tag); }}class SpanTag implements TextTag {

  @Override
  public void startWrite(a) {
    System.out.println("<span>");
  }

  @Override
  public void endWrite(a) {
    System.out.println("</span>"); }}class EmTag implements TextTag {

  @Override
  public void startWrite(a) {
    System.out.println("<em>");
  }

  @Override
  public void endWrite(a) {
    System.out.println("</em>"); }}Copy the code

In this case, you see a composite object. We can distinguish composite objects from non-composite objects because the first one can hold one or more non-composite objects (the private List Tags field in the PTag class). Non-composite objects are called leaves. The TextTag interface is called a component because it provides a common behavior for both object types (a bit like the Linux file management system where files in common are managed in a folder, which is node management).

In the Spring in the world, we retrieve the complex object is org. Springframework. Beans. BeanMetadataElement interface, is used to configure the bean object. It is the basic interface for all inherited objects. Now, on the one hand, we have a leaf, by the org. Springframework. Beans. Factory. The parsing. BeanComponentDefinition said, On the other side is composite positeComponentDefinition at org.springframework.beans.factory.parsing.Com. CompositeComponentDefinition is similar to the components, because it contains addNestedComponent (ComponentDefinition component) method, It allows leaves to be added to nestedComponents in private final lists. As you can see, thanks to this list, BeanComponentDefinition and CompositeComponentDefinition ponentDefinition component is org.springframework.beans.factory.parsing.Com.

The strategy pattern

The third concept described in this article is the strategic design pattern. A policy defines several objects that do the same thing in different ways. The manner in which the task is accomplished depends on the strategy employed. For example, we can go to a country. We can go there by bus, plane, boat or even car. All these methods will get us to the destination country. However, we will check our bank accounts to choose the most appropriate approach. If we have a lot of money, we will take the fastest route (probably private flight). If we don’t have enough, we’ll take the slowest (bus, bus). The bank account is used as a factor in determining the adaptation strategy.

Spring in the org. Springframework. Web. Servlet. MVC. Multiaction. MethodNameResolver class (out of date, but does not affect to study) used in the strategy design pattern. It is a parameterized implementation of the (also outdated) MultiActionController. Before we start explaining policies, we need to understand the utility of MultiActionController. This class allows the same class to handle several types of requests. As each controller in Spring, the MultiActionController executes methods in response to provided requests. Policies are used to detect which method should be used. Parsing process is realized in MethodNameResolver implementation, such as in ParameterMethodNameResolver in the same package. Methods can be resolved by multiple criteria: property mapping, HTTP request parameters, or URL paths.

@Override
public String getHandlerMethodName(HttpServletRequest request) throws NoSuchRequestHandlingMethodException {
  String methodName = null;

  // Check parameter names where the very existence of each parameter
  // means that a method of the same name should be invoked, if any.
  if (this.methodParamNames ! =null) {
    for (String candidate : this.methodParamNames) {
      if (WebUtils.hasSubmitParameter(request, candidate)) {
        methodName = candidate;
        if (logger.isDebugEnabled()) {
          logger.debug("Determined handler method '" + methodName +
            "' based on existence of explicit request parameter of same name");
        }
        break; }}}// Check parameter whose value identifies the method to invoke, if any.
  if (methodName == null && this.paramName ! =null) {
    methodName = request.getParameter(this.paramName);
    if(methodName ! =null) {
      if (logger.isDebugEnabled()) {
        logger.debug("Determined handler method '" + methodName +
          "' based on value of request parameter '" + this.paramName + "'"); }}}if(methodName ! =null && this.logicalMappings ! =null) {
    // Resolve logical name into real method name, if appropriate.
    String originalName = methodName;
    methodName = this.logicalMappings.getProperty(methodName, methodName);
    if (logger.isDebugEnabled()) {
      logger.debug("Resolved method name '" + originalName + "' to handler method '" + methodName + "'"); }}if(methodName ! =null && !StringUtils.hasText(methodName)) {
    if (logger.isDebugEnabled()) {
      logger.debug("Method name '" + methodName + "' is empty: treating it as no method name found");
    }
    methodName = null;
  }

  if (methodName == null) {
    if (this.defaultMethodName ! =null) {
      // No specific method resolved: use default method.
      methodName = this.defaultMethodName;
      if (logger.isDebugEnabled()) {
        logger.debug("Falling back to default handler method '" + this.defaultMethodName + "'"); }}else {
      // If resolution failed completely, throw an exception.
      throw newNoSuchRequestHandlingMethodException(request); }}return methodName;
}Copy the code

As we can see in the previous code, the name of the method is resolved by the presence of predefined properties or parameters in the URL provided by the parameter mapping (by default, the parameter name is Action).

Template pattern

The final design pattern presented in this article is the template approach. This pattern defines the skeleton of the class’s behavior and delays the execution of some of the substeps (in the example below, a method is placed in another method that is executed only when the other method is called, and may be executed sequentially after the other behavior methods). One method is written (construct() in the example below), which is defined as final and acts as a synchronizer. It executes the methods defined by subclasses in a given order. In the real world, we can compare the template approach to housing construction. Independent of the company that builds the house, we need to start with building the foundation and only do the rest after we’re done. The execution logic will be stored in a method that we cannot change. For example, infrastructure or wall painting can be used as a template method, specific to the company building the house. We can see it in the given example:

public class TemplateMethod {

  public static void main(String[] args) {
    HouseAbstract house = newSeaHouse(); house.construct(); }}abstract class HouseAbstract {
  protected abstract void constructFoundations(a);
  protected abstract void constructWall(a);

  // template method
  public final void construct(a) { constructFoundations(); constructWall(); }}class EcologicalHouse extends HouseAbstract {

  @Override
  protected void constructFoundations(a) {
    System.out.println("Making foundations with wood");
  }

  @Override
  protected void constructWall(a) {
    System.out.println("Making wall with wood"); }}class SeaHouse extends HouseAbstract {

  @Override
  protected void constructFoundations(a) {
    System.out.println("Constructing very strong foundations");
  }

  @Override
  protected void constructWall(a) {
    System.out.println("Constructing very strong wall"); }}Copy the code

This code should output:

Constructing very strong foundations
Constructing very strong wallCopy the code

Spring in the org. Springframework. Context. Support. AbstractApplicationContext class using the template method. They are not one template method (construct in our case), but multiple. For example, getsFreshBeanFactory returns a new version of the internal bean factory, calling two abstract methods: refreshBeanFactory (to refresh the factory bean) and getBeanFactory (to get the updated factory bean). This method, among others, is used in public void Refresh () to throw the BeansException that constructs the application context, the IllegalStateException method (mentioned again later in Spring and in application Context analysis).

We can find some GenericApplicationContext in the same package by template method implementation example of the realization of the abstract methods (say a bit of a mouthful, it is good to read a few times) :

/**
  * Do nothing: We hold a single internal BeanFactory and rely on callers
  * to register beans through our public methods (or the BeanFactory's).
  * @see #registerBeanDefinition
  */
@Override
protected final void refreshBeanFactory(a) throws IllegalStateException {
  if (this.refreshed) {
    throw new IllegalStateException(
      "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
  }
  this.beanFactory.setSerializationId(getId());
  this.refreshed = true;
}

@Override
protected void cancelRefresh(BeansException ex) {
  this.beanFactory.setSerializationId(null);
  super.cancelRefresh(ex);
}

/** * Not much to do: We hold a single internal BeanFactory that will never * get released. */
@Override
protected final void closeBeanFactory(a) {
  this.beanFactory.setSerializationId(null);
}

/** * Return the single internal BeanFactory held by this context * (as ConfigurableListableBeanFactory). */
@Override
public final ConfigurableListableBeanFactory getBeanFactory(a) {
  return this.beanFactory;
}

/**
  * Return the underlying bean factory of this context,
  * available for registering bean definitions.
  * <p><b>NOTE:</b> You need to call {@link#refresh()} to initialize the * bean factory and its contained beans with application context semantics * (autodetecting  BeanFactoryPostProcessors, etc). *@return the internal bean factory (as DefaultListableBeanFactory)
  */
public final DefaultListableBeanFactory getDefaultListableBeanFactory(a) {
  return this.beanFactory;
}Copy the code

The above shows how Spring can better organize context (the template approach) by using behavior and structural design patterns and strategies to address execution methods. It uses two structural design patterns, the proxy pattern to simplify the AOP part and the composite pattern to construct complex objects.

Have a problem can add QQ group 523409180 discussion