In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article will explain in detail how to understand the implementation mechanism of Spring AOP. The content of the article is of high quality, so the editor shares it for you as a reference. I hope you will have some understanding of the relevant knowledge after reading this article.
AOP (Aspect Orient Programming), commonly known as aspect-oriented programming, as a supplement to object-oriented, is used to deal with crosscutting concerns distributed in various modules in the system, such as transaction management, logging, caching and so on. The key to the implementation of AOP lies in the AOP proxy automatically created by the AOP framework. AOP proxy is mainly divided into static proxy and dynamic proxy. The static proxy is represented by AspectJ; and the dynamic proxy is represented by Spring AOP. Static proxy is the compile-time implementation, dynamic proxy is the run-time implementation, it is conceivable that the former has better performance.
This paper mainly introduces two proxy implementation mechanisms of Spring AOP, JDK dynamic proxy and CGLIB dynamic proxy.
The static proxy generates the AOP proxy class at the compilation stage, that is, the generated bytecode is woven into the enhanced AOP object; the dynamic proxy does not modify the bytecode, but temporarily generates an AOP object in memory, which contains all the methods of the target object, and enhances it at a specific pointcut, and calls back the methods of the original object.
There are two main ways of dynamic agent in Spring AOP, JDK dynamic agent and CGLIB dynamic agent. The JDK dynamic proxy receives the proxied class through reflection and requires that the proxied class must implement an interface. The core of JDK dynamic agent is the InvocationHandler interface and Proxy class.
If the target class does not implement the interface, Spring AOP chooses to use CGLIB to dynamically proxy the target class. CGLIB (Code Generation Library), a code-generated class library, can dynamically generate subclasses of a class at run time. Note that CGLIB is a dynamic proxy done by inheritance, so if a class is marked as final, it cannot use CGLIB as a dynamic proxy, and methods such as private cannot be used as aspects.
We use examples to study the specific implementation of AOP.
Use Spring AOP directly
First define the interfaces and implementations that need to be cut in. For simplicity, define a Speakable interface and a concrete implementation class, with only two methods sayHi () and sayBye ().
Public interface Speakable {void sayHi (); void sayBye ();} @ Service public class PersonSpring implements Speakable {@ Override public void sayHi () {try {Thread.currentThread () .sleep (30);} catch (Exception e) {throw new RuntimeException (e);} System.out.println ("hibernation!");} @ Override public void sayBye () {try {Thread.currentThread () .sleep (10) } catch (Exception e) {throw new RuntimeException (e);} System.out.println ("Byebirds!");}}
Next we want to implement a function that records the execution time of sayHi () and sayBye ().
Define a MethodMonitor class to record the Method execution time
Public class MethodMonitor {private long start; private String method; public MethodMonitor (String method) {this.method = method; System.out.println ("begin monitor.."); this.start = System.currentTimeMillis ();} public void log () {long elapsedTime = System.currentTimeMillis ()-start; System.out.println ("end monitor.."); System.out.println ("Method:" + method + ", execution time:" + elapsedTime + "milliseconds.");}}
It's not enough to have this class. I hope it's easier to have a static method, like this.
MonitorSession.begin (); doWork (); MonitorSession.end ()
Just do it. Define a MonitorSession.
Public class MonitorSession {private static ThreadLocal monitorThreadLocal = new ThreadLocal (); public static void begin (String method) {MethodMonitor logger = new MethodMonitor (method); monitorThreadLocal.set (logger);} public static void end () {MethodMonitor logger = monitorThreadLocal.get (); logger.log ();}}
Everything is ready, and then we just need to do the aspect coding.
@ Aspect @ Component public class MonitorAdvice {@ Pointcut ("execution (* com.deanwangpro.aop.service.Speakable.* (..)") Public void pointcut () {} @ Around ("pointcut ()") public void around (ProceedingJoinPoint pjp) throws Throwable {MonitorSession.begin (pjp.getSignature (). GetName ()); pjp.proceed (); MonitorSession.end ();}}
How to use it? I used spring boot to write a startup function.
@ SpringBootApplication public class Application {@ Autowired private Speakable personSpring; public static void main (String [] args) {SpringApplication.run (Application.class, args);} @ Bean public CommandLineRunner commandLineRunner (ApplicationContext ctx) {return args-> {/ / spring aop System.out.println ("* spring aop *"); personSpring.sayHi (); personSpring.sayBye (); System.exit (0);};}
Output after running:
Jdk dynamic proxy begin monitor..Hi!!end monitor..Method: sayHi, execution time: 32 milliseconds.begin monitor..Bye!!end monitor..Method: sayBye, execution time: 22 milliseconds.
JDK dynamic agent
In the example just now, the internal implementation mechanism is actually JDK dynamic proxy, because Person implements an interface.
In order not to conflict with * * examples, we define a Person to implement Speakable. This implementation does not have Spring Annotation, so it will not be hosted by Spring.
Public class PersonImpl implements Speakable {@ Override public void sayHi () {try {Thread.currentThread () .sleep (30);} catch (Exception e) {throw new RuntimeException (e);} System.out.println ("hippie!");} @ Override public void sayBye () {try {Thread.currentThread () .sleep (10);} catch (Exception e) {throw new RuntimeException (e) } System.out.println ("bindings!");}}
The big deal is that we need to implement a proxy using InvocationHandler to include the Person object. So the re-run time is actually the method that executes the agent, and then the agent executes the real method. So we were able to do something before and after the implementation of the real method. JDK dynamic proxy is implemented using reflection and looks directly at the code.
Public class DynamicProxy implements InvocationHandler {private Object target; public DynamicProxy (Object object) {this.target = object;} @ Override public Object invoke (Object arg0, Method arg1, Object [] arg2) throws Throwable {MonitorSession.begin (arg1.getName ()); Object obj = arg1.invoke (target, arg2); MonitorSession.end (); return obj } @ SuppressWarnings ("unchecked") public T getProxy () {return (T) Proxy.newProxyInstance (target.getClass () .getClassLoader (), target.getClass () .getInterfaces (), this);}}
You can get this proxy object through getProxy, and invoke is the specific execution method, and you can see that we have added Monitor before and after executing each real method.
I implemented a factory class to get the Person proxy object
Public class PersonProxyFactory {public static Speakable newJdkProxy () {/ / Agent PersonImpl DynamicProxy dynamicProxy = new DynamicProxy (new PersonImpl ()); Speakable proxy = dynamicProxy.getProxy (); return proxy;}}
Specific use
/ / jdk dynamic proxy System.out.println ("* jdk dynamic proxy *"); Speakable jdkProxy = PersonProxyFactory.newJdkProxy (); jdkProxy.sayHi (); jdkProxy.sayBye ()
Output result:
* jdk dynamic proxy * begin monitor.. Hi!! End monitor.. Method: sayHi, execution time: 32 milliseconds. Begin monitor.. Bye!! End monitor.. Method: sayBye, execution time: 22 milliseconds.
CGLib dynamic agent
Let's create a new Person without implementing any interfaces this time.
Public class Person {public void sayHi () {try {Thread.currentThread (). Sleep (30);} catch (Exception e) {throw new RuntimeException (e);} System.out.println ("hippie!");} public void sayBye () {try {Thread.currentThread (). Sleep (10);} catch (Exception e) {throw new RuntimeException (e);} System.out.println ("Byebread!");}}
If Spring recognizes that the class being proxied does not implement Interface, then CGLib is used to create a dynamic proxy, and the principle is actually a subclass of the proxied class.
Public class CGLibProxy implements MethodInterceptor {private static CGLibProxy instance = new CGLibProxy (); private CGLibProxy () {} public static CGLibProxy getInstance () {return instance;} private Enhancer enhancer = new Enhancer (); @ SuppressWarnings ("unchecked") public T getProxy (Class clazz) {enhancer.setSuperclass (clazz); enhancer.setCallback (this); return (T) enhancer.create () } @ Override public Object intercept (Object arg0, Method arg1, Object [] arg2, MethodProxy arg3) throws Throwable {MonitorSession.begin (arg1.getName ()); Object obj = arg3.invokeSuper (arg0, arg2); MonitorSession.end (); return obj;}}
Similarly, you can get this proxy object through getProxy. Intercept is the specific execution method, and you can see that we add Monitor before and after the execution of each real method.
Add a method to get the Person proxy class in the factory class
Public static Person newCglibProxy () {CGLibProxy cglibProxy = CGLibProxy.getInstance (); Person proxy = cglibProxy.getProxy (Person.class); return proxy;}
Specific use
/ / cglib dynamic proxy System.out.println ("* cglib proxy *"); Person cglibProxy = PersonProxyFactory.newCglibProxy (); cglibProxy.sayHi (); cglibProxy.sayBye ()
Output result:
Begin monitor..Hi!!end monitor..Method: sayHi, execution time: 53 milliseconds.begin monitor..Bye!!end monitor..Method: sayBye, execution time: 14 milliseconds.
Summary
Compared with JDK dynamic proxy and CGLib proxy, it is found that CGLib takes longer to create proxy object than JDK dynamic proxy in practical use.
Method: newJdkProxy, execution time: 5 milliseconds. Method: newCglibProxy, execution time: 18 milliseconds.
So CGLib is better suited to proxies for classes that don't need to be instantiated frequently.
In terms of the implementation efficiency of specific methods, the CGlib that does not pass the reflection is supposed to be faster, and then the test results are not the case, and the expert advice is needed.
JDKMethod: sayHi, execution time: 32 milliseconds.CGLibMethod: sayHi, execution time: 53 milliseconds. On how to understand the implementation mechanism of Spring AOP to share here, I hope that the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.