Spring框架中的设计模式(五)

 Spring框架中的设计模式(五)java

经过之前的4篇文章,咱们看到Spring采用了大量的关于建立和结构方面的设计模式。本文将描述属于行为方面的两种设计模式:命令和访问者。spring

前传:shell

命令模式

这篇文章描述的第一个行为设计模式是命令。它容许将请求封装在一个对象内并附加一个回调动做(每次遇到所所谓的回调你们就只须要理解为一个函数方法就好,省的去浪费那么多脑子)。请求被封装在命令对象之下,而请求的结果被发送到接收者。命令自己不是由调用者执行。为了直白了解其中的主要思想,想象一下管理服务器的状况(远程经过 ssh操做 Linux服务器)。管理员( invoker)在命令行( commands)中启动一些操做,将结果发送到服务器(接收器)。在这里,全部这一切都是由客户端的终端(也就是咱们用的 xshell)来完成的。搞个 Demo来讲明一下(对于命令,它的动做就是执行,对于管理员来说,咱们的动做其实就是一个回车,执不执行固然是管理员说的算了,执行交给命令对象了,服务器最后就是一个展现结果):app

  1. public class CommandTest {
    
    
    
     // This test method is a client
    
     @Test
    
     public void test() {
    
       Administrator admin = new Administrator();
    
       Server server = new Server();
    
    
    
       // start Apache
    
       admin.setCommand(new StartApache(server));
    
       admin.typeEnter();
    
    
    
       // start Tomcat
    
       admin.setCommand(new StartTomcat(server));
    
       admin.typeEnter();
    
    
    
       // check executed commands
    
       int executed = server.getExecutedCommands().size();
    
       assertTrue("Two commands should be executed but only "+
    
         executed+ " were", executed == 2);
    
     }
    
    
    
    }
    
    
    
    // commands
    
    abstract class ServerCommand {
    
    
    
     protected Server server;
    
    
    
     public ServerCommand(Server server) {
    
       this.server = server;
    
     }
    
    
    
     public abstract void execute();
    
    }
    
    
    
    class StartTomcat extends ServerCommand {
    
    
    
     public StartTomcat(Server server) {
    
       super(server);
    
     }
    
    
    
     @Override
    
     public void execute() {
    
       server.launchCommand("sudo service tomcat7 start");
    
     }
    
    }
    
    
    
    class StartApache extends ServerCommand {
    
    
    
     public StartApache(Server server) {
    
       super(server);
    
     }
    
    
    
     @Override
    
     public void execute() {
    
       server.launchCommand("sudo service apache2 start");
    
     }
    
    }
    
    
    
    // invoker
    
    class Administrator {
    
    
    
     private ServerCommand command;
    
    
    
     public void setCommand(ServerCommand command) {
    
       this.command = command;
    
     }
    
    
    
     public void typeEnter() {
    
       this.command.execute();
    
     }
    
    
    
    }
    
    
    
    // receiver
    
    class Server {
    
    
    
     // as in common terminals, we store executed commands in history
    
     private List<String> executedCommands = new ArrayList<String>();
    
    
    
     public void launchCommand(String command) {
    
       System.out.println("Executing: "+command+" on server");
    
       this.executedCommands.add(command);
    
     }
    
    
    
     public List<String> getExecutedCommands() {
    
       return this.executedCommands;
    
     }
    
    
    
    }

     

     

测试应经过并打印两个命令:框架

  1. Executing: sudo service apache2 start on server
    
    Executing: sudo service tomcat7 start on server

     

     

命令模式不只容许封装请求(ServerCommand)并将其传输到接收器(Server),并且还能够更好地处理给定的请求。在这里,这种更好的处理是经过存储命令的执行历史。在Spring中,咱们在beanFactory后置处理器的特性中来找到指令设计模式的原理。要经过快速对它们进行定义,应用程序上下文会启动后置处理器,并能够用来对建立的bean进行一些操做(这里不打算细说了,具体的我后面会专门写一篇这方面的文章,来分析其中的源码细节)。运维

