Spring Learning ==> AOP

I. Overview

  AOP (Aspect Oriented Programming) called aspect-oriented programming, program development is mainly used to solve some of the problems on the system level, such as logging, transaction, permissions, etc., Struts2 interceptor AOP design is based on the idea of ​​a more classic example of. Without changing the original logic, add some extra features. This agent also functions to read and write separation can also use AOP to do.

  AOP can be said that OOP (Object Oriented Programming, Object Oriented Programming) supplement and perfect. OOP introduced as encapsulation, inheritance, polymorphism, etc. concept to build a hierarchy of objects, used to simulate the behavior of a common set. However, OOP allows developers to define vertical relationship, but are not suitable for transverse relationship defined, for example, the log function. Log code tends to spread laterally in all object hierarchy, the core object corresponding to the function it no relation to other types of code, such as security, exception handling, and continuity are also transparent so, this spread independent code is referred to throughout the transverse (cross cutting), in OOP design, which led to a lot of code repetition, to the detriment of reusable modules.

  Contrary AOP technology, which uses a technique called "transverse", the internal cross-sectional decapsulates the object, and those that affect the behavior of the public classes encapsulated into a plurality of reusable modules, and named it " Aspect ", namely section. The so-called "cut", it simply is that nothing to do with business, but it is the responsibility of the business logic or common module called encapsulated, easy to duplicate code to reduce system and reduce the degree of coupling between modules, and facilitate future operability and maintainability.

  Use "cross-cutting" technology, AOP the software system is divided into two parts: the core concerns and crosscutting concerns. The main flow of business processes is a core concern, not part of the relationship is with crosscutting concerns. It features a crosscutting concern is that they often occur in many core concerns, and everywhere essentially similar, such as certification authority, log things. AOP is that the various concerns separation system, the core and crosscutting concerns separated.

Second, solutions to problems

Earlier we mentioned, the use of AOP ideas to solve the problem log, things, permissions, and so for us. There is now a demand: add time calculation method of execution in all core business is old business systems and logging.

public interface IInfoService {

  String addInfo(String info) throws Throwable;

  String updateInfo(String info);

  String delInfo(String info);

  String queryInfo(String info);
}
IInfoService Interface
public class InfoServiceImpl implements IInfoService {
  @Override
  public String addInfo(String info) {

    System.out.println("InfoServiceImpl.addInfo");

    return "InfoServiceImpl.addInfo111";
  }

  @Override
  public String updateInfo(String info) {

    System.out.println("InfoServiceImpl.updateInfo");

    return "InfoServiceImpl.updateInfo";
  }

  @Override
  public String delInfo(String info) {

    System.out.println("InfoServiceImpl.delInfo");

    return "InfoServiceImpl.delInfo";
  }

  @Override
  public String queryInfo(String info) {

    System.out.println("InfoServiceImpl.queryInfo");

    return "InfoServiceImpl.queryInfo";
  }
}
InfoServiceImpl implementation class

IInfoService interfaces, among them addInfo, updateInfo, delInfo, queryInfo four methods, InfoServiceImpl class implements these four methods, if we are to statistics InfoServiceImpl class four specific methods for the implementation and execution time of each method are written to the log, how do we achieve it?

1, template design patterns

We have designed a template class as follows:

public  class ServiceTemplate { 

  public  static <T> T Test (Supplier <T> Supplier) {
     // 1. the recording start time and the name of a printing method, where only the name of a method of fixing the printing 
    Long Start = System.currentTimeMillis (); 
    the System. out.println ( "addInfo Start ..." ); 

    // 2. get Object incoming object instances supplier of 
    T RESP = supplier.get (); 

    // 3. recording end time and print method name 
    Long end = System. with currentTimeMillis (); 
    System.out.println ( "addInfo End ..." ); 
    System.out.println ( "cost Time:" + (End - Start)); 

    return RESP; 
  } 
}

We used a supply type (without parameters, return value) of the object as a parameter to the static method supplier Test (), in supplier.get () method executes are recorded before and after the time of execution, and finally calculate the execution time of the method .

Let's look at how to call four methods InfoServiceImpl class:

public  class AppTemplate { 

  public  static  void main (String [] args) { 
  
// generate objects Supplier Supplier <String> Supplier = () -> { the try {
     IInfoService InfoService = new new InfoServiceImpl (); 
return infoService.addInfo ( "" ); } the catch (Throwable the Throwable) { Throwable.printStackTrace (); } return null ; }; / ** * pattern mode call * call ServiceTemplate.test () method performs supplier.get () method * to perform the above infoService.addInfo ( "") * / RESP String = ServiceTemplate.test (Supplier); System.out.println (RESP); System.out.println ( "--------------- ------ template call mode --------- " ); } }

Throughout the implementation process is as follows: First, it will generate a Supplier object as a parameter passed to ServiceTemplate.test () method, when test () method will first execute print "addInfo start ..." and record the time method to begin, and then call supplier.get will be executed when () method infoService.addInfo ( "") method, and finally print "addInfo end ..." and the method of computing time, the results are as follows:

However, we found that if you want to perform other methods (such as updateInfo), the infoService.addInfo ( "") instead of infoService.updateInfo ( ""), results are as follows:

The method of execution has changed, but the log beginning of the log and the end of the print has not changed, because we are in print in the journal template is written dead, no way changes depending on the method name, because what method call in the template we do not You know, so this implementation is not perfect.

2, the decorative design pattern

Or the use of the above IInfoService InfoServiceImpl interfaces and implementation class. Then we design a IInfoService interface implementation class, as follows:

