Spring框架中的设计模式(五)java
经过之前的4篇文章,咱们看到Spring采用了大量的关于建立和结构方面的设计模式。本文将描述属于行为方面的两种设计模式:命令和访问者。spring
前传:shell
Spring框架中的设计模式(一)apache
Spring框架中的设计模式(三)tomcat
这篇文章描述的第一个行为设计模式是命令。它容许将请求封装在一个对象内并附加一个回调动做(每次遇到所所谓的回调你们就只须要理解为一个函数方法就好,省的去浪费那么多脑子)。请求被封装在命令对象之下,而请求的结果被发送到接收者。命令自己不是由调用者执行。为了直白了解其中的主要思想,想象一下管理服务器的状况(远程经过 ssh
操做 Linux
服务器)。管理员( invoker
)在命令行( commands
)中启动一些操做,将结果发送到服务器(接收器)。在这里,全部这一切都是由客户端的终端(也就是咱们用的 xshell
)来完成的。搞个 Demo
来讲明一下(对于命令,它的动做就是执行,对于管理员来说,咱们的动做其实就是一个回车,执不执行固然是管理员说的算了,执行交给命令对象了,服务器最后就是一个展现结果):app
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; } }
测试应经过并打印两个命令:框架
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
中的两段代码:
/** * 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
注释):
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测试用例:
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的实例)参数的访问者模式
。