当咱们将先前Demo里呈现的命令逻辑转换并对比到 Springbean工厂后处理器时,咱们能够区分如下 actors后置处理器bean(是指实现 BeanFactoryPostProcessor接口)是命令,org.springframework.context.support.PostProcessorRegistrationDelegate是调用者(它执行 postProcessBeanFactory方法注册全部的后置处理器bean,此处看下面第二段代码)和接收器org.springframework.beans.factory.config.ConfigurableListableBeanFactory能够在元素(bean)构造初始化以前修改它们(例如:在初始化bean以前能够更改属性)。

另外,回顾下上面的那个Demo,和咱们的Demo中的命令历史管理同样。 PostProcessorRegistrationDelegate包含一个内部类 BeanPostProcessorChecker,它能够记录当一个bean不符合处理条件的状况。

能够观察 PostProcessorRegistrationDelegate中的两段代码:

  1. /**
    
        * BeanPostProcessor that logs an info message when a bean is created during
    
        * BeanPostProcessor instantiation, i.e. when a bean is not eligible for
    
        * getting processed by all BeanPostProcessors.
    
        */
    
       private static class BeanPostProcessorChecker implements BeanPostProcessor {
    
    
    
           private static final Log logger = LogFactory.getLog(BeanPostProcessorChecker.class);
    
    
    
           private final ConfigurableListableBeanFactory beanFactory;
    
    
    
           private final int beanPostProcessorTargetCount;
    
    
    
           public BeanPostProcessorChecker(ConfigurableListableBeanFactory beanFactory, int beanPostProcessorTargetCount) {
    
               this.beanFactory = beanFactory;
    
               this.beanPostProcessorTargetCount = beanPostProcessorTargetCount;
    
           }
    
    
    
           @Override
    
           public Object postProcessBeforeInitialization(Object bean, String beanName) {
    
               return bean;
    
           }
    
    
    
           @Override
    
           public Object postProcessAfterInitialization(Object bean, String beanName) {
    
               if (bean != null && !(bean instanceof BeanPostProcessor) && !isInfrastructureBean(beanName) &&
    
                       this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
    
                   if (logger.isInfoEnabled()) {
    
                       logger.info("Bean '" + beanName + "' of type [" + bean.getClass() +
    
                               "] is not eligible for getting processed by all BeanPostProcessors " +
    
                               "(for example: not eligible for auto-proxying)");
    
                   }
    
               }
    
               return bean;
    
           }
    
    
    
           private boolean isInfrastructureBean(String beanName) {
    
               if (beanName != null && this.beanFactory.containsBeanDefinition(beanName)) {
    
                   BeanDefinition bd = this.beanFactory.getBeanDefinition(beanName);
    
                   return RootBeanDefinition.ROLE_INFRASTRUCTURE == bd.getRole();
    
               }
    
               return false;
    
           }
    
       }

     

     

