What is AOP
AOP (Aspect-Oriented Programming, aspect-oriented programming) can be said to be a supplement and improvement of OOP (Object-Oriented Programming). OOP introduces concepts such as encapsulation, inheritance, and polymorphism to establish an object hierarchy to simulate a collection of public behaviors. When we need to introduce public behavior to scattered objects, OOP seems powerless. That is, OOP allows you to define relationships from top to bottom, but is not suitable for defining relationships from left to right. For example, logging function. Log code is often scattered horizontally across all object levels without any relation to the core functionality of the object to which it is scattered. The same is true for other types of code, such as security, exception handling, and transparency. This kind of irrelevant code scattered everywhere is called cross-cutting code. In OOP design, it causes a lot of code duplication, which is not conducive to the reuse of each module.
Introduction
The Java design pattern I wrote some time ago - the proxy pattern. Recently, when I was looking at Spring Aop, I felt that there should be close connections in the proxy pattern, so I decided to understand the implementation principle of Spring Aop.
Speaking of AOP, we have to talk about OOP. The concepts of encapsulation, inheritance and polymorphism are introduced in OOP to establish an object hierarchy to simulate a collection of public behaviors. However, if we need to introduce common parts for some objects, OOP will introduce a lot of duplicate code. For example: logging function.
AOP technology uses a technique called "crosscutting" to dissect the inside of the encapsulated object and encapsulate the common behaviors that affect multiple classes into a reusable module, which can reduce the system's duplication of code, reduce the coupling between modules, and facilitate future operability and maintenance. AOP divides the software system into two parts: core concern and cross-cut attention. The main process of business processing is the core focus, and the part that has little to do with it is the cross-sectional focus. One characteristic of cross-cutting concerns is that they often occur in multiple core concerns, and are basically similar everywhere. For example, permission authentication, logging, and transaction processing.
Implementation principle
When I was learning the proxy mode, I learned that the proxy mode is divided into dynamic proxy and static proxy. Now we will first implement our own AOP framework based on the proxy model, and then study the implementation principles of Spring's AOP.
First, it is implemented with a static proxy. The key to static proxy is to implement a common interface between the proxy object and the target object, and the proxy object holds a reference to the target object.
Public interface code:
public interface IHello {/*** Business method* @param str*/void sayHello(String str);} Target class code: public class Hello implements IHello{@Overridepublic void sayHello(String str) {System.out.println("hello "+str);}} For proxy class code, we add logging function to it, and execute specific methods before and after the method starts. Isn’t it particularly similar to AOP?
public class ProxyHello implements IHello{ private IHello hello; public ProxyHello(IHello hello) {super(); this.hello = hello;}@Overridepublic void saysHello(String str) {Logger.start();//Add specific method hello.sayHello(str);Logger.end();}} Log class code:
public class Logger {public static void start(){System.out.println(new Date()+ " say hello start...");}public static void end(){System.out.println(new Date()+ " say hello end");}} Test code:
public class Test {public static void main(String[] args) {IHello hello = new ProxyHello(new Hello());//If we need logging function, use proxy class //IHello hello = new Hello();//If we do not need logging function, use target class hello.sayHello("tomorrow"); }}In this way, we implement the simplest AOP, but there will be a problem: if we have many classes like Hello, then should we write many classes like HelloProxy? In fact, it is also a very troublesome thing. After jdk1.3, jdk provides us with an API java.lang.reflect.InvocationHandler class. This class allows us to dynamically do something for some methods when the JVM calls the methods of a certain class. Let’s implement the implementation of dynamic proxy.
Dynamic proxy implementation mainly implements InvocationHandler, and injects the target object into the proxy object, using the reflection mechanism to execute the target object method.
The interface implementation is the same as the static proxy, the proxy class code:
public class DynaProxyHello implements InvocationHandler{private Object target;//target object/*** Instantiate the target object through reflection* @param object* @return*/public Object bind(Object object){this.target = object;return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {Object result = null;Logger.start();//Add additional methods//Methods to run target objects through reflection mechanism result = method.invoke(this.target, args);Logger.end();return result;}} Test class code:
public class DynaTest {public static void main(String[] args) {IHello hello = (IHello) new DynaProxyHello().bind(new Hello());//If we need logging function, use proxy class //IHello hello = new Hello();//If we do not need logging function, use target class hello.sayHello("tomorrow");}} After reading the above code, there may be a problem compared to Spring AOP. The log class can only be printed before and after the method, but AOP should be able to execute when the conditions are met. Can all the DynaPoxyHello object and the log operation object (Logger) be decoupled?
Looking at the following code implementation, it will decouple the DynaPoxyHello object and the log operation object (Logger):
We need to add log operation code (or other operation code) before or after the method of the proxy object. Then, we can abstract an interface, which has only two methods: one is the method executed before the proxy object wants to execute the method. We named it start, and the second method is the method executed after the proxy object executes the method, and we named it end.
Logger's interface:
public interface ILogger {void start(Method method);void end(Method method);} Logger interface implementation:
public class DLogger implements ILogger{@Overridepublic void start(Method method) {System.out.println(new Date()+ method.getName() + " say hello start...");}@Overridepublic void end(Method method) {System.out.println(new Date()+ method.getName() + " say hello end");}} Dynamic proxy class:
public class DynaProxyHello implements InvocationHandler{//Call object private Object proxy;//Target object private Object target;public Object bind(Object target,Object proxy){this.target=target;this.proxy=proxy;return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {Object result = null;//Reflection gets the operator's instance Class clazz = this.proxy.getClass();//Reflection gets the operator's Start method Method start = clazz.getDeclaredMethod("start", new Class[]{Method.class});//Reflection executes the start method start.invoke(this.proxy, new Object[]{this.proxy.getClass()});//Executes the original method to process the object method.invoke(this.target, args);//Reflection obtains the operator's end method Method end = clazz.getDeclaredMethod("end", new Class[]{Method.class});//Reflection executes the end method end.invoke(this.proxy, new Object[]{method});return result;}} Test code:
public class DynaTest {public static void main(String[] args) {IHello hello = (IHello) new DynaProxyHello().bind(new Hello(), new DLogger());//If we need logging function, use proxy class //IHello hello = new Hello();//If we do not need logging function, use target class hello.sayHello("tomorrow");}} Through the above example, we can find that through dynamic proxying and transmission technology, the function of AOP has been basically implemented. If we only need to print the log before the method is executed, we can not implement the end() method, so that we can control the printing timing. If we want the specified method to print the log, we only need to add a judgment on the method name to the invoke() method. The method name can be written in the XML file, so that we can decouple it with the configuration file, so that we implement a simple spring aop framework.
The above content is the Spring AOP implementation principle introduced to you by the editor. I hope it will be helpful to you!