public class DeclareInfoServiceImpl implements IInfoService {

  private IInfoService infoService;

  public DeclareInfoServiceImpl(IInfoService infoService) {
    this.infoService = infoService;
  }

  @Override
  public String addInfo(String info) {

    System.out.println("addInfo start...");

    String resp = null;
    try {
      resp = this.infoService.addInfo(info);
    } catch (Throwable throwable) {
      throwable.printStackTrace();
    }

    System.out.println("addInfo end...");

    return resp;
  }

  @Override
  public String updateInfo(String info) {
    System.out.println("updateInfo start...");

    String resp = this.infoService.updateInfo(info);

    System.out.println("updateInfo end...");

    return resp;
  }

  @Override
  public String delInfo(String info) {
    System.out.println("delInfo start...");

    String resp = this.infoService.delInfo(info);

    System.out.println("delInfo end...");

    return resp;
  }

  @Override
  public String queryInfo(String info) {
    System.out.println("queryInfo start...");

    String resp = this.infoService.queryInfo(info);

    System.out.println("queryInfo end...");

    return resp;
  }
}
DeclareInfoServiceImpl implementation class

This class implements all the methods from IInfoService interface constructor parameters IInfoService objects, in addition to achieve the necessary time to calculate and print the log, the object calls once again IInfoService same name addInfo, updateInfo and other methods, so if we pass a InfoServiceImpl object class, the method can be performed before or after adding the log and computation time. Test code is as follows:

public  class AppDeclare { 

  public  static  void main (String [] args) throws the Throwable { 

    // Decorator call 
    IInfoService InfoService = new new DeclareInfoServiceImpl ( new new InfoServiceImpl ()); 
    infoService.addInfo ( "" ); 
    System.out.println ( " --------------- --------------- decorative call mode " ); 
  } 
}

At first glance decorator call mode, we found buffered stream operations like file IO operating system. Yes, stream buffer operation is also a decorative pattern to the design. Look at the following result:

However, this model is also very obvious shortcomings, we need to implement all methods DeclareInfoServiceImpl class are coupled with a manual log, if the method is very much under the circumstances is unlikely.

3, dynamic proxy design pattern

Dynamic proxy model built using JDK classes of Proxy 'newProxyInstance () method to generate a proxy object, the proxy object and then use the corresponding method to execute.

public  class the ServiceProxy { 

  public  static  void main (String [] args) throws the Throwable { 

    IInfoService InfoService = new new InfoServiceImpl (); 

    / ** 
     * Construction of Proxy, generates a proxy object proxyInfoService 
     * Loader ClassLoader, 
     * Class [] the interfaces, <?> 
     * H of InvocationHandler 
     * / 
    IInfoService proxyInfoService = (IInfoService) the Proxy.newProxyInstance (
         // ClassLoader Loader: class loader 
        . infoService.getClass () getClassLoader (),
         // class [] the interfaces <?>: the interface proxy object
        . infoService.getClass () The getInterfaces (),
         // of InvocationHandler H: 
        new new of InvocationHandler () { 
            @Override 
            public Object Invoke (Object Proxy, Method, Method, Object [] args) throws the Throwable {
               // 1. inlet log 
              Long Start = the System .currentTimeMillis (); 
              System.out.println (String.format ( "% S ... Start" , method.getName ())); 

              // 2. performing service code
               // equivalent logic for performing a method InfoServiceImpl.addInfo 
              Response = Object Method.invoke (InfoService, args); 

              // 3. outlet log 
              Long= End System.currentTimeMillis (); 
              System.out.println (String.format ( "% S End ..." , method.getName ())); 
              System.out.println ( "cost Time:" + (End - Start)); 

              // returns the execution result of the service code 
              return Response;}}); 

    // call to the specific method through a proxy object 
    proxyInfoService.addInfo ( "" ); 
    proxyInfoService.updateInfo ( "" ); 
  } 
}

'newProxyInstance () method takes three parameters:

  • The first parameter is the class loader ClassLoader to acquire infoService proxy object class loader by infoService.getClass () getClassLoader ().;
  • The second parameter Class [] interfaces is an array of objects bytecode proxy object belongs infoService interface, is acquired by infoService.getClass () getInterfaces () <?>.;
  • The third parameter overrides invoke InvocationHandler InvocationHandler the object class () method, we can increase the time statistics, logs, print and other functions inside. In invoke () method by Method.invoke () method to be executed corresponding proxy object infoService addInfo (), updateInfo () method and the like.

Generated proxy objects  proxyInfoService similar objects beneath the class, but is virtual, we do not see.

public class ProxyInfoServiceImpl implements IInfoService {

  private IInfoService infoService;

  private InvocationHandler h;

  public ProxyInfoServiceImpl(IInfoService infoService) {
    this.infoService = infoService;
  }

  @Override
  public String addInfo(String info) throws Throwable {

    System.out.println("start");

    String resp = infoService.addInfo(info);

    System.out.println("end");

    // 大概模拟下InvocationHandler的调用过程
    return (String) h.invoke(this.infoService, null, new Object[]{info});
  }

  @Override
  public String updateInfo(String info) {
    return null;
  }

  @Override
  public String delInfo(String info) {
    return null;
  }

  @Override
  public String queryInfo(String info) {
    return null;
  }
}
Alerts generated class

This class looks like DeclareInfoServiceImpl implementation class decorator pattern, it is also to achieve self-Interface IInfoService, but once invike () method will tune in every way.

Results are as follows:

three,

 

four,

Guess you like

Origin www.cnblogs.com/L-Test/p/11609338.html