定义后的调用,用的就是 ConfigurableListableBeanFactory的实例(看 BeanPostProcessorChecker注释):

  1. public static void registerBeanPostProcessors(
    
               ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    
    
    
           String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
    
    
    
           // Register BeanPostProcessorChecker that logs an info message when
    
           // a bean is created during BeanPostProcessor instantiation, i.e. when
    
           // a bean is not eligible for getting processed by all BeanPostProcessors.
    
           int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
    
     //BeanPostProcessorChecker
    
           beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
    
    
    
           // Separate between BeanPostProcessors that implement PriorityOrdered,
    
           // Ordered, and the rest.
    
           List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    
           List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
    
           List<String> orderedPostProcessorNames = new ArrayList<>();
    
           List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    
           for (String ppName : postProcessorNames) {
    
               if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    
                   BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    
                   priorityOrderedPostProcessors.add(pp);
    
                   if (pp instanceof MergedBeanDefinitionPostProcessor) {
    
                       internalPostProcessors.add(pp);
    
                   }
    
               }
    
               else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    
                   orderedPostProcessorNames.add(ppName);
    
               }
    
               else {
    
                   nonOrderedPostProcessorNames.add(ppName);
    
               }
    
           }
    
    
    
           // First, register the BeanPostProcessors that implement PriorityOrdered.
    
           sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
    
           registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
    
    
    
           // Next, register the BeanPostProcessors that implement Ordered.
    
           List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
    
           for (String ppName : orderedPostProcessorNames) {
    
               BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    
               orderedPostProcessors.add(pp);
    
               if (pp instanceof MergedBeanDefinitionPostProcessor) {
    
                   internalPostProcessors.add(pp);
    
               }
    
           }
    
           sortPostProcessors(beanFactory, orderedPostProcessors);
    
           registerBeanPostProcessors(beanFactory, orderedPostProcessors);
    
    
    
           // Now, register all regular BeanPostProcessors.
    
           List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    
           for (String ppName : nonOrderedPostProcessorNames) {
    
               BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    
               nonOrderedPostProcessors.add(pp);
    
               if (pp instanceof MergedBeanDefinitionPostProcessor) {
    
                   internalPostProcessors.add(pp);
    
               }
    
           }
    
           registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
    
    
    
           // Finally, re-register all internal BeanPostProcessors.
    
           sortPostProcessors(beanFactory, internalPostProcessors);
    
           registerBeanPostProcessors(beanFactory, internalPostProcessors);
    
    
    
           // Re-register post-processor for detecting inner beans as ApplicationListeners,
    
           // moving it to the end of the processor chain (for picking up proxies etc).
    
           beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
    
       }

     

     

总结一个过程就是,我要BeanFactory里面获得对象(也就是为了获得一个命令的执行结果),那么,想要在获得对象的时候就已经实现了一些对其修改的想法,那么就经过后置处理器,也是就实现了后置处理器接口的beans(命令里能够经过传入不一样的参数来获得不一样结果,或者对命令的脚本进行修改),而后还须要一个执行者(咱们在作自动化运维的时候,不止操做一个脚本,这里的 PostProcessorRegistrationDelegate就是集中来管理这些的),最后获得的结果就由 BeanFactory来展现咯。

访问者模式

接下来要介绍的一个行为设计模式是Visitor:抽象一点就是经过另外一种类型的对象来使一个对象访问。在这个简短定义中,使用这个设计模式中的对象将被视为访问者或对象可被访问。第一个访问者要有可访问支持。这个模式的一个现实的例子能够是一个汽车质检员,他们检查一些汽车零件,好比轮子,制动器和发动机,以判断汽车质量是否合格。咱们来作个JUnit测试用例:

  1. public class VisitorTest {
    
    
    
     @Test
    
     public void test() {
    
       CarComponent car = new Car();
    
       Mechanic mechanic = new QualifiedMechanic();
    
       car.accept(mechanic);
    
       assertTrue("After qualified mechanics visit, the car should be broken",
    
         car.isBroken());
    
       Mechanic nonqualifiedMechanic = new NonQualifiedMechanic();
    
       car.accept(nonqualifiedMechanic);
    
       assertFalse("Car shouldn't be broken becase non qualified mechanic " +
    
         " can't see breakdowns", car.isBroken());
    
     }
    
    
    
    }
    
    
    
    // visitor
    
    interface Mechanic {
    
     public void visit(CarComponent element);
    
     public String getName();
    
    }
    
    
    
    class QualifiedMechanic implements Mechanic {
    
    
    
     @Override
    
     public void visit(CarComponent element) {
    
       element.setBroken(true);
    
     }
    
    
    
     @Override
    
     public String getName() {
    
       return "qualified";
    
     }
    
    }
    
    
    
    class NonQualifiedMechanic implements Mechanic {
    
    
    
     @Override
    
     public void visit(CarComponent element) {
    
       element.setBroken(true);
    
     }
    
    
    
     @Override
    
     public String getName() {
    
       return "unqualified";
    
     }
    
    }
    
    
    
    // visitable
    
    abstract class CarComponent {
    
     protected boolean broken;
    
    
    
     public abstract void accept(Mechanic mechanic);
    
    
    
     public void setBroken(boolean broken) {
    
       this.broken = broken;
    
     }
    
    
    
     public boolean isBroken() {
    
       return this.broken;
    
     }
    
    }
    
    
    
    class Car extends CarComponent {
    
    
    
     private boolean broken = false;
    
     private CarComponent[] components;
    
    
    
     public Car() {
    
       components = new CarComponent[] {
    
         new Wheels(), new Engine(), new Brake()
    
       };
    
     }
    
    
    
     @Override
    
     public void accept(Mechanic mechanic) {
    
       this.broken = false;
    
       if (mechanic.getName().equals("qualified")) {
    
         int i = 0;
    
         while (i < components.length && this.broken == false) {
    
           CarComponent component = components[i];
    
           mechanic.visit(component);
    
           this.broken = component.isBroken();
    
           i++;
    
         }
    
       }
    
       // if mechanic isn't qualified, we suppose that
    
       // he isn't able to see breakdowns and so
    
       // he considers the car as no broken
    
       // (even if the car is broken)
    
     }
    
    
    
     @Override
    
     public boolean isBroken() {
    
             return this.broken;
    
     }
    
    }
    
    
    
    class Wheels extends CarComponent {
    
    
    
     @Override
    
     public void accept(Mechanic mechanic) {
    
       mechanic.visit(this);
    
     }
    
    }
    
    
    
    class Engine extends CarComponent {
    
    
    
     @Override
    
     public void accept(Mechanic mechanic) {
    
       mechanic.visit(this);
    
     }
    
    }
    
    
    
    class Brake extends CarComponent {
    
    
    
     @Override
    
     public void accept(Mechanic mechanic) {
    
       mechanic.visit(this);
    
     }
    
    }

     

     

