In fact, the meaning of AOP is to face-slicing programming.
OO focuses on our approach to problem solving (encapsulated into method), while AOP focuses on the common denominator of many problem-solving approaches, and is a complement to oo thinking!
Let's take an example that people often cite:
For example, we are going to develop an application that has a lot of business methods in it, but we are now going to do a full monitoring of the implementation of this method, or some monitoring. Maybe we'll just go ahead and add a log record.
Let's write an example to see our simplest solution
Let's first write an interface Ihello.java code as follows: |
|
package sinosoft.dj.aop.staticaop; public interface ihello { /** *//** * Suppose this is a business method * @param name */ void sayhello ( String name, } There is a method for entering "Hello" The name of the incoming; let's write a class to implement the Ihello interface package sinosoft.dj.aop.staticaop;public class hello implements ihello { public void sayhello (String name) { System.out.println ("hello " + name); } Now we're going to add a logging business to this business method, What do we do without changing the original code? Maybe you'll write a class to implement the Ihello interface and rely on the Hello class. The code is as follows: package sinosoft.dj.aop.staticaop; public class HelloProxy implements IHello { private ihello hello; public helloproxy (Ihello hello) { this.hello = hello; } public void SayHello (String name) { logger.logging (level.debuge, " Sayhello method start. "); hello.sayhello (name); Logger.logging (level.info, "sayhello method end!"); }} where. The Logger class and level enumeration code is as follows:logger.java package sinosoft.dj.aop.staticaop; import java.util.date; public class logger{ /** *//** * logging by level * @param level * @param context */ public statIc void logging (Level level, string context) { if (Level.equals (level.info)) { system.out.println (New date (). toLocaleString () + + Context); } if ( Level.equals (level.debuge)) { System.err.println (New date () + " " + context); } }}level.javapackage sinosoft.dj.aop.staticaop;public enum level { info,debuge;} Let's go write a test class and see the code below:test.javapackage sinosoft.dj.aop.staticaop;public class test { public static void main (String[] args)  {   &NBSp; ihello hello = new helloproxy (New Hello ()); hello.sayhello ("Doublej"); } run the above code and we can get the following result: Tue mar 04 20:57:12 cst 2008 sayhello method start. hello doublej2008-3-4 20:57:12 sayhello method end!
From the code above, we can see that the Hello object was created by Helloproxy this so-called proxy state. So,
If we want to remove the logging function later, we just change the code that gets the Hello object to the following:
Package SINOSOFT.DJ.AOP.STATICAOP;
public class Test {
public static void Main (string[] args) {
Ihello Hello = new Hello ();
Hello.sayhello ("Doublej");
}
}
The above code can be said to be the simplest implementation of AOP!
But we'll find a problem, if we have a lot of classes like Hello, are we going to write a lot of helloproxy like that?
Yes, it is. In fact, it is a very troublesome thing. After jdk1.3. The JDK provides us with an API Java.lang.reflect.InvocationHandler class. This class allows us to do something dynamically when the JVM invokes a method of a class. Let's change the code above to see the effect.
Similarly, we write a Ihello interface and a Hello implementation class. In the interface. We define two methods; The code is as follows:
ihello.java package sinosoft.dj.aop.proxyaop; public interface ihello { /** *//** * Business Process a method * @param name */ void SayHello (String name); /** *//** * Business Process B methods * @param name */ void saygoogbye (string name);} hello.java package sinosoft.dj.aop.proxyaop; public class hello Implements ihello { public void sayhello (String Name) { system.out.println ("Hello " + name); } public void saygoogbYe (string name) { system.out.println (name+ " goodbye! "); } We're going to write a proxy class just like that. Let this class implement the Java.lang.reflect.InvocationHandler interface, the code is as follows: package sinosoft.dj.aop.proxyaop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.method; import java.lang.reflect.proxy; public class dynaproxyhello implements invocationhandler { /** *//** * the object to be processed (that is, the object we want to add business logic to before and after the method, such as Hello in the example) */ private Object delegate; /** *//** * Dynamic Generation method After the object is processed (fixed) * * @param delegate * @param proxy *&nbSP; @return */ public object bind (Object delegate) { this.delegate = delegate; return proxy.newproxyinstance ( this.delegate.getclass (). getClassLoader (), this.delegate .getclass (). Getinterfaces (), this); } /** *//** * each method in the object to be processed is sent by this method to the JVM call, i.e., The method to handle the object can only be called by this method * This method is dynamic, not manually called */ public object invoke (Object proxy, method method, object[] args )       &NBsp; throws throwable { object result = null; try { //logging before executing the original method logger.logging (Level.debuge, method.getname () + " Method start! ");       //JVM executes the original method through this statement (reflection mechanism) result = method.invoke (This.delegate, args); Log logs after //executes the original method logger.logging (Level.info, method.getname () + " Method end . "); } catch (exception e) { e.printstacktrace (); } //return method return value to caller return result; }} The logger class and level enumeration that appear in the above class are the same as the implementation of the previous example. There is no code to be posted here. Let's write a test class and try it out. The code is as follows:test.java package Sinosoft.dj.aop.proxyaop; public class test { public static void main (String[] args) { IHello hello = (Ihello) New dynaproxyhello (). Bind (New hello ()); hello.saygoogbye ("Double j"); hello.sayhello ("Double j"); }}
The result of running the output is as follows:
Tue may 23:47:30 CST saygoogbye Method start!
Double J goodbye!
2010-5-11 23:47:30 saygoogbye Method end.
Tue may 23:47:30 CST SayHello Method start!
Hello Double J
2010-5-11 23:47:30 sayHello Method end.
from the above example we see. As long as you are programming with interface-oriented, It is possible for any of your object's methods to be preceded by a logging operation. He (Dynapoxyhello) automatically goes to the agent to execute each method in the Proxied object (Hello), A Java.lang.reflect.InvocationHandler interface will decouple our proxy object from the object being proxied. But we found another problem, This Dynapoxyhello object can only be added to the logging operation before and after the method. Can we decouple the Dynapoxyhello object from the Log Manipulation object (Logger)? The
result is positive. Let's analyze our needs.
We want to add the log operation code (or code of other operations) before or after the method of the Proxied object,
then we can abstract an interface that has only two methods, one that executes before the proxy object executes the method, which we named Start, The second method is the one that executes after the proxy object executes the method, which we named end. The interface is defined as follows:
package sinosoft.dj.aop.proxyaop; import java.lang.reflect.method; public interface ioperation { /** *//** * How to do before you do * @param method */ void start (Method method); /** *// Actions after the ** * method is executed * @param method */ void end (Method method);} Let's write a class that implements the above interface. We take him as a real operator, as below is a class of log operators: Loggeroperation.javapackage sinosoft.dj.aop.proxyaop;import java.lang.reflect.method;public class loggeroperation implements ioperation { public void end (Method method) { logger.logging (Level.debuge, method. GetName () + " METHOD END ."); } public void start (Method method) { logger.logging (Level.info, method.getname () + " Method start! ");    &NBSP}} Then we'll change the code in the proxy object Dynaproxyhello. The following: package sinosoft.dj.aop.proxyaop; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.Proxy; public class DynaProxyHello implements invocationhandler { /** *//** * Operators */ private Object proxy; /** *//** * object to be processed (that is, the object we want to add business logic to before and after the method, such as Hello in the example) */ private object delegate; /** *//** * objects that are processed by the dynamic generation method (fixed) * * @param delegate * @param proxy * @return */ public object bind (object delegate,object Proxy) { this.proxy = proxy; this.delegate = Delegate; return proxy.newproxyinstance ( this.delegate.getclass (). getClassLoader (), this.delegate .getclass (). Getinterfaces (), this); } /** *//** * each method in the object to be processed is sent by this method to the JVM call, i.e., The method to handle the object can only be called by this method * This method is dynamic, not manually called */ public object invoke (object proxy, method method, object[] args) throws Throwable { object result = null; try { // Reflection gets an instance of the operator class clazz = this.proxy.getclass (); // Reflection gets operator's Start method method start = clazz.getdeclaredmethod ("Start", new class[] { method.class }); //reflection executes the Start method start.invoke ( this.proxy, new object[] { method }); //execute the original method to process the object Result = method.invoke (This.delegate, args);// reflection Gets the operator's End method Method end = clazz.getdeclaredmethod ("End", new class[] { method.class });// Reflection Execute End Method end.invoke (this.proxy, new object[] { method }); } catch (Exception e) { e.printstacktrace (); } return result; } and then we change the code in the Test.java. Test it: package sinosoft.dj.aop.proxyaop;public class test { public static void main (String[] args) { IHello hello = (Ihello) New dynaproxyhello (). Bind (New hello (), New loggeroperation ()); hello.saygoogbye ("double j"); hello.sayhello ("Double j "); }}
The result is still the same.
If you want to add log records before each method, do not add logging to the method. You change the Loggeroperation class to the following:
Package SINOSOFT.DJ.AOP.PROXYAOP;
Import Java.lang.reflect.Method;
public class Loggeroperation implements IOperation {
public void End (method method) {
Logger.logging (Level.debuge, Method.getname () + "method end.");
}
public void Start (method method) {
Logger.logging (Level.info, Method.getname () + "method start!");
}
}
Run it. You will find that no log is logged after each method. In this way, we can decouple the agent and the operator!
Let's leave a question for everyone, if we don't want all methods to be logged, how should we go about decoupling?
My idea is to add an if () to the public object invoke (object proxy, Method method, object[] args) method in the proxy object, to judge the names of the methods passed in. The condition of the judgment exists in the XML. So we can configure the file to be decoupled. If interested friends can put the operator, the agent is configured through the configuration file, then you can write a simple SPRINGAOP framework.
Reflection implements AOP Dynamic Proxy mode (Spring AOP implementation principle)