Let's start with the code. What is traditional AOP (aspect-oriented programming) programming
Requirements: Implement a simple calculator to add logs before each step of the operation. The most traditional way is as follows:
Calculator.java
Package cn.limbo.spring.aop.calculator;/** * Created by Limbo on 16/7/14. */public interface Calculator { int add (int i, int j); int sub (int i, int j); int mul (int i, int j); int div (int i, int j);}
Calculatorimpl.java
Package cn.limbo.spring.aop.calculator;/** * Created by Limbo on 16/7/14. */public class Calculatorimpl implements Calculator {@Override public int add (int i, int j) {System.out.pri Ntln ("The method add begin with [" + i + "," + j+ "]"); System.out.println ("The method add End with [" + i + "," + j+ "]"); return i + j; } @Override public int sub (int i, Int. j) {System.out.println ("the method sub begin with [" + i + "," + j+ "]" ); System.out.println ("The method sub End with [" + i + "," + j+ "]"); return i-j; } @Override public int mul (int i, Int. j) {System.out.println ("The method mul begin with [" + i + "," + j+ "]" ); System.out.println ("The method Mul end With [" + i + "," + j+ "]"); return I * j; } @Override public int div (int i, Int. j) {System.out.println ("the method div begin with [" + i + "," + j+ "]" ); System.out.println ("The method div End With [" + i + "," + j+ "]");return i/j; }}
This completes the requirements, but we found that if you want to modify the log information, then you need to change in the specific method, this is cumbersome, and the original refreshing method is very confusing, the method should represent the core function, rather than these insignificant concerns, The following method is implemented in native Java to dynamically add output log methods when executing methods
Calculatorimpl.java
Package cn.limbo.spring.aop.calculator;/** * Created by Limbo on 16/7/14. */public class Calculatorimpl implements Calculator { @Override public int Add (int i, int j) { return i + j;
} @Override public int sub (int i, int j) { return i-j; } @Override public int mul (int i, int j) { return i * j; } @Override Public int div (int i, int j) { return i/j; }}
Calculatorloggingproxy.java
Package Cn.limbo.spring.aop.calculator;import Java.lang.reflect.invocationhandler;import Java.lang.reflect.Method ; Import Java.lang.reflect.proxy;import java.util.arrays;import java.util.objects;/** * Created by Limbo on 16/7/14. */public class Calculatorloggingproxy {//object to proxy private Calculator target; Public Calculatorloggingproxy (Calculator target) {this.target = target; The public Calculator Getloggingproxy () {///proxy object is loaded by which class loader is responsible for loading ClassLoader loader = Target.getclass (). GetClass Loader (); The type of the proxy object, that is, which methods class[] interfaces = new Class[]{calculator.class}; When invoking a method in the proxy object, execute the code invocationhandler handler = new Invocationhandler () {@Override/** * Proxy: The agent of the object that is being returned, in general, do not use the object in the Invoke method * Method: Methods being invoked * args: When calling a method, the passed in parameter */public object Invoke (object proxy, Method method, object[] args) throws Throwable {Stri Ng MethodName = Method.getname (); System.out.println ("the method" + MethodName + "begins with" + arrays.aslist (args)); Log Object result = Method.invoke (Target,args); System.out.println ("the method" + MethodName + "ends with" + result); return result; } }; Calculator proxy = (Calculator) proxy.newproxyinstance (Loader,interfaces,handler); return proxy; }}
Main.java
Package cn.limbo.spring.aop.calculator;/** * Created by Limbo on 16/7/14. */public class Main {public static void Main (string[] args) { Calculator Calculator = new Calculatorimpl (); Calculator proxy = new Calculatorloggingproxy (Calculator). Getloggingproxy (); int result = Proxy.add (up); SYSTEM.OUT.PRINTLN ("--->" + result); result = Proxy.sub; SYSTEM.OUT.PRINTLN ("--->" + result); result = Proxy.mul (3,2); SYSTEM.OUT.PRINTLN ("--->" + result); result = Proxy.div (14,2); SYSTEM.OUT.PRINTLN ("--->" + result);} }
This write although has simplified the code, and can arbitrarily modify the log information code, but it is still very troublesome to write!!!
Below we implement the spring-brought AOP package but join
Com.springsource.org.aopalliance-1.0.0.jar
Com.springsource.org.aspectj.weaver-1.8.5.release.jar
These two extra packages
Look at the code below, the main point of all the unload code inside
Calculator.java
Package cn.limbo.spring.aop.impl;/** * Created by Limbo on 16/7/14. */public interface Calculator { int add (int i, int j); int sub (int i, int j); int mul (int i, int j); int div (int i, int j);}
Calculatorimpl.java
Package Cn.limbo.spring.aop.impl;import org.springframework.stereotype.component;/** * Created is limbo on 16/7/14. */@Component ("Calculatorimpl") public class Calculatorimpl implements Calculator { @Override public int Add ( int i, int j) { return i + J; } @Override Public int sub (int i, int j) { return i-j; } @Override public int mul (int i, int j) { return i * j; } @Override Public int div (int i, int j) { return i/j; }}
Loggingaspect.java
Package Cn.limbo.spring.aop.impl;import Org.aspectj.lang.joinpoint;import Org.aspectj.lang.ProceedingJoinPoint; Import Org.aspectj.lang.annotation.*;import Org.springframework.core.annotation.order;import Org.springframework.stereotype.component;import Java.util.arrays;import Java.util.list;import java.util.Objects;/ * * Created by Limbo on 16/7/14. *///This class as a tangent: it is required to be placed in the IOC container, then declared as a slice @order (0)//Specify the tangent priority, the smaller the priority, the higher the @aspect@componentpublic class Loggingaspect {/** * A method that declares a pointcut expression, which, in general, does not need to add additional code in the method * primarily to re-use the path, using @pointcut to declare other notifications following the pointcut expression * to refer to the current pointcut expression directly using the method name */@Point Cut ("Execution (* cn.limbo.spring.aop.impl.calculator.* (..))") public void Declarejointpointexpression () {}//declares that the method is a pre-notification: Executes the @Before before the target method ("Declarejointpointexpression ()" )//@Before ("Execution (* cn.limbo.spring.aop.impl.*.* (..))") Any return value under the package, any class, any method, any parameter type public void Beforemethod (Joinpoint joinpoint) {String methodName = Joinpoint.getsig Nature (). GetName (); List<object> args = Arrays.aslist (Joinpoint.getargs ()); System.out.println ("The Method" + methodname+ "begins with" + args); }//Executes after the target method executes, regardless of whether the method is faulted//The return value of the target method cannot be accessed in the post-notification, only access the @After by returning the notification ("Execution (* Cn.limbo.spring.aop.impl.Calculat Or.* (Int,int)) "public void Aftermethod (Joinpoint joinpoint) {String methodName = Joinpoint.getsignature (). GetName (); System.out.println ("The Method" + methodname+ "Ends"); /** * Code executed after the normal end of the method * Returns a notification that the return value of the method can be accessed */@AfterReturning (value = "Execution" (* cn.limbo.spring.aop.imp L.calculator.* (..)) ", returning =" result ") public void afterreturning (Joinpoint joinpoint, Object result) { String methodName = Joinpoint.getsignature (). GetName (); System.out.println ("The Method" + MethodName + "Ends with" + result); /** * Execute code when the target method has an exception * you can access the exception object, and you can specify a specific exception when the notification is executed */@AfterThrowing (value = "Execution" (* CN.LIMBO.SPR Ing.aop.impl.calculator.* (..)) ", Throwing = "ex") public void afterthrowing (Joinpoint joinpoint,exception ex)//exception can be changed to a specific exception such as NullPointerException { String methodName = Joinpoint.getsignature (). GetName (); System.out.println ("The Method" + MethodName + "occurs with" + ex); /** * Surround notification requires Proceedingjoinpoint type parameters feature the most powerful * surround notification is similar to the whole process of dynamic agents: Parameters of the Proceedingjoinpoint type can determine whether to execute the target method * and the surround Pass Must have a return value, which is the return value of the target method */@Around ("Execution (* cn.limbo.spring.aop.impl.calculator.* (..))") Public Object Aroundmethod (Proceedingjoinpoint proceedingjoinpoint) {object result =null; String methodName = Proceedingjoinpoint.getsignature (). GetName (); try {//Pre-Notification System.out.println ("the Method" + MethodName + "begins with" + arrays.aslist (Proceed Ingjoinpoint.getargs ())); result = Proceedingjoinpoint.proceed (); Return notification System.out.println ("the Method" + MethodName + "Ends with" + result); } catch (Throwable throwable) {//Exception notification throwable.printstacktrace (); } System.out.println ("The Method" + methodName + "Ends"); return result; }}
Applicationcontext.xml
<?xml Version= "1.0" encoding= "UTF-8"? ><beans xmlns= "Http://www.springframework.org/schema/beans" xmlns:xsi= "http ://www.w3.org/2001/XMLSchema-instance "xmlns:context=" Http://www.springframework.org/schema/context "XMLNS:AOP = "HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP" xsi:schemalocation= "Http://www.springframework.org/schema/beans Http://www.springframework.org/schema/beans/spring-beans.xsd Http://www.springframework.org/schema/context http ://www.springframework.org/schema/context/spring-context.xsd HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP/http Www.springframework.org/schema/aop/spring-aop.xsd "> <!--Configure auto-Scan Package--<context:component-scan Base-package= "Cn.limbo.spring.aop.impl" ></context:component-scan> <!--make aspect annotations work and automatically generate proxy objects for matching classes- > <aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>
Using XML to configure AOP
Application-config.xml
<?xml version= "1.0" encoding= "UTF-8"? ><beans xmlns= "Http://www.springframework.org/schema/beans" xmlns: Xsi= "Http://www.w3.org/2001/XMLSchema-instance" xmlns:aop= "HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP" xmlns:tx= " Http://www.springframework.org/schema/tx "xsi:schemalocation=" Http://www.springframework.org/schema/beans http:/ /www.springframework.org/schema/beans/spring-beans-2.0.xsd HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP http://www. Springframework.org/schema/aop/spring-aop-2.0.xsd Http://www.springframework.org/schema/tx Http://www.springfram Ework.org/schema/tx/spring-tx-2.0.xsd "> <bean id=" Usermanager "class=" Com.tgb.aop.UserManagerImpl "/>& lt;! --<bean id= "Aspcejhandler" class= "Com.tgb.aop.AspceJAdvice"/>--><bean id= "Xmlhandler" class= " Com.tgb.aop.XMLAdvice "/><aop:config><aop:aspect id=" aspect "ref=" Xmlhandler "><aop:pointcut id=" Pointusermgr "expression=" Execution (* com.tgb.aop.*.find* (..))" /><aop:before method= "Dobefore" pointcut-ref= "pointusermgr"/><aop:after method= "DoAfter" pointcut-ref= "Pointusermgr"/><aop:around method= "Doaround" pointcut-ref= "Pointusermgr"/><aop:after-returning Method= "Doreturn" pointcut-ref= "pointusermgr"/><aop:after-throwing method= "dothrowing" throwing= "ex" pointcut-ref= "Pointusermgr"/></aop:aspect></aop:config></beans>
A total of 5 types of notifications, of which around is the most powerful, but not necessarily the most commonly used, aspect the bottom of the implementation are through the agent to achieve, can only say this wheel made good
Spring Learning notes----AOP programming