在这个例子中,咱们能够看到他们有两个机制(访问者,其实就是免检和难免检):合格和不合格。暴露于他们的可见对象是汽车。经过其接受方式,决定哪一个角色应该适用于被访问者(经过代码 mechanic.getName().equals("qualified")来判断)。当访问者合格时,Car让他分析全部组件。若是访问者不合格,Car认为其干预是无用的,而且在方法 isBroken()中直接返回 false(其实就是为了达到一个免检的效果)。 Spring在beans配置中实现了访问者设计模式。为了观察,咱们能够看看org.springframework.beans.factory.config.BeanDefinitionVisitor对象,该对象用于 解析bean元数据并将其解析为 String(例如:具备做用域或工厂方法名称的XML属性)或 Object(例如:构造函数定义中的参数)。已解析的值在与分析的bean关联的 BeanDefinition实例中进行判断设置。具体的源码请看 BeanDefinitionVisitor的代码片断:

/**

* Traverse the given BeanDefinition object and the MutablePropertyValues

* and ConstructorArgumentValues contained in them.

* @param beanDefinition the BeanDefinition object to traverse

* @see #resolveStringValue(String)

*/

public void visitBeanDefinition(BeanDefinition beanDefinition) {

 visitParentName(beanDefinition);

 visitBeanClassName(beanDefinition);

 visitFactoryBeanName(beanDefinition);

 visitFactoryMethodName(beanDefinition);

 visitScope(beanDefinition);

 visitPropertyValues(beanDefinition.getPropertyValues());

 ConstructorArgumentValues cas = beanDefinition.

   getConstructorArgumentValues();

 visitIndexedArgumentValues(cas.

   getIndexedArgumentValues());

 visitGenericArgumentValues(cas.

   getGenericArgumentValues());

}



protected void visitParentName(BeanDefinition beanDefinition) {

 String parentName = beanDefinition.getParentName();

 if (parentName != null) {

   String resolvedName = resolveStringValue(parentName);

   if (!parentName.equals(resolvedName)) {

     beanDefinition.setParentName(resolvedName);

   }

 }

}

​​​​​​在这种状况下,他们只是访问方式,没有对访问者作任何补充的控制(在Demo里对car的质检员作了控制)。这里访问包括分析给定 BeanDefinition的参数,并将其替换为已解析对象。

在最后一篇关于Spring中设计模式的文章中,咱们发现了2种行为模式: 用于处理bean工厂的后置处理的命令模式用于将定义的bean参数转换为面向对象(String或Object的实例)参数的访问者模式

相关文章
相关标签/搜索