Spring框架中的设计模式(五)
来源:互联网 发布:php curl 存储cookie 编辑:程序博客网 时间:2024/05/20 16:11
命令模式
这篇文章描述的第一个行为设计模式是命令。它允许将请求封装在一个对象内并附加一个回调动作(每次遇到所所谓的回调大家就只需要理解为一个函数方法就好,省的去浪费那么多脑子)。请求被封装在命令对象之下,而请求的结果被发送到接收者。命令本身不是由调用者执行。为了直白了解其中的主要思想,想象一下管理服务器的情况(远程通过ssh
操作Linux
服务器)。管理员(invoker
)在命令行(commands
)中启动一些操作,将结果发送到服务器(接收器)。在这里,所有这一切都是由客户端的终端(也就是我们用的xshell
)来完成的。搞个Demo
来说明一下(对于命令,它的动作就是执行,对于管理员来讲,我们的动作其实就是一个回车,执不执行当然是管理员说的算了,执行交给命令对象了,服务器最后就是一个展示结果):
public class CommandTest {// This test method is a clientpublic void test() {Administrator admin = new Administrator();Server server = new Server();// start Apacheadmin.setCommand(new StartApache(server));admin.typeEnter();// start Tomcatadmin.setCommand(new StartTomcat(server));admin.typeEnter();// check executed commandsint executed = server.getExecutedCommands().size();assertTrue("Two commands should be executed but only "+executed+ " were", executed == 2);}}// commandsabstract 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);}public void execute() {server.launchCommand("sudo service tomcat7 start");}}class StartApache extends ServerCommand {public StartApache(Server server) {super(server);}public void execute() {server.launchCommand("sudo service apache2 start");}}// invokerclass Administrator {private ServerCommand command;public void setCommand(ServerCommand command) {this.command = command;}public void typeEnter() {this.command.execute();}}// receiverclass Server {// as in common terminals, we store executed commands in historyprivate 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 serverExecuting: sudo service tomcat7 start on server
命令模式不仅允许封装请求(ServerCommand)并将其传输到接收器(Server),而且还可以更好地处理给定的请求。在这里,这种更好的处理是通过存储命令的执行历史。在Spring中,我们在beanFactory后置处理器的特性中来找到指令设计模式的原理。要通过快速对它们进行定义,应用程序上下文会启动后置处理器,并可以用来对创建的bean进行一些操作(这里不打算细说了,具体的我后面会专门写一篇这方面的文章,来分析其中的源码细节)。
当我们将先前Demo里呈现的命令逻辑转换并对比到Spring bean工厂后处理器
时,我们可以区分以下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;}public Object postProcessBeforeInitialization(Object bean, String beanName) {return bean;}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;//BeanPostProcessorCheckerbeanFactory.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 {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());}}// visitorinterface Mechanic {public void visit(CarComponent element);public String getName();}class QualifiedMechanic implements Mechanic {public void visit(CarComponent element) {element.setBroken(true);}public String getName() {return "qualified";}}class NonQualifiedMechanic implements Mechanic {public void visit(CarComponent element) {element.setBroken(true);}public String getName() {return "unqualified";}}// visitableabstract 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()};}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)}public boolean isBroken() {return this.broken;}}class Wheels extends CarComponent {public void accept(Mechanic mechanic) {mechanic.visit(this);}}class Engine extends CarComponent {public void accept(Mechanic mechanic) {mechanic.visit(this);}}class Brake extends CarComponent {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的实例)参数的访问者模式
。
- Spring框架中的设计模式(五)
- Spring框架中的设计模式(一)
- Spring框架中的设计模式(一)
- Spring框架中的设计模式(二)
- Spring框架中的设计模式(三)
- Spring框架中的设计模式(四)
- Spring框架中的设计模式(一)
- Spring框架中的设计模式(二)
- Spring框架中的设计模式(三)
- spring中的设计模式
- spring中的设计模式
- spring中的设计模式
- Spring中的设计模式
- Spring中的设计模式
- Spring中的设计模式
- Spring中的设计模式
- Spring中的设计模式
- spring中的设计模式
- Java—API
- WebSocket connection to 'ws://localhost/aa/ws1' net::ERR_CONNECTION_REFUSED
- springmvc-annotation注解式开发(表单封装)
- 配置Java环境
- 使用Ynm3k的iosMonkey脚本测试iOS应用的稳定性
- Spring框架中的设计模式(五)
- 限流模式-Guava的RateLimiter
- Coursera Machine Learning 第二周编程全套满分题目+注释 ex1+ex1_multi(包括选做Optional)
- Centos6.5 下Docker的安装
- easyui中的tree的图标更改
- MFC 单例运行三种方式
- 关于prepareStatement可以防止SQL注入的理解
- 华为Eudemon1000防火墙-详细配置
- 配置监听(系统启动和关闭时运行的程序)