J2EE Design Patterns 1 Intercepting Filter(截取筛选器)

来源:互联网 发布:小米平板软件 编辑:程序博客网 时间:2024/05/22 12:32

Design Patterns的意义

经典Design Pattern解决的是coding的问题,逻辑之间的维护和解耦。而J2EE Design Pattern关注的是系统架构的问题。二者层面虽略有不同,但是原理相近,万佛朝宗。

1术语,定义

2解决方案重用,一些问题解决的最佳实践

3优化系统架构

4标准,可复用的工具支持

 

 

Context

TThe presentation-tier request handling mechanism receives many different types of requests, which require varied types of processing. Some requests are simply forwarded to the appropriate handler component, while other requests must be modified, audited, or uncompressed before being further processed.

 

Problem

The classic solution consists of a series of conditional checks, with any failed check aborting the request. Nested if/else statements are a standard strategy, but this solution leads to code fragility and a copy-and-paste style of programming, because the flow of the filtering and the action of the filters is compiled into the application.

The key to solving this problem in a flexible and unobtrusive manner is to have a simple mechanism for adding and removing processing components, in which each component completes a specific filtering action.

 

Services should be easy to add or remove unobtrusively without affecting existing components, so that they can be used in a variety of combinations, such as

  • Logging and authentication
  • Debugging and transformation of output for a specific client
  • Uncompressing and converting encoding scheme of input

 

 

 

Solution

Create pluggable filters to process common services in a standard manner without requiring changes to core request processing code. The filters intercept incoming requests and outgoing responses, allowing preprocessing and post-processing. We are able to add and remove these filters unobtrusively, without requiring changes to our existing code.

We are able, in effect, to decorate our main processing with a variety of common services, such as security, logging, debugging, and so forth. These filters are components that are independent of the main application code, and they may be added or removed declaratively. For example, a deployment configuration file may be modified to set up a chain of filters. The same configuration file might include a mapping of specific URLs to this filter chain.

 

 

 

To implement the Custom Filter Strategy, the developer could use the Decorator pattern [GoF] to wrap filters around the core request processing logic. For example, there may be a debugging filter that wraps an authentication filter. 

 

 

In the servlet controller, we delegate to a method called processRequest to handle incoming requests, as shown in Example 7.3.

Example 7.3 Handling Requests

public void processRequest(ServletRequest req,   ServletResponse res)   throws IOException, ServletException {  Processor processors = new DebuggingFilter(     new AuthenticationFilter(new CoreProcessor()));  processors.execute(req, res);  //Then dispatch to next resource, which is probably   // the View to display  dispatcher.dispatch(req, res);}

 

 

Notice that when we use a decorator implementation, each filter invokes on the next filter directly, though using a generic interface. Alternatively, this strategy can be implemented using a FilterManager and FilterChain. In this case, these two components coordinate and manage filter processing and the individual filters do not communicate with one another directly. This design approximates that of a servlet 2.3-compliant implementation, though it is still a custom strategy. The FilterChain adds filters to the chain in the appropriate order (for the sake of brevity, this is done in the FilterChain constructor, but would normally be done in place of the comment), processes the filters, and finally processes the target resource. Figure 7.4 is a sequence diagram for this code.

This strategy does not allow us to create filters that are as flexible or as powerful as we would like. For one, filters are added and removed programmatically. While we could write a proprietary mechanism for handling adding and removing filters via a configuration file, we still would have no way of wrapping the request and response objects. Additionally, without a sophisticated buffering mechanism, this strategy does not provide flexible postprocessing.

 

The Standard Filter Strategy provides solutions to these issues, leveraging features of the 2.3 Servlet specification, which has provided a standard solution to the filter dilemma.

 

 

Standard Filter Strategy

Filters are controlled declaratively using a deployment descriptor.

 

 

 

The following excerpt in Example 7.10 is from the deployment descriptor for the Web application containing this example. It shows how these two filters are registered and then mapped to a resource, in this case a simple test servlet. Additionally, the sequence diagram for this example is shown in Figure 7.5.

Example 7.10 Deployment Descriptor - Standard Filter Strategy

...<filter>    <filter-name>StandardEncodeFilter</filter-name>    <display-name>StandardEncodeFilter</display-name>    <description></description>    <filter-class> corepatterns.filters.encodefilter.            StandardEncodeFilter</filter-class>  </filter>  <filter>    <filter-name>MultipartEncodeFilter</filter-name>    <display-name>MultipartEncodeFilter</display-name>    <description></description>    <filter-class>corepatterns.filters.encodefilter.            MultipartEncodeFilter</filter-class>    <init-param>      <param-name>UploadFolder</param-name>      <param-value>/home/files</param-value>    </init-param> </filter>...<filter-mapping>    <filter-name>StandardEncodeFilter</filter-name>    <url-pattern>/EncodeTestServlet</url-pattern>  </filter-mapping>  <filter-mapping>    <filter-name>MultipartEncodeFilter</filter-name>    <url-pattern>/EncodeTestServlet</url-pattern>  </filter-mapping>...

Consequences

  • Centralizes Control with Loosely Coupled Handlers
    Filters provide a central place for handling processing across multiple requests, as does a controller. Filters are better suited to massaging requests and responses for ultimate handling by a target resource, such as a controller. Additionally, a controller often ties together the management of numerous unrelated common services, such as authentication, logging, encryption, and so forth, while filtering allows for much more loosely coupled handlers, which can be combined in various combinations.

  • Improves Reusability
    Filters promote cleaner application partitioning and encourages reuse. These pluggable interceptors are transparently added or removed from existing code, and due to their standard interface, they work in any combination and are reusable for varying presentations.
  • Declarative and Flexible Configuration
    Numerous services are combined in varying permutations without a single recompile of the core code base.
  • Information Sharing is Inefficient
    Sharing information between filters can be inefficient, since by definition each filter is loosely coupled. If large amounts of information must be shared between filters, then this approach may prove to be costly.

Related Patterns

  • Front Controller 
    The controller solves some similar problems, but is better suited to handling core processing.

  • Decorator [GoF]
    The Intercepting Filter pattern is related to the Decorator pattern, which provides for dynamically pluggable wrappers.
  • Template Method [GoF]
    The Template Method pattern is used to implement the Template Filter Strategy.
  • Interceptor [POSA2]
    The Intercepting Filter pattern is related to the Interceptor pattern, which allows services to be added transparently and triggered automatically.
  • Pipes and Filters [POSA1]
    The Intercepting Filter pattern is related to the Pipes and Filters pattern.

所有的消息进系统之前需要过滤一下(auth,verify,enrich,standarrise),单一过滤器需要很多的if else,逻辑耦合,维护复杂。所以需要解耦。

用IOC的方式,将过滤器与input Controller mapping(也可以定义顺序)起来。而filters之间用类似装饰器模式的方式形成管道,一层一层的分离过滤逻辑,同时也可以灵活组合。

在每个过滤器之中使用模板方法模式,将pre,main,post process规格化,对输入进行处理和包装。

 

原创粉丝点击