brief introduction
- Commons chain is a subproject of apache commons. It is mainly used in the "responsibility chain" scenario. The call process of action in struts is supported by the "chain" framework If your project also has requirements based on this scenario, you can consider using it
- The so-called "responsibility chain" is a series of ordered command s that can be executed in order and can exchange or transmit execution results to each other, which is similar to the "responsibility chain" model we often call
Let's start with an example
- Automobile sales process: test run - > sales negotiation - > arrange Finance - > end sales
Suppose you use a traditional template pattern
public abstract class SellVehicleTemplate { // Selling cars public void sellVehicle() { testDriveVehicle(); negotiateSale(); arrangeFinancing(); closeSale(); } // Test run public abstract void testDriveVehicle(); // Sales negotiation public abstract void negotiateSale(); // Arrange Finance public abstract void arrangeFinancing(); // Close sales public abstract void closeSale(); }
Use the common chain responsibility chain mode
import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; // Get customer information public class GetCustomerInfo implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("GetCustomerInfo "); return false; } } // Commissioning (Continued) public class TestDriveVehicle implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Test drive the vehicle"); return false; } } // Sales negotiation public class NegotiateSale implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Negotiate sale"); return false; } } // Arrange Finance public class ArrangeFinancing implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Arrange financing"); return false; } } // Close sales public class CloseSale implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Congratulations " + ctx.get("customerName") +", you bought a new car!"); return false; } } // Define responsibility chain and test import org.apache.commons.chain.impl.ChainBase; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; import org.apache.commons.chain.impl.ContextBase; // Inherit ChainBase public class SellVehicleChain extends ChainBase { public SellVehicleChain() { super(); addCommand(new GetCustomerInfo()); addCommand(new TestDriveVehicle()); addCommand(new NegotiateSale()); addCommand(new ArrangeFinancing()); addCommand(new CloseSale()); } public static void main(String[] args) throws Exception { Command process = new SellVehicleChain(); Context ctx = new ContextBase(); process.execute(ctx); } // Operation results: Test drive the vehicle Negotiate sale Arrange financing Congratulations George Burdell, you bought a new car!
Context explicit call
- Commons Chain provides a way to define the responsibility chain in the configuration file, and create chain - config. In the project resource directory XML file
<catalog> <chain name="sell-vehicle"> <command id="GetCustomerInfo" className="com.jadecove.chain.sample.GetCustomerInfo"/> <command id="TestDriveVehicle" className="com.jadecove.chain.sample.TestDriveVehicle"/> <command id="NegotiateSale" className="com.jadecove.chain.sample.NegotiateSale"/> <command id="ArrangeFinancing" className="com.jadecove.chain.sample.ArrangeFinancing"/> <command id="CloseSale" className="com.jadecove.chain.sample.CloseSale"/> </chain> </catalog> // Read from xml configuration public class CatalogLoader { private static final String CONFIG_FILE = "/com/jadecove/chain/sample/chain-config.xml"; private ConfigParser parser; private Catalog catalog; public CatalogLoader() { parser = new ConfigParser(); } public Catalog getCatalog() throws Exception { if (catalog == null) { parser.parse(this.getClass().getResource(CONFIG_FILE)); } catalog = CatalogFactoryBase.getInstance().getCatalog(); return catalog; } public static void main(String[] args) throws Exception { CatalogLoader loader = new CatalogLoader(); Catalog sampleCatalog = loader.getCatalog(); Command command = sampleCatalog.getCommand("sell-vehicle"); Context ctx = new SellVehicleContext(); command.execute(ctx); } }
API details
- Command: an executable "instruction", and multiple commands form a "responsibility chain". It has only one method, Boolean execute (context). When the "responsibility chain" starts calling, all command object execute methods on the chain will be executed successively until the end, or an exception is thrown, or a command returns true to terminate the call. The context object represents the context information of the current "responsibility chain", which can be used to save some temporary variables (which can be shared among commands). If this method returns false, it means that the responsibility chain will continue to execute subsequent commands. If it returns true, it means that the call is terminated and subsequent commands will not be executed
- Chain: the implementation class is ChainBase, the command organizer, including addCommand method. You can add multiple commands, and then call the execute method to execute the execute method in the command chain in turn.
- Filter: it also extends the command interface, can be added to the Chain like command, and has an additional interface Boolean postprocess (context, exception, exception). When all command and filter execute methods are executed without exception, the postprocess method of filter will be executed in reverse order; Once an exception occurs in the link, the postprocess method of the filter will be executed immediately. If the method returns true after processing, it indicates that the error processing has been completed and the execution of the Chain will not end. However, in essence, this error is caught and will not be thrown out. If the postprocess method returns false, the error will continue to be thrown out, and then the Chain will end abnormally.
- Context: similar to "session", it is used to save the "variable parameters" or "Command execution results" that need to be maintained in the current Chain. The internal storage structure of context is a Map, and its data can be operated by the Command in the Chain. Context is not thread safe, and it is not expected that this instance can be reused. Every time the Chain is called, a new context instance should be created, Its implementation class is ContextBase.
- We can write a SellVehicleContext class to inherit ContextBase and perform type conversion in command, so that we can get the value directly through get
public class SellVehicleContext extends ContextBase { private String customerName; public String getCustomerName() { return customerName; } public void setCustomerName(String name) { this.customerName = name; } } // Type conversion public boolean execute(Context ctx) throws Exception { SellVehicleContext myCtx = (SellVehicleContext) ctx; System.out.println("Congratulations " + myCtx.getCustomerName() + ", you bought a new car!"); return false; } // call public static void main(String[] args) throws Exception { Command process = new SellVehicleChain(); Context ctx = new SellVehicleContext(); process.execute(ctx); }
Version used in work:
import org.apache.commons.chain.Context; import org.apache.commons.chain.impl.ChainBase; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.stereotype.Component; /** * Business code entries of different responsibility chains are distinguished by chainName */ @Component("chainRunner") public class ChainRunner implements BeanFactoryAware { private BeanFactory beanFactory; public void runChain( String chainName, Context context) { try { createChain(chainName).execute( context ); } catch ( Exception exc ) { throw new RuntimeException( "Chain \"" + chainName + "\": Execution failed.", exc ); } } public void setBeanFactory( BeanFactory beanFactory ) throws BeansException { this.beanFactory = beanFactory; } protected ChainBase createChain( String chainName ) { return ( ChainBase ) this.beanFactory.getBean( chainName ); } }
Cite the above example:
// Get customer information public class GetCustomerInfoCommand implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("GetCustomerInfo "); ctx.put("getCustomerInfo","ok"); return false; } } // Commissioning (Continued) @Component public class TestDriveVehicleCommand implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Test drive the vehicle"); ctx.put("testDriveVehicle","ok"); return false; } } // Sales negotiation @Component public class NegotiateSaleCommand implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Negotiate sale"); ctx.put("negotiateSale","ok"); return false; } } // Arrange Finance @Component public class ArrangeFinancingCommand implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Arrange financing"); ctx.put("arrangeFinancing","ok"); return false; } } // Close sales @Component public class CloseSaleCommand implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Congratulations " + ctx.get("customerName") +", you bought a new car!"); return false; } }
Test:
public class ChainCarSalesTest extends BaseTest { @Autowired private ChainRunner chainRunner; @Test public void test() { Context context = new ContextBase(); context.put("customerName", "Lao Wang"); chainRunner.runChain(ChainCarSales.SERVICE_NAME, context); // Get return value System.out.println("Get one of them command Return value of:"+context.get("negotiateSale")); } } GetCustomerInfo Test drive the vehicle Negotiate sale Arrange financing Congratulations Lao Wang, you bought a new car! Get one of them command Return value of:ok
Author: industrious bear
Link: https://www.jianshu.com/p/883bab2fcd36
Source: Jianshu
The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.