- 1. Agent mode
- 2. Bytecode and proxy mode
- 3. Static proxy
- 3.1 AspectJ static proxy
- 3.2 JDK static agent
- 4. Dynamic agent
- 4.1 dynamic agent idea
- 4.1 JDK dynamic agent (through interface)
- 4.2 CGLIB dynamic proxy (through inheritance)
- 5.Spring AOP
- 5.1 concept
- 5.2 XML based
- 5.3 annotation based
- 6. Summary
This article is going to talk about the proxy mechanism of Java to the AOP of Spring.
1. Agent mode
Agency mode is a very common design mode. When the word agent is taken apart, it means accepting on behalf of the client. Obviously, it involves three roles: the client requesting the agent, the agent providing the agent, and the customer who wants to actually contact the client through the agent.
For example, a very common example in life is that all stars have their own agent to do all kinds of things for themselves. In this scenario, the star itself is the client and the agent is the agent. The star entrusts the time arrangement right of arranging performances and attending meetings to the agent. In this way, when all businesses as customers want to invite stars to speak for them, You can only do it through an agent.
In this way, the stars themselves don't have to expose their identity, and the economic man can also tell the business stars in the communication what food to eat and what car to make when attending the event, saving the stars from worrying about these trivial things. On the other hand, being a broker can also provide services to multiple stars. In this way, businesses can only contact one broker and contact different stars to find a suitable candidate for their own company.
Through the above example, the advantages of agent mode are obvious:
*Advantage 1 *: you can hide the implementation of delegate classes;
*Advantage 2 *: it can realize the decoupling between the customer and the delegate class, and can do some additional processing without modifying the delegate class code.
2. Bytecode and proxy mode
Java programmers should know that Java compiles. Java source files into. Class bytecode files through the java compiler. This. Class file is a binary file that contains machine codes that can only be recognized by the JVM virtual machine. The JVM virtual machine reads the bytecode file, takes out the binary data, loads it into memory, parses the information in the. Class file, and generates the corresponding class object, Then, the class object creates a specific instance of the class to call and realize specific functions.
The above figure illustrates the process of loading bytecode in Java, but the strength of Java is that it can not only load the bytecode generated during compilation, but also generate corresponding binary data in the run-time system according to the format and structure of the. Class file organized by the Java compilation system, and then load and convert the binary data into the corresponding class, This completes the ability to dynamically create a class in the code, as shown in the following figure.
The following is an example of dynamically generating classes, which is implemented through javassist. Javassist is an open-source class library for analyzing, editing and creating Java bytecode. We can use Javasisst tool to dynamically create bytecode and load classes at runtime, as shown in the following code:
public class JavassistDemo { public static void main(String[] args) { makeNewClass(); } public static Class<?> makeNewClass() { try { // Get ClassPool ClassPool pool = ClassPool.getDefault(); // Create Student class CtClass ctClass = pool.makeClass("com.fufu.aop.Student"); // Create Student class member variable name CtField name = new CtField(pool.get("java.lang.String"), "name", ctClass); // Set name to private name.setModifiers(Modifier.PRIVATE); // Write name to class ctClass.addField(name, CtField.Initializer.constant("")); //Write class file //Add a set method with the name "setName" ctClass.addMethod(CtNewMethod.setter("setName", name)); //Add a get method with the name getname ctClass.addMethod(CtNewMethod.getter("getName", name)); // Add a parameterless construct CtConstructor cons = new CtConstructor(new CtClass[] {}, ctClass); cons.setBody(""); //Equivalent to public sclass() ctClass.addConstructor(cons); // Add a structure with parameters cons = new CtConstructor(new CtClass[] , ctClass); cons.setBody("{$0.name = $1;}"); //The first incoming parameter is $1, and the second incoming parameter is $2, which is equivalent to public Sclass(String s) ctClass.addConstructor(cons); //Reflection calls the newly created class Class<?> aClass = ctClass .toClass(); Object student = aClass.newInstance(); Method getter = null; getter = student.getClass().getMethod("getName"); System.out.println(getter.invoke(student)); } catch (Exception e) { e.printStackTrace(); } return null; } }
The two methods of static and dynamic bytecode loading are introduced to introduce the following two proxy methods. The proxy mechanism is divided into static proxy and dynamic proxy according to the creation time of the proxy class:
*Static proxy *: the proxy class is generated in the compilation stage and already exists before the program runs. This proxy method is called static proxy. In this case, the proxy class is usually defined in Java code.
*Dynamic proxy *: the proxy class is created when the program runs, that is, in this case, the proxy class is not defined in the Java code, but dynamically generated at run time according to our "instructions" in the Java code.
At present, static agents mainly include AspectJ static agent and JDK static agent technology, while dynamic agents include JDK dynamic agent and Cglib dynamic agent technology. Spring Aop integrates and uses JDK dynamic agent and Cglib dynamic agent technologies. Next, we will introduce all concepts step by step with examples.
3. Static proxy
3.1 AspectJ static proxy
For AspectJ, we will only have a simple understanding to lay a foundation for subsequent understanding. Now we only need to know the following definition:
AspectJ is an aspect oriented framework implemented in Java, which extends the Java language. AspectJ has a custom syntax, so it has a special compiler to generate Class files that comply with the Java byte encoding specification.
Note the description of "special compiler" in the above definition. It can be seen that AspectJ is a typical static proxy technology, because proxy classes are generated during compilation, and using AspectJ must also specify a specific compiler. Next, we use AspectJ to implement the star and broker model on the top.
First, introduce AspectJ dependency into maven project:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.9</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>1.8.9</version> </dependency>
Then change javac compiler to acj compiler in idea to support AspectJ syntax:
The star's performance is abstracted into a ShowService interface, including the functions of singing and dancing
public interface ShowService { // Singing performance void sing(String songName); // Dance performance void dance(); }
The star class implements the ShowService interface:
package com.fufu.aop; public class Star implements ShowService{ private String name; @Override public void sing(String songName) { System.out.println(this.name + " sing a song: " + songName); } @Override public void dance() { System.out.println(this.name + "dance"); } public Star(String name) { this.name = name; } public Star() { } public static void main(String[] args) { Star star = new Star("Eminem"); star.sing("Mockingbird"); } }
Implement a proxy AgentAspectJ with AspectJ syntax:
package com.fufu.aop; public aspect AgentAspectJ { /** * Define tangent point */ pointcut sleepPointCut():call(* Star.sing(..)); /** * Define tangent point */ pointcut eatPointCut():call(* Star.eat(..)); /** * Define pre notification * * before(Parameters): join point function{ * Function body * } */ before():sleepPointCut(){ getMoney(); } /** * Define post notification * after(Parameters): join point function{ * Function body * } */ after():sleepPointCut(){ writeReceipt(); } private void getMoney() { System.out.println("get money"); } private void writeReceipt() { System.out.println("write receipt"); } }
Create a Star and run the method:
public static void main(String[] args) { Star star = new Star("Eminem"); star.sing("Mockingbird"); }
Output:
get money Eminem sing a song: Mockingbird write receipt
You can see that the pre notification and post notification defined in AgentAspectJ are output before and after the sing() method of Star. Therefore, during compilation, AspectJ generates an enhanced Star class according to the code defined in AgentAspectJ code. When we actually call it, we will realize the function of agent class.
We don't delve into the specific AspectJ syntax. We just need to know that pointcut is the entry point to define the proxy. Here, two pointcuts are defined, namely, the sing() method and dance() method of the Star class. before() and after() can define the additional operations required before and after the cut-in point.
To sum up, AspctJ uses a specific compiler and syntax to enhance the compilation time of classes and realize the static agent technology. Let's look at the JDK static agent.
3.2 JDK static agent
Generally, JDK static proxy is more of a design pattern. The proxy class and delegate class of JDK static proxy will implement the same interface or derive from the same parent class. The basic class diagram of the proxy pattern is as follows:
We then write the above examples of stars and brokers into code to implement a JDK static proxy mode.
The broker also implements the ShowService interface, holds a star object to provide real performances, and adds the things that the broker needs to deal with before and after various performances, such as collecting money, issuing invoices, etc
package com.fufu.aop; /** * agent */ public class Agent implements ShowService{ private Star star; public Agent(Star star) { this.star = star; } private void getMoney() { System.out.println("get money"); } private void writeReceipt() { System.out.println("write receipt"); } @Override public void sing(String songName) { // Collect money before singing getMoney(); // The star began to sing star.sing(songName); // Invoice after singing writeReceipt(); } @Override public void dance() { // Collect money before the dance begins getMoney(); // The star began to dance star.dance(); // Invoice after dancing writeReceipt(); } }
Invite stars to perform through agents:
public static void main(String[] args) { Agent agent = new Agent(new Star("Eminem")); agent.sing("Mockingbird"); }
Output:
get money Eminem sing a song: Mockingbird write receipt
The above is a typical example of static agent, which is very simple but can also explain the problem. Let's take a look at the advantages and disadvantages of static agent:
Advantages: business classes can only focus on their own logic and can be reused. Common logic processing can be added through proxy classes.
Disadvantages:
- An interface of proxy object only serves one type of object. If there are many classes to proxy, it is bound to proxy for each class. Static proxy is not competent when the program scale is a little large.
- If a method is added to the interface, all proxy classes need to implement this method in addition to all implementation classes. It increases the complexity of code maintenance
In addition, if you want to use the proxy mode according to the above method, the real role (delegate class) must exist in advance and be used as the internal attribute of the proxy object. However, in actual use, a real role must correspond to a proxy role. If used heavily, it will lead to the rapid expansion of the class; In addition, if the real role (delegate class) is not known in advance, how to use the proxy? These problems can be solved through Java's dynamic proxy class.
4. Dynamic agent
The source code of the dynamic proxy class is dynamically generated by the JVM according to reflection and other mechanisms during the program running, so there is no bytecode file of the proxy class. The relationship between proxy class and delegate class is determined when the program runs.
4.1 dynamic agent idea
To understand the idea of implementing the dynamic agent class, we also need to start with the problems of the static agent, because after all, the dynamic agent appears to solve the problems of the static agent. Looking back, we can see the problems of the static agent:
- Class inflation: each proxy class is a concrete class that needs to be written by programmers, which is unrealistic.
- Method level proxy: both the proxy class and the implementation class implement the same interface, resulting in that each method of the proxy class needs to be proxy. If you have several methods, I will have several. The coding is complex and cannot be maintained.
How dynamic agents solve:
- The first question is easy to answer. Similar to the example of using Javasisst, dynamically create the bytecode of the proxy class in the code, and then obtain the proxy class object.
- The second problem is to lead to invocationhandler. In order to construct a universal and simple proxy class, you can hand over all the actions that trigger the real role to a trigger manager, which can uniformly manage the trigger. This manager is the invocationhandler. In static proxy, the proxy class only calls the corresponding implementation method by adding specific logic before and after, sleep() corresponds to sleep(), run() corresponds to run(), while in Java, method Method is also an object, so the dynamic proxy class can give all calls to Method as InvocationHandler objects. Invocationhandler calls different methods of specific implementation classes according to what method. Invocationhandler is responsible for adding proxy logic and calling methods of specific implementation classes.
In other words, the dynamic proxy class still implements the same interface as the implementation class, but the dynamic proxy class is dynamically generated according to the interface implemented by the implementation class, which does not need the user's attention. In addition, all method calls of the dynamic proxy class are uniformly handed over to InvocationHandler, and each method of each interface of the implementation class is ignored.
In this pattern, it is very important that Proxy and RealSubject should implement the same function. (the function I'm talking about here can be understood as the public method of a class)
In object-oriented programming, if we want to agree that Proxy and RealSubject can achieve the same function, there are two ways:
a. A more intuitive way is to define a function interface, and then let Proxy and RealSubject implement this interface. b. There is also a more obscure way, that is, through inheritance. Because if the Proxy inherits from RealSubject, the Proxy has the function of RealSubject. The Proxy can also implement polymorphism by rewriting the methods in RealSubject.
The mechanism of creating dynamic agent provided in JDK is designed with the idea of a, while cglib is designed with the idea of b.
4.1 JDK dynamic agent (through interface)
Let's take a specific example, or the model of the above stars and brokers as an example, so as to facilitate comparison and understanding:
Abstract the star's performance into a ShowService interface, including the functions of singing and dancing:
package com.fufu.aop; public interface ShowService { // Singing performance void sing(String songName); // Dance performance void dance(); }
The star class implements the ShowService interface:
package com.fufu.aop; /** * Star class */ public class Star implements ShowService{ private String name; @Override public void sing(String songName) { System.out.println(this.name + " sing a song: " + songName); } @Override public void dance() { System.out.println(this.name + "dance"); } public Star(String name) { this.name = name; } public Star() { } }
Implement the request processor of a proxy class to handle calls to all methods of a specific class:
package com.fufu.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class InvocationHandlerImpl implements InvocationHandler { ShowService target; public InvocationHandlerImpl(ShowService target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // Collect money before the show begins getMoney(); // The star began to sing Object invoke = method.invoke(target, args); // Invoice after the show writeReceipt(); return invoke; } private void getMoney() { System.out.println("get money"); } private void writeReceipt() { System.out.println("write receipt"); } }
Implement a dynamic proxy through JDK dynamic proxy mechanism:
package com.fufu.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class JDKProxyDemo { public static void main(String[] args) { // 1. Create a specific class to be represented Star star = new Star("Eminem"); // 2. Get the corresponding ClassLoader ClassLoader classLoader = star.getClass().getClassLoader(); // 3. Obtain all interfaces implemented by the proxy object Class[] interfaces = star.getClass().getInterfaces(); // 4. Set the request processor to handle all method calls InvocationHandler invocationHandler = new InvocationHandlerImpl(star); /** * 5.According to the information provided above, in the process of creating a proxy object, * a.JDK Bytecode equivalent to. class file will be dynamically created in memory according to the passed in parameter information * b.Then it is converted into the corresponding class according to the corresponding bytecode, * c.Then call newInstance() to create an instance. */ Object o = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); ShowService showService = (ShowService)o; showService.sing("Mockingbird"); } }
Let's start with the creation of agents and see what JDK's dynamic agents do:
Object o = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
- Proxy.newProxyInstance() gets the list of all interfaces of Star class (second parameter: interfaces)
- Determine the class name of the proxy class to be generated. The default is: com.sun.proxy.$ProxyXXXX
- Dynamically create the bytecode of the Proxy class in the code according to the interface information to be implemented;
- Convert the corresponding bytecode into the corresponding class object;
- Create an InvocationHandler instance handler to handle all Proxy method calls
- The class object of Proxy takes the created handler object as the parameter (the third parameter: invocationHandler) and instantiates a Proxy object
For InvocationHandler, we need to implement the following invoke methods:
public Object invoke(Object proxy, Method method, Object[] args)
When calling each method in the proxy object, the invoke method of InvocationHandler is directly called inside the code, and the invoke method distinguishes what method it is according to the method parameter passed to it by the proxy class.
It can be seen that the object generated by the Proxy.newProxyInstance() method also implements the ShowService interface, so it can be forcibly converted to ShowService in the code, which achieves the same effect as the static proxy. We can use the following code to save the bytecode of the generated proxy class to disk, and then decompile to see the structure of the dynamic proxy class generated by JDK.
package com.fufu.aop; import sun.misc.ProxyGenerator; import java.io.FileOutputStream; import java.io.IOException; public class ProxyUtils { public static void main(String[] args) { Star star = new Star("Eminem"); generateClassFile(star.getClass(), "StarProxy"); } public static void generateClassFile(Class clazz, String proxyName) { //Generate bytecode according to the class information and the provided proxy class name byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces()); String paths = clazz.getResource(".").getPath(); System.out.println(paths); FileOutputStream out = null; try { //Keep to hard disk out = new FileOutputStream(paths + proxyName + ".class"); out.write(classFile); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } }
Decompile the StarPoxy.class file to get:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // import com.fufu.aop.ShowService; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; // The dynamic proxy class StarPoxy implements the ShowService interface public final class StarProxy extends Proxy implements ShowService { // Load all methods defined in the interface private static Method m1; private static Method m3; private static Method m4; private static Method m2; private static Method m0; //The constructor accesses the InvocationHandler, that is, it holds the InvocationHandler object h public StarProxy(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[])).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } // The automatically generated sing() method actually calls the invoke method of the InvocationHandler object h, and the incoming m3 parameter object represents the sing() method public final void sing(String var1) throws { try { super.h.invoke(this, m3, new Object[]); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } //Similarly, generate dance() method public final void dance() throws { try { super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } // Load all methods defined in the interface static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]); m3 = Class.forName("com.fufu.aop.ShowService").getMethod("sing", new Class[]); m4 = Class.forName("com.fufu.aop.ShowService").getMethod("dance", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
It can be seen from the decompiled code above that the dynamic proxy class generated by JDK implements the same interface as the specific class and holds the InvocationHandler object (the InvocationHandler object also holds the specific class). Calling the method in the dynamic proxy class will trigger the invoke() method passed in to the InvocationHandler. The method parameter is used to distinguish what specific method is called, See the following figure for details:
4.2 CGLIB dynamic proxy (through inheritance)
The mechanism for generating dynamic proxy classes provided in JDK has a distinctive feature:
A class must have an implemented interface, and the generated proxy class can only proxy the methods defined by a class interface. For example, if Star in the above example implements the method play() in addition to the method inherited from ShowService interface, there will be no such method in the generated dynamic proxy class! In a more extreme case, if a class does not implement an interface, the class cannot generate a dynamic proxy with JDK!
Fortunately, we have cglib, "cglib (Code Generation Library) is a powerful, high-performance and high-quality code generation class library, which can extend Java classes and implement Java interfaces at runtime."
cglib creates a dynamic proxy class of class A in the following mode:
- Find all non final public type method definitions on A;
- Converting the definitions of these methods into bytecode;
- Convert the bytecode into the class object of the corresponding agent;
- Implement the MethodInterceptor interface to process requests for all methods on the proxy class (this interface has the same function and role as the JDK dynamic proxy InvocationHandler)
With the above example of JDK dynamic proxy, cglib is easy to understand. Let's illustrate with an example. ShowService interface and Star class are unchanged before reuse:
Implement the MethodInterceptor interface:
package com.fufu.aop; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class MethodInterceptorImpl implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { // Collect money before the show begins getMoney(); // The star began to sing Object invoke = methodProxy.invokeSuper(o, objects); // Invoice after the show writeReceipt(); return invoke; } private void getMoney() { System.out.println("get money"); } private void writeReceipt() { System.out.println("write receipt"); } }
To create a dynamic proxy:
package com.fufu.aop; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; public class CglibProxyDemo { public static void main(String[] args) { Star star = new Star("Eminem"); MethodInterceptor methodInterceptor = new MethodInterceptorImpl(); //Enhancer in cglib to create dynamic proxy Enhancer enhancer = new Enhancer(); //Set the class to create the dynamic proxy enhancer.setSuperclass(star.getClass()); // Setting callback is equivalent to calling callback for all methods on the proxy class, and callback needs to implement intercept() method to intercept enhancer.setCallback(methodInterceptor); ShowService showService = (ShowService) enhancer.create(); showService.sing("Mockingbird"); } }
It can be seen from the above examples that Cglib implements dynamic proxy through inheritance. Specific classes do not need to implement specific interfaces, and proxy classes can call non interface methods of specific classes, which is more flexible.
5.Spring AOP
5.1 concept
The specific concepts of AOP are no longer mentioned. Search a lot on the Internet. This article mainly introduces the proxy technology used in the lower layer of Spring AOP, because many people use copy configuration when using Spring AOP. They are not clear about these technical concepts introduced above.
Spring AOP adopts dynamic proxy, which enhances business methods during operation, so it will not generate new classes. For dynamic proxy technology, spring AOP provides support for JDK dynamic proxy and CGLib. However, when to use which proxy?
1. If the target object implements the interface, the dynamic proxy of JDK will be used to implement AOP by default
2. If the target object implements an interface, you can force the use of CGLIB to implement AOP
3. If the target object does not implement the interface, the CGLIB library must be used, and spring will automatically convert between JDK dynamic agent and CGLIB
At present, spring seems to have nothing to do with AspectJ. Why do @ AspectJ annotations appear in many projects that apply Spring AOP? Spring is a dynamic proxy for applications. Why is it still related to AspectJ? The reason is that when Spring AOP is configured based on annotations, it needs to rely on the standard annotations of AspectJ package, but it does not need additional compilation and AspectJ weaver, but not XML based configuration. Therefore, Spring AOP only reuses the annotations of AspectJ and has no other dependencies on AspectJ.
When Spring needs @ AspectJ annotation support, it needs to be configured in the Spring configuration file as follows:
<aop:aspectj-autoproxy/>
On the second point, the mandatory use of CGLIB can be realized through the following configuration in the Spring configuration file:
<aop:aspectj-autoproxy proxy-target-class="true"/>
The proxy target class attribute value determines whether an interface based or class based proxy is created. If the proxy target class attribute value is set to true, the class based proxy will work (cglib library is required). If the proxy target class attribute value is set to false or this attribute is omitted, the standard JDK interface based proxy.
Therefore, although Aspect Annotation is used, its compiler and Weaver are not used. The implementation principle is JDK dynamic proxy or Cglib, which generates proxy classes at runtime.
Having written so much, here are two more Spring AOP demo codes based on XML and annotations:
5.2 XML based
Section class:
package com.fufu.spring.aop; import org.springframework.stereotype.Component; /** * Spring AOP based on XML */ @Component public class AgentAdvisorXML { public void getMoney() { System.out.println("get money"); } public void writeReceipt() { System.out.println("write receipt"); } }
Profile:
<?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:context="http://www.springframework.org/schema/context" 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"> <bean id="star"> <property name="name" value="Eminem"/> </bean> <bean id="agentAdvisorXML"/> <!--Spring be based on Xml Section of--> <aop:config> <!-- Define tangent function --> <aop:pointcut id="singPointCut" expression="execution(* com.fufu.proxy.Star.sing(..))"/> <!-- Define section order Define priority,The smaller the value, the higher the priority--> <aop:aspect ref="agentAdvisorXML" order="0"> <!--Before advice --> <aop:before method="getMoney" pointcut-ref="singPointCut"/> <!--Post notification--> <aop:after method="writeReceipt" pointcut-ref="singPointCut"/> </aop:aspect> </aop:config> </beans>
Test class:
package com.fufu.spring.aop; import com.fufu.proxy.ShowService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop.xml"); Object star = applicationContext.getBean("star"); ShowService showService = (ShowService)star; showService.sing("Mockingbird"); } }
5.3 annotation based
Section class:
package com.fufu.spring.aop; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * Annotation based Spring AOP */ @Aspect @Component public class AgentAdvisor { @Before(value = "execution(* com.fufu.proxy.ShowService.sing(..))") public void getMoney() { System.out.println("get money"); } @After(value = "execution(* com.fufu.proxy.ShowService.sing(..))") public void writeReceipt() { System.out.println("write receipt"); } }
Profile:
<?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:context="http://www.springframework.org/schema/context" 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"> <context:component-scan base-package="com.fufu.proxy, com.fufu.spring.aop"/> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
Test class:
package com.fufu.spring.aop; import com.fufu.proxy.ShowService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop-annotation.xml"); Object star = applicationContext.getBean("star"); ShowService showService = (ShowService)star; showService.sing("Mockingbird"); } }
6. Summary
Although the above contents are relatively simple and easy to understand, you can have a comprehensive understanding of Java proxy mechanism and Spring AOP. If there are errors, please correct them.