Reprint: http://www.cnblogs.com/shipengzhi/articles/2716004.html One, the problem to be solved
- Some APIs have signature parameters (signature), the passport first verifies the signature, and the validation passes before the implementation method is executed.
The first implementation method (Origin): The code that writes the checksum in the interface that requires the signature check, for example:
Boolean isValid = Accountservice.validsignature (AppID, signature, client_signature); if (!isvalid) return Errorutil.builderror (errorutil.err_code_com_sing);
The second implementation (Spring interception): Using the Spring Interceptor function to intercept the specified interface, the interceptor implements the signature verification algorithm, for example:
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path= "/connect/share/**"/> < Mvc:mapping path= "/friend/**"/> <mvc:mapping path= "/account/get_bind"/> <mvc:mapping path= "/ Account/get_associate "/> <bean class=" Com.sogou.upd.passport.web.inteceptor. Identityandsecureinteceptor"/>
The third implementation approach (Spring AOP): Custom annotations that add annotations to methods that require signature validation, such as:
@SecureValid@ResponseBody @requestmapping (value = "/share/add", method = requestmethod.post) public Object Addshare (httpservletrequest req, httpservletresponse res,infoapirequestparams requestparams) {...}
2. Logging functions, such as: Some interfaces need to record the request and response, execution time, class name, method name and other log information. can also be implemented in the above three ways. 3. Code performance monitoring issues such as method invocation time, number of times, thread and stack information, and so on. This type of problem presents a solution to the latter topic, which uses the above three methods to achieve too many shortcomings.
Here are three ways to compare implementations:
Implementation method |
Advantages |
Disadvantages |
Origin |
Best performance with no reflection mechanism |
Code reuse is not good when logic is complex Need to write the same code in each interface (I'm too lazy to write a few letters) |
Spring Inter |
Ideal for intercepting all methods, such as printing all method execution times while debugging Similar filter functions, such as log processing, encoding conversion, permission checking is a sub-function of AOP |
No reflection mechanism, performance has an impact Need to configure which interfaces to intercept in the XML file, it is more troublesome |
Spring AOP |
Easy to use, add an annotation Very flexible, can be @before, @After, @Around, etc. |
No reflection mechanism, performance is affected (performance comparison is shown in detail later) |
Implementation of Spring AOP custom annotations Add the following to the Maven dependency:
<!--Spring AOP + AspectJ by Shipengzhi--<dependency> <groupid>org.springframework& Lt;/groupid> <artifactId>spring-aop</artifactId> <version>3.0.6.release</ver sion> </dependency> <dependency> <groupid>org.springframework</groupid> ; <artifactId>spring-aspects</artifactId> <version>3.0.6.RELEASE</version> </de pendency> <dependency> <groupId>org.aspectj</groupId> <artifactId> aspectjrt</artifactid> <version>1.6.11</version> </dependency> <depend Ency> <groupId>org.aspectj</groupId> <ARTIFACTID>ASPECTJWEAVER</ARTIFACTID&G T <version>1.6.11</version> </dependency> <dependency> <GROUPID>CGLib</groupid> <artifactId>cglib</artifactId> <version>2.1_3</version> </dependency> <!--End--
Add spring support in Spring-***.xml to open the AOP feature
Header file declaration: xmlns:aop= "HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP" HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP/http Www.springframework.org/schema/aop/spring-aop-3.0.xsd <!--Custom AOP-- <aop:aspectj-autoproxy Proxy-target-class= "true" > <aop:include name= "Controlleraspect"/> </aop:aspectj-autoproxy >
Write custom annotations. Implements a description of the functionality implemented by the method to obtain descriptive information in the notification
/* * Verify signature legitimacy Custom transaction */@Target ({Elementtype.method}) @Retention (retentionpolicy.runtime) @Documented @inheritedpublic @ Interface Securevalid { String desc () Default "Identity and security authentication begins ...";}
@Target is used to describe the use of annotations (that is, where the annotations described can be used), and the values are:
Take value |
Describe |
CONSTRUCTOR |
Used to describe the constructor (lead Bento). |
FIELD |
Used to describe the domain (lead bento). |
Local_variable |
Used to describe local variables (pick-up bento). |
METHOD |
Used to describe a method. |
Package |
Used to describe the package (pick box). |
PARAMETER |
Used to describe parameters. |
TYPE |
Used to describe a class or interface (even an enum). |
The @Retention is used to describe the life cycle of annotations (that is, the description of the annotations in which they are valid), with the following values:
Take value |
Describe |
SOURCE |
Valid in the source file (that is, the source file is reserved, and the boxed box is picked). |
CLASS |
Valid in class file (that is, class is reserved, and the boxed box is picked). |
RUNTIME |
Valid at run time (that is, run-time retention). |
@Documented By default the Javadoc command will not generate our annotation to the doc, so using that tag is telling the JDK that it will also generate annotation into Doc.
@Inherited For example, there is a Class A, on which there is a tag annotation, then the subclass B of a is not to be labeled annotation can inherit it, the answer is yes
There are three types of annotation property values : base type, array type, enum type
1: Basic String type
Public @interface userdefinedannotation { intvalue (); String name (); String address (); } Used: @UserdefinedAnnotation (value=123,name= "Wangwenjun", address= "Mars") public static void Main (string[] args) { System.out.println ("Hello"); } }
If there is only one attribute in a annotation named value, I can omit the attribute name when I am not using it.
Public @interface userdefinedannotation { int value (); } You can also write the following form of Java code @UserdefinedAnnotation (123) equivalent to @UserdefinedAnnotation (value=123) public static void Main (string[] args) { System.out.println ("Hello"); }
2: Array type We define a property of an array type in the custom annotation code as follows:
Public @interface userdefinedannotation { int[] value (); } Used: Public class Useannotation { @UserdefinedAnnotation ({123}) public static void Main (string[] args) { System.out.println ("Hello"); }
Note 1: Where 123 of the outer braces can be omitted, because there is only one element, if there is more than one element, the curly braces cannot be omitted. For example {123,234}.
Note 2: Where the property name value is omitted when we use it, it is because he is called value, and if it is a different name we can not omit the format that must be @userdefinedannotation (property name ={123,234}).
3: Enum type
public enum Dateenum { monday,tuesday,wednesday,thursday,friday,saturday,sunday } is then defined in a annotation Package com.wangwenjun.annatation.userdefined; Public @interface userdefinedannotation { dateenum week (); } Used: public class Useannotation { @UserdefinedAnnotation (week=dateenum.sunday) public static void main (string[ ] args) { System.out.println ("Hello"); } }
4: Default Value
Public @interface userdefinedannotation { String name () default "Zhangsan"; } Used: Public class Useannotation { @UserdefinedAnnotation () public static void Main (string[] args) { System.out.println ("Hello"); } }
5: note
Annotation is not allowed to inherit other interfaces, this is the need to pay attention, this is also a rule of annotation.
Annotation is also the existence of package structure, in the use of direct import can be.
Annotation types are supported only for OST data types, one-dimensional arrays of enum types and class types, other types or user-defined classes are not available as annotation types, I have reviewed the documents and tested them.
Write an operation log slice notification implementation class
Before writing a slice notification implementation class, we need to figure out which types of notifications we need, a pre-notification, a post-notification, a surround notification, or an exception notification. According to my needs, we know that we have logged the operation log in two cases, one is the success of the operation, one is the operation failed. When the operation is successful, the method must have been completed, we need to implement a post-notification, the operation fails to indicate that the method exception does not work properly completed, Gu also need an exception notification. The code is as follows:
@Aspect//This note indicates that the class is a slice class
@Component//Inject dependent public class Logaspect {//Callout The method body is a post-notification, and when the target method executes successfully executes the method body @AfterReturning ("Within (COM.ABCHINA.I Rms.. *) && @annotation (RL) "public void addlogsuccess (Joinpoint JP, Rmpflog RL) {object[] Parames = JP.G Etargs ();//Gets the target method body parameter String params = Parseparames (parames); Parse the parameters of the target method body String className = Jp.gettarget (). GetClass (). toString ();//Gets the target class name className = Classname.subs Tring (classname.indexof ("com")); String signature = Jp.getsignature (). toString ();//Gets the target method signature String methodName = signature.substring (signature.last IndexOf (".") +1, Signature.indexof ("(")); String modelname = Getmodelname (className); Gets the owning module according to the class name ...} Label the method body as an exception notification, and when the target method exception occurs, the method body @AfterThrowing (pointcut= "Within (com.abchina.irms) is executed. *) && @annotation (RL) ", throwing=" ex ") public void Addlog (Joinpoint JP, Rmpflog RL, businessexception ex) { ... }
There are two identical parameters JP and RL,JP are tangent objects, through which we can get the class, method name, parameters and other information of the method in which the tangent point is cut, and the method can see the implementation of the methods body. RL is the object of our custom annotation, which allows us to get the value of the parameter in the annotation. This gets the descriptive information for the method. An ex parameter is given in the exception notification, which is the exception thrown when the method executes, so that the appropriate exception information can be obtained. This is the custom exception I wrote here. Note: If you specify an exception parameter, the exception object must be consistent with the exception thrown by the method body that the notification is in, otherwise the notification will not execute.
@AfterReturning ("Within (com.abchina.irms. *) && @annotation (RL)), specifies that the method body is a post-notification with an expression parameter that is used to retrieve the tangent point that meets the criteria. The expression specifies that all method bodies with @rmpflog annotations under the Com/abchina/irms directory and all subdirectories are tangent points.
@AfterThrowing (pointcut= "Within (com.abchina.irms). *) && @annotation (RL) ", throwing=" ex "), is the specified method body as an exception notification, which has an expression parameter and a throw exception argument. The expression parameter has the same meaning as the expression parameter of the post-notification, and throws an exception argument, which means that if the com/abchina/ Any method body with @rmpflog annotations under the Irms directory and all its subdirectories will execute when the Businessexception exception is thrown at execution time.
Basic concepts of AOP:
- Facets (Aspect): Notifications and pointcuts together form facets, times, places, and "stories" to take place.
- Connection point (Joinpoint): A program is able to apply a "timing" of notifications, which are connection points, such as when a method is invoked, when an exception is thrown, and so on.
- Notification (ADVICE): A notification defines what a facet is and when it is used. Describes the work to be done on the slice and when it is necessary to perform the work.
- Entry point (Pointcut): A notification defines the "story" and the time that the slice will take place, and the Pointcut defines where the story occurs, such as the name of a class or method.
- Target object: The object that is being notified.
- AOP Proxy (AOP proxies) has two kinds of proxy methods in spring AOP, JDK dynamic agent and cglib agent. By default, when TargetObject implements an interface, the JDK dynamic agent is used, whereas the Cglib proxy is used instead.
- Weaving (Weaving) the process of applying facets to a target object to create a new proxy object, weaving generally occurs in the following time:
(1) Compile time: When a class file is compiled, this requires a special compiler to do so, such as AspectJ's weaving compiler;
(2) class loading: Use special ClassLoader to enhance the byte code of the class before the target class is loaded into the program;
(3) Run time: section at a time of operation is woven into, SPRINGAOP is in this way woven into the plane, the principle is the use of the JDK dynamic agent.
pointcut expression, Pointcut the definition consists of two parts: pointcut expression (expression) and Pointcut signature (signature). Let's look at the format of the execution expression first:
Execution (modifier-pattern? ret-type-pattern declaring-type-pattern? Name-pattern (Param-pattern) Throws-pattern?)
Pattern indicates modifier match (Modifier-pattern?), return value match (Ret-type-pattern), Classpath match (Declaring-type-pattern?), method name matching (name-pattern) , Parameter matching ((Param-pattern)), exception type matching (Throws-pattern?), followed by "?" option is available.
You can use "*" in each pattern to represent all matches. In (Param-pattern), you can specify a specific parameter type, separated by "," between multiple parameters, and each can also use "*" to indicate a match of any type of parameter, such as a (string) method that matches a string parameter; (*,string) Represents a method that matches two parameters, the first argument can be any type, and the second argument is a string type; you can use (..) Represents 0 or more arbitrary parameters.
Now let's look at a few examples:
1) Execution (* * (..)) means matching all methods
2) Execution (public * com. savage.service.userservice.* (..)) represents all of the publicly-owned methods in the matching Com.savage.server.UserService
3) Execution (* com.savage.server). *.*(..)) Represents all methods that match the Com.savage.server package and its sub-packages
In addition to the execution expression, there are also within, this, target, args and other pointcut expressions. A pointcut definition consists of a pointcut expression and a pointcut signature, for example:
Pointcut expression @pointcut ("Execution (* com.savage.aop.messagesender.* (..))") When point signs private void log () {} and then you want to use the defined pointcut, you can specify the pointcut signature, such as: @Before ("og ()") above the definition equivalent to: @Before ("execution (* com.savage.aop.messagesender.* (..)) ")
When pointcut is defined, you can also use &&, | | |,! operations, such as:
@Pointcut ("Logsender () | | | Logreceiver () ")
Private void LogMessage () {}
Notification (Advice) type
@Before Pre-notification (before advice): A notification that is performed before a connection point (Joinpoint), but this notification does not prevent execution before the connection point.
Post- @After notification (after advice): Notification that is executed when a connection point exits (whether it is a normal return or an unexpected exit).
@AfterReturning Notification after return advice: A notification that is executed after a connection point is completed normally, excluding the case of throwing an exception.
@Around Surround notification (Around advice): A notification that surrounds a connection point, similar to the Dofilter method of the filter in the servlet specification in the Web. You can customize the behavior before and after the call to the method, or you can choose not to execute.
@AfterThrowing Notification After an exception is thrown (after throwing advice): the notification that is executed when the method throws an exception.
Custom annotation implementations at the controller level
/** * Security and Identity Check for Controller */@Around ("Within (@org. Springframework.stereotype.Controller *) && @ann Otation (IS) "Public Object valididentityandsecure (Proceedingjoinpoint PJP, Securevalid is) throws Exception {object[] args = Pjp.getargs (); The parameters of all methods in the controller, the first two are: Request,response httpservletrequest Request = (httpservletrequest) args[0]; HttpServletResponse response = (httpservletresponse) args[1]; String AppID = Request.getparameter ("AppID"); int app_id = integer.valueof (AppID); String signature = request.getparameter ("signature"); String clientsignature = Request.getparameter ("Client_signature"); String uri = Request.getrequesturi (); String Provider = Request.getparameter ("provider"); if (Stringutils.isempty (provider)) {Provider = "passport"; }//Check try {appservice.validateappid (app_id) for AppID and signature; BoOlean IsValid = accountservice.validsignature (app_id, signature, clientsignature); if (!isvalid) throw new Problemexception (errorutil.err_code_com_sing); } catch (Exception e) {return HandleException (E, provider, URI); }//Continue executing the next code Object retVal = null; try {retVal = Pjp.proceed (); } catch (Throwable e) {if (e instanceof Exception) {return handleexception ((Exception) e, provider, URI);} }//Current interface cannot go here return retVal; }
III. implementation of Spring Interceptor Add interceptor configuration to Spring-***.xml
Writing Interceptor Implementation Classes
public class Costtimeinteceptor extends Handlerinterceptoradapter { private static final Logger log = LOGGERFACTORY.G Etlogger (costtimeinteceptor.class); @Override Public Boolean prehandle (httpservletrequest request, httpservletresponse response, Object handler) Throws Exception { long startTime = System.currenttimemillis (); Request.setattribute ("StartTime", startTime); return true; } @Override public void Posthandle (HttpServletRequest request, httpservletresponse response, Object handler, Modelandview Modelandview) throws Exception { long startTime = (long) request.getattribute ("StartTime"); Long endTime = System.currenttimemillis (); Long executetime = Endtime-starttime; if (log.isinfoenabled ()) { log.info ("[" + Request.getrequesturi () + "] Executetime:" + executetime + "MS"); } }}
Four, performance comparison
experimental Environment: for/account/get_associate interface, concurrent 500, 10 minutes of pressure measurement
Index |
Origin |
Spring Inter |
Spring AOP |
Cpu |
user%:26.57 sys%:10.97 cpu%:37.541 |
user%:26.246 sys%:10.805 cpu%:37.051 |
User%:24.123 sys%:9.938 cpu%:34.062 |
Load |
13.85 |
13.92 |
12.21 |
QPS |
6169 |
6093.2 |
5813.27 |
Rt |
0.242ms |
0.242ms |
0.235ms |
Using AOP has no significant effect on response time
No significant impact on load with AOP
No significant CPU impact with AOP
Conclusion: The effect of using AOP performance is negligible
Resolve log and signature checks with spring AOP custom annotations