Technology Sharing

Detailed explanation of proxy: static proxy, dynamic proxy, SpringAOP implementation

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Agent introduction

Proxy means that an object A can have the same behavior as another object B by holding it. In order to open the protocol to the outside world, B often implements an interface, and A will also implement the interface. However, B is a "real" implementation class, while A is more "virtual". It borrows B's methods to implement the interface methods. Although A is a "pseudo-army", it can enhance B and do other things before and after calling B's methods. Spring AOP uses dynamic proxies to complete the dynamic "weaving" of code.

The benefits of using a proxy are more than that. If a project relies on an interface provided by another project, but the interface of the other project is unstable and the protocol is often changed, a proxy can be used. When the interface changes, only the proxy needs to be modified, and there is no need to modify the business code one by one. In this sense, we can do this for all external interfaces, so as to prevent external code from invading our code. This is called defensive programming. There may be many other applications of proxies.

In the above example, class A is hard-coded to hold B, which is a static proxy of B. If the object of A's proxy is uncertain, it is a dynamic proxy. There are currently two common implementations of dynamic proxy, jdk dynamic proxy and cglib dynamic proxy.

2. Static Proxy

Static proxy is a design pattern, a type of proxy pattern. In static proxy, the proxy class is defined before the program runs, and the relationship between the proxy class and the proxied class is determined during compilation. This means that the proxy class and the proxied class implement the same interface or inherit the same parent class. The proxy class holds an instance of the proxied class and calls the proxied class's methods in its own methods. At the same time, it can add some of its own operations before and after the call, such as logging, permission checking, transaction processing, etc.

Static proxy has three components: abstract interface, proxy class, and proxied class. The implementation example is as follows:

1) Define abstract interface

  1. public interface TargetInteface {
  2. void method1();
  3. void method2();
  4. int method3(Integer i);
  5. }

2) Define the proxy class

  1. public class TargetProxy implements TargetInteface {
  2. private Target target =new Target();
  3. @Override
  4. public void method1() {
  5. System.out.println("执行方法前...");
  6. target.method1();
  7. System.out.println("执行方法后...");
  8. }
  9. @Override
  10. public void method2() {
  11. System.out.println("执行方法前...");
  12. target.method2();
  13. System.out.println("执行方法后...");
  14. }
  15. @Override
  16. public int method3(Integer i) {
  17. System.out.println("执行方法前...");
  18. int method3 = target.method3(i);
  19. System.out.println("执行方法后...");
  20. return method3;
  21. }
  22. }

3) Define the proxy class

  1. public class Target implements TargetInteface {
  2. @Override
  3. public void method1() {
  4. System.out.println(" Target method1 running ...");
  5. }
  6. @Override
  7. public void method2() {
  8. System.out.println("Target method2 running ...");
  9. }
  10. @Override
  11. public int method3(Integer i) {
  12. System.out.println("Target method3 running ...");
  13. return i;
  14. }
  15. }

4) Define the client and view the execution results

  1. public class TargetUser {
  2. public static void main(String[] args) {
  3. TargetInteface target = new TargetProxy();
  4. target.method1();
  5. System.out.println("-----------------------------");
  6. target.method2();
  7. System.out.println("-----------------------------");
  8. System.out.println(target.method3(3));
  9. }
  10. }

Result output:

Before executing the method...
 Target method1 running ...
After executing the method...
-----------------------------
Before executing the method...
Target method2 running ...
After executing the method...
-----------------------------
Before executing the method...
Target  method3 running ...
After executing the method...
3

It is not difficult to see from the implementation of static proxy that the advantages of static proxy are simple implementation and easy to understand. But its disadvantages are also obvious, that is, every time you need to add proxy function to a new class, you need to manually create a new proxy class, which will lead to a sharp increase in the number of classes and the maintenance cost. At the same time, the degree of coupling between the proxy class and the proxied class is too high. When the method is added, deleted, or modified in the proxied class, the corresponding method must also be added, deleted, or modified in the proxy class, which increases the maintenance cost of the code. Another problem is that when the proxy object proxies the implementation classes of multiple target interfaces, different methods must appear in multiple implementation classes. Since the proxy object must implement the same interface as the target object (actually an inclusion relationship), it is necessary to write many methods, which is extremely easy to cause bloated and difficult to maintain code.

3. Dynamic Proxy

The core idea of ​​dynamic proxy is to indirectly access the original object through the proxy object without modifying the original object code, and perform additional operations before and after the access.

The implementation principle of dynamic proxy is mainly based on Java's reflection mechanism. When using dynamic proxy, you need to define an interface or a group of interfaces that define the behavior of the proxy class (the proxy object). Then, you need to write an implementationInvocationHandlerThe class of the interface contains the logic executed before and after the method call of the proxy object.Proxy.newProxyInstance()method, passing in the interface's class loader, interface array, andInvocationHandlerObject, Java will dynamically generate a proxy class that implements the specified interface at runtime and delegate method calls toInvocationHandlerWhen you call a method on a proxy object, you are actually callingInvocationHandlerInterfaceinvoke()Method, in which some preprocessing logic can be executed according to the method name, parameters and other information, and then the corresponding method of the proxied object can be called through reflection.

Next, we will introduce two dynamic proxies: JDK Proxy and CGLib

1)JDK Proxy

① Internal mechanism of JDK Proxy

JDK Proxy dynamically generates proxy classes through Java's reflection mechanism. Specifically,ProxyClass will useProxyGeneratorClass (although this class is not a public API, it is the key to implementing dynamic proxy in JDK) to generate the bytecode of the proxy class and load it into the JVM. The generated proxy class inherits fromjava.lang.reflect.ProxyClass and implement the specified interface. In the proxy class method, it will callInvocationHandlerofinvokeMethod, forwards the method call to the processor for processing.

In addition, to improve performance, JDK Proxy also provides a caching mechanism for caching the Class objects of the generated proxy classes. In this way, when you need to create a proxy object of the same type, you can directly obtain the Class object of the proxy class from the cache without regenerating it. Caching is done throughWeakCacheClass, which uses weak references to cache objects so that the cache items that are no longer in use can be automatically cleaned up when the JVM performs garbage collection.

② JDK Proxy implementation steps

  • Define interfaces and proxy classes: First define one or more interfaces that will be implemented by the proxy class.
  1. public interface TargetInteface {
  2. void method1();
  3. void method2();
  4. int method3(Integer i);
  5. }
  1. public class Target implements TargetInteface {
  2. @Override
  3. public void method1() {
  4. System.out.println("method1 running ...");
  5. }
  6. @Override
  7. public void method2() {
  8. System.out.println("method2 running ...");
  9. }
  10. @Override
  11. public int method3(Integer i) {
  12. System.out.println("method3 running ...");
  13. return i;
  14. }
  15. }
  • Creating an InvocationHandler:accomplishInvocationHandlerinterface, and rewriteinvokeMethod.invokeIn the method, you can add custom logic, such as logging, permission checking, etc., and call the method of the original class through reflection.
  • Generate proxy object:transferProxy.newProxyInstanceMethod, passing in the class loader, interface array, andInvocationHandlerInstance to dynamically generate a proxy object. This method returns a proxy class instance that implements the specified interface.
  1. public class TargetProxy {
  2. public static <T> Object getTarget(T t) {
  3. //新构建了一个 新的 代理类的对象
  4. return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
  5. @Override
  6. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  7. // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
  8. //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
  9. System.out.println("执行方法前...");
  10. Object invoke = method.invoke(t, args);
  11. System.out.println("执行方法后...");
  12. return invoke;
  13. }
  14. });
  15. }
  16. }
  • Using Proxy Objects: When you call a method through a proxy object, you are actually callingInvocationHandlerofinvokemethod, in which the custom logic is executed and then the method of the original class is called.
  1. public class TargetUser {
  2. public static void main(String[] args) {
  3. TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
  4. target.method1();
  5. System.out.println("-----------------------------");
  6. target.method2();
  7. System.out.println("-----------------------------");
  8. System.out.println(target.method3(3));
  9. }
  10. }

Result output:
Before executing the method...
method1 running ...
After executing the method...
-----------------------------
Before executing the method...
method2 running ...
After executing the method...
-----------------------------
Before executing the method...
method3 running ...
After executing the method...
3

③ Characteristics of JDK Proxy

  1. Interface Proxy: JDK Proxy can only proxy classes that implement interfaces, and cannot proxy ordinary classes that do not implement interfaces.
  2. Dynamic Generation: The proxy class is dynamically generated at runtime, and developers do not need to manually write proxy class code.
  3. Strong flexibility: You can add additional functionality or logic to the original class without modifying the original class code.
  4. Performance Considerations: Because of the reflection and dynamic class generation involved, the performance of JDK Proxy may be slightly lower than static proxy or directly calling the original class method.

2)CGLib

① The core principle of CGLib dynamic proxy

  1. Bytecode Operation: CGLib uses ASM (a small and fast bytecode manipulation framework) to dynamically generate new Java classes (usually subclasses of the target class). These newly generated classes inherit from the target class and insert proxy logic when the method is called.
  2. Method interception:CGLib's core function is to implement method-level interception. Developers can implementMethodInterceptorThe interface is used to define a method interceptor, which executes custom logic before and after the method call of the proxy object, such as preprocessing, postprocessing, exception handling, etc.
  3. FastClass Mechanism: To improve performance, CGLib uses the FastClass mechanism. FastClass indexes the methods of the target class and directly accesses the target method through the index when calling. This method is much faster than Java reflection.

② Implementation steps of CGLib dynamic proxy

  • Introducing CGLib dependency: Introduce the Maven or Gradle dependency of CGLib into your project.
  1. import net.sf.cglib.proxy.Enhancer;
  2. import net.sf.cglib.proxy.MethodInterceptor;
  3. import net.sf.cglib.proxy.MethodProxy;
  4. import java.lang.reflect.Method;
  • Define the target class: Define the target class that needs to be proxied.
  1. public class Target {
  2. public void method1() {
  3. System.out.println("method1 running ...");
  4. }
  5. public void method2() {
  6. System.out.println("method2 running ...");
  7. }
  8. public int method3(Integer i) {
  9. System.out.println("method3 running ...");
  10. return i;
  11. }
  12. }
  • Implementing the MethodInterceptor interface: Create aMethodInterceptorInterface class and overrideinterceptMethod. Write the proxy logic in this method.
  • Creating a proxy object: Use the CGLib providedEnhancerclass to create a proxy object. You need to set the class to be proxied (throughsetSuperclassmethod) and callbacks (viasetCallbackMethod sets the MethodInterceptor implementation class).
  1. public class TargetProxy {
  2. public static <T> Object getProxy(T t) {
  3. Enhancer en = new Enhancer(); //帮我们生成代理对象
  4. en.setSuperclass(t.getClass());//设置要代理的目标类
  5. en.setCallback(new MethodInterceptor() {//代理要做什么
  6. @Override
  7. public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  8. System.out.println("执行方法前。。。");
  9. //调用原有方法
  10. Object invoke = methodProxy.invokeSuper(object, args);
  11. // Object invoke = method.invoke(t, args);// 作用等同与上面。
  12. System.out.println("执行方法后。。。");
  13. return invoke;
  14. }
  15. });
  16. return en.create();
  17. }
  18. }
  • Using Proxy Objects: When the method of the target class is called through the proxy object, it will be triggeredinterceptDelegate logic in methods.
  1. public class TargetUser {
  2. public static void main(String[] args) {
  3. Target target = (Target) TargetProxy.getProxy(new Target());
  4. System.out.println(target.getClass().getName());
  5. target.method1();
  6. }
  7. }

Result output:

com.heaboy.aopdemo.cglibproxy.TargetEnhancerByCGLIBf9f41fb8
Before executing the method...
method1 running ...
After executing the method...

③ Applicable scenarios of CGLib dynamic proxy

  1. Need to proxy a class that does not implement an interface: When the target class does not implement any interface, you can use CGLib for proxying.
  2. High performance requirements: In scenarios with high performance requirements, if JDK dynamic proxy cannot meet the needs, you can consider using CGLib.
  3. AOP framework implementation: In aspect-oriented programming frameworks, such as Spring AOP, when you need to proxy a class that does not implement an interface, CGLib is usually used as the underlying implementation.

④ Advantages and disadvantages of CGLib dynamic proxy

advantage:

  1. High flexibility: It can proxy classes that do not implement interfaces, broadening the scope of application of the proxy.
  2. Better performance: Through the FastClass mechanism, the calling efficiency is higher than the reflection mechanism of JDK dynamic proxy.
  3. Powerful: Supports dynamically adding additional functions or logic to the target class at runtime without modifying the original class code.

shortcoming:

  1. Bytecode operation overhead: Dynamically generating bytecode and loading it into the JVM will bring certain performance overhead.
  2. Final classes and methods cannot be proxied: Since CGLib implements proxy by inheriting the target class, it is impossible to proxy final-modified classes and methods.
  3. High complexity of use: Compared with JDK dynamic proxy, CGLib is more complicated to use and requires the introduction of additional dependencies and the handling of bytecode generation issues.

3)JDK Proxy VS CGLib 

Proxy object type:JDK Proxy can only proxy classes that implement interfaces; while CGLib can directly proxy ordinary classes.

performance:CGLib generates subclasses of the proxy class at runtime, and its performance is generally considered to be slightly better than JDK Proxy. However, in most scenarios, this performance difference is not significant.

scenes to be used:If the target object already implements the interface, using JDK Proxy is a simple and straightforward choice. If you need to proxy a class that does not implement the interface, you must use CGLib.

rely:JDK Proxy does not require additional dependencies because it is part of the Java core library; CGLib requires adding the CGLib library as a project dependency.

JDK Proxy is a native function of the Java language and does not need to be implemented by loading third-party classes;

Java provides stable support for JDK Proxy and will continue to upgrade and update JDK Proxy. For example, the performance of JDK Proxy in Java 8 is much better than that of previous versions.

JDK Proxy is implemented through interceptor plus reflection;

JDK Proxy can only proxy classes that inherit interfaces;

JDK Proxy is relatively simple to implement and call;

CGLib is a tool provided by a third party, implemented based on ASM, and has relatively high performance;

CGLib does not need to be implemented through interfaces, it completes the call by implementing subclasses.

4. Static Proxy vs Dynamic Proxy

the difference

Static proxy: Static proxies are determined during compilation. You need to write a proxy class for each proxied class. The proxy class and the proxied class implement the same interface or inherit the same parent class.

The proxy class of a static proxy exists at compile time, so it can only proxy specific classes when the program is running, and it is impossible to dynamically decide which classes to proxy.

Static proxies wrap method calls of the original object and can add additional logic before and after the call, but the proxy class needs to be written in advance, which increases the amount of code.

Static proxies explicitly specify proxy objects in the code and are relatively intuitive to use, but adding new proxy classes requires recompilation.

Dynamic Proxy: Dynamic proxy is to create proxy objects at runtime without writing proxy classes in advance. It uses Java's reflection mechanism to dynamically generate proxy classes and proxy objects.

Dynamic proxy is based on interface and is implemented through java.lang.reflect.Proxy class and java.lang.reflect.InvocationHandler interface.

Dynamic proxies can proxy classes of multiple interfaces and dynamically decide which classes to proxy. At runtime, proxies can be generated for different objects as needed, which is more flexible.

Dynamic proxy does not require writing a specific proxy class for each proxied class, which is more flexible and saves code.

Dynamic proxies can add custom logic before and after the proxy object's method call, such as logging, transaction management, etc. The disadvantage of dynamic proxies is that compared to static proxies, generating proxy objects at runtime requires a certain performance overhead.

Applicable scene

Static proxy is suitable for the following scenarios:

When the number of target objects (proxied objects) is limited and certain, static proxy can be implemented by manually writing proxy classes. Static proxy creates proxy classes at compile time, so it has better performance at runtime.

Static proxies encapsulate the target object and add additional functionality without modifying the original code. This makes static proxies often used for cross-cutting concerns such as logging and transaction management.

Dynamic proxy is suitable for the following scenarios:

When the number of target objects is uncertain or cannot be determined in advance, dynamic proxy can generate proxy objects more conveniently. It generates proxy classes and proxy objects at runtime, avoiding the tedious work of manually writing multiple proxy classes.

Dynamic proxies can flexibly add, delete, or change proxy behaviors for target objects at runtime, which makes dynamic proxies often used in application scenarios such as AOP (aspect-oriented programming) and RPC (remote procedure call).

It should be noted that since dynamic proxy creates proxy classes and proxy objects through reflection mechanism at runtime, its performance may be slightly lower than that of static proxy. In addition, dynamic proxy can only proxy target objects that implement the interface, while static proxy does not have this limitation.

In summary, static proxy is suitable for scenarios where the number of target objects is limited and certain, and encapsulation and additional functions are required; while dynamic proxy is suitable for scenarios where the number of target objects is uncertain or cannot be determined in advance, and the proxy behavior needs to be flexibly added, deleted, or changed. Choose the appropriate proxy method based on specific needs and situations.

5. Proxy implementation in SpringAOP

1) Introduction to Spring AOP

Talk about your understanding of AOP

Spring AOP is an important module in the Spring framework, which is used to implement aspect-oriented programming.

Aspect-oriented programmingThis is a programming pattern that allows programmers to modularize through custom crosscutting points, encapsulating behaviors that affect multiple classes into reusable modules. For example, if you don't use AOP, you need to put the log output statements in all classes and methods, but with AOP, you can encapsulate the log output statements into a reusable module, and then put them in the class in a declarative way, and the log output is automatically completed every time the class is used.

In the idea of ​​aspect-oriented programming, the functions are divided into two types

  • Core Business:Login, register, add, delete, modify, check, all called core business

  • Peripheral functions:Logs, transaction management, these secondary are peripheral businesses

In aspect-oriented programming, core business functions and peripheral functions are developed independently, and the two are not coupled. Then the aspect functions and core business functions are "woven" together, which is called AOP.

AOP can transform those things that are not related to the business.However, it encapsulates the logic or responsibilities commonly called by business modules (such as transaction processing, log management, permission control, etc.),easy toReduce system duplication of codeReduce coupling between modules,andFacilitates future scalability and maintainability

There are several concepts in AOP:

  • AspectJ: Aspect is just a concept. There is no specific interface or class corresponding to it. It is a general term for Join point, Advice and Pointcut.

  • Join point: A join point refers to a point in the program execution process, such as a method call, exception handling, etc. In Spring AOP, only method-level join points are supported.

  • Advice: Advice, that is, the cross-cutting logic in a section we define, has three types: "around", "before" and "after". In many AOP implementation frameworks, Advice is usually used as an interceptor, and can also contain many interceptors as a link around the Join point for processing.

  • Pointcut: Pointcut, used to match join points. Which Join points in an AspectJ need to be screened by Pointcut.

  • Introduction: Introduction, allowing an aspect to declare that the advised objects implement any additional interfaces they do not actually implement. For example, a proxy object can proxy two target classes.

  • Weaving: Weaving, with connection points, pointcuts, notifications, and aspects, how do we apply them to the program? Yes, it is weaving. Under the guidance of pointcuts, the notification logic is inserted into the target method, so that our notification logic can be executed when the method is called.

  • AOP proxy: AOP proxy refers to the object that implements the aspect protocol in the AOP implementation framework. There are two types of proxies in Spring AOP, namely JDK dynamic proxy and CGLIB dynamic proxy.

  • Target object: The target object is the object being proxied.

Spring AOP is implemented based on JDK dynamic proxy and Cglib promotion. Both proxy methods are runtime methods, so there is no compile-time processing. Therefore, Spring is implemented through Java code.

What problems does AOP solve?

Some common behaviors that are scattered across multiple classes or objects (such as logging, transaction management, permission control, interface current limiting, interface idempotence, etc.) are usually called Cross-cutting concerns If we repeat these behaviors in each class or object, it will lead to redundant, complex and difficult to maintain code.

AOP can separate cross-cutting concerns (such as logging, transaction management, permission control, interface current limiting, interface idempotence, etc.) from Core business logic (core concerns) Separate it out to achieve separation of concerns.

Application scenarios of AOP

  • Logging: Customize logging annotations and use AOP to implement logging with just one line of code.

  • Performance statistics: Use AOP to count the execution time of the target method before and after execution, which is convenient for optimization and analysis.

  • Transaction Management:@Transactional Annotations allow Spring to perform transaction management for us, such as rolling back exception operations, eliminating the need for repeated transaction management logic.@TransactionalAnnotations are implemented based on AOP.

  • Permission control: Use AOP to determine whether the user has the required permissions before the target method is executed. If so, the target method is executed, otherwise it is not executed. For example, SpringSecurity uses@PreAuthorize You can customize permission checking by annotating one line of code.

  • Interface current limiting: Use AOP to limit the current of requests through specific current limiting algorithms and implementations before the target method is executed.

  • Cache management: Use AOP to read and update the cache before and after the target method is executed.

How to implement AOP

Common implementation methods of AOP include dynamic proxy, bytecode manipulation, etc.

Spring AOP is based on dynamic proxy. If the object to be proxied implements a certain interface, Spring AOP will use JDK Proxy, to create a proxy object, and for objects that do not implement the interface, you cannot use JDK Proxy to proxy, then Spring AOP will use Cglib Generate a subclass of the proxied object as a proxy

2) Implementing Spring AOP based on JDK Proxy dynamic proxy

① Configure SpringAOP

existspring-aop.xmlConfigure related beans and aspects in the configuration file

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. 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">
  5. <bean id="target" class="com.xxhh.aopdemo.aop.Target"/>
  6. <bean id="targetAdvice" class="com.xxhh.aopdemo.aop.TargetAdvice"/>
  7. <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
  8. <property name="target" ref="target"/> <!--被代理的类-->
  9. <property name="interceptorNames" value="targetAdvice"/> <!--如果用多种增强方式,value的值使用逗号(,)分割-->
  10. <property name="proxyTargetClass" value="false"/> <!--如果设置为true,则创建基于类的代理(使用CGLIB);如果设置为false,则创建基于接口的代理(使用JDK动态代理)。-->
  11. <property name="interfaces" value="com.xxhh.aopdemo.aop.TargetInteface"/> <!--target实现的接口-->
  12. </bean>
  13. </beans>

② Define abstract interface

  1. public interface TargetInteface {
  2. void method1();
  3. void method2();
  4. int method3(Integer i);
  5. }

③ Define the proxy class

  1. public class Target implements TargetInteface{
  2. /*
  3. * 需要增强的方法,连接点JoinPoint
  4. **/
  5. @Override
  6. public void method1() {
  7. System.out.println("method1 running ...");
  8. }
  9. @Override
  10. public void method2() {
  11. System.out.println("method2 running ...");
  12. }
  13. @Override
  14. public int method3(Integer i) {
  15. System.out.println("method3 running ...");
  16. return i;
  17. }
  18. }

④ Define proxy class (enhancement method)

  1. public class TargetAdvice implements MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice {
  2. /*
  3. * 通知/增强
  4. **/
  5. @Override
  6. public Object invoke(MethodInvocation methodInvocation) throws Throwable {
  7. System.out.println("前置环绕通知");
  8. Object proceed = methodInvocation.proceed();
  9. System.out.println("后置环绕通知");
  10. return proceed;
  11. }
  12. @Override
  13. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
  14. System.out.println("后置返回通知");
  15. }
  16. @Override
  17. public void before(Method method, Object[] args, Object target) throws Throwable {
  18. System.out.println("前置通知");
  19. }
  20. }

⑤ Testing

  1. public class AopTest {
  2. public static void main(String[] args) {
  3. ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-aop.xml");
  4. TargetInteface targetProxy = (TargetInteface) appCtx.getBean("targetProxy");
  5. targetProxy.method1();
  6. }
  7. }

Output:

Front surround notification
Pre-notification
method1 running ...
Post-return notification
Rear surround notification

3) Implementing SpringAOP based on CGLib dynamic proxy

① Configure SpringAOP

existspring-confaop.xmlConfigure related beans and aspects in the configuration file

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. 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">
  7. <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
  8. <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
  9. <!--扫包-->
  10. <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
  11. </beans>

② Define the proxy class

  1. /*
  2. * 目标类
  3. **/
  4. public class Target {
  5. public void method1() {
  6. System.out.println("method1 running ...");
  7. }
  8. public void method2() {
  9. System.out.println("method2 running ...");
  10. }
  11. /*
  12. * 连接点JoinPoint
  13. **/
  14. public int method3(Integer i) {
  15. System.out.println("method3 running ...");
  16. // int i1 = 1 / i;
  17. return i;
  18. }
  19. }

③ Define the proxy class (aspect class)

  1. import org.aspectj.lang.ProceedingJoinPoint;
  2. /*
  3. * 切面类
  4. **/
  5. public class TargetAspect {
  6. /*
  7. * 前置通知
  8. **/
  9. public void before() {
  10. System.out.println("conf前置通知");
  11. }
  12. public void after() {
  13. System.out.println("conf后置通知");
  14. }
  15. public void afterReturning() {
  16. System.out.println("conf后置返回通知");
  17. }
  18. public void afterThrowing(Exception ex) throws Exception {
  19. // System.out.println("conf异常通知");
  20. // System.out.println(ex.getMessage());
  21. }
  22. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  23. Object proceed = null;
  24. if (!"".equals("admin")) {
  25. System.out.println("conf环绕前置");
  26. proceed = pjp.proceed(pjp.getArgs());
  27. System.out.println("conf环绕后置");
  28. }
  29. return proceed;
  30. }
  31. }

④ Testing

  1. public class AopTest {
  2. public static void main(String[] args) {
  3. ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-confaop.xml");
  4. Target targetProxy = (Target) appCtx.getBean("target");
  5. System.out.println(targetProxy.method3(0));
  6. }
  7. }

Output:

conf pre-notification
conf surround prepend
method3 running ...
conf post-return notification
conf surround post
conf post notification

4) Implementing SpringAOP based on annotation dynamic proxy

① Configure SpringAOP

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. 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">
  7. <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
  8. <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
  9. <!--扫包-->
  10. <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
  11. </beans>

② Definition annotation

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface TestAnnotation{
  5. }

③ Define the aspect class

  1. /*
  2. * 切面类
  3. **/
  4. @Aspect
  5. @Component
  6. public class AnnotationAspect {
  7. // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
  8. @Pointcut("@annotation(TestAnnotation)")
  9. private void advicePointcut() {}
  10. /*
  11. * 前置通知
  12. **/
  13. @Before("advicePointcut()")
  14. public void before() {
  15. System.out.println("annotation前置通知");
  16. }
  17. @After("advicePointcut()")
  18. public void after() {
  19. System.out.println("annotation后置通知");
  20. }
  21. @AfterReturning(pointcut = "advicePointcut()")
  22. public void afterReturning() {
  23. System.out.println("annotation后置返回通知");
  24. }
  25. @AfterThrowing(pointcut = "advicePointcut()", throwing = "ex")
  26. public void afterThrowing(Exception ex) throws Exception {
  27. System.out.println("annotation异常通知");
  28. System.out.println(ex.getMessage());
  29. }
  30. @Around("advicePointcut()")
  31. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  32. Object proceed = null;
  33. if (!"".equals("admin")) {
  34. System.out.println("annotation环绕前置");
  35. proceed = pjp.proceed(pjp.getArgs());
  36. System.out.println("annotation环绕后置");
  37. }
  38. return proceed;
  39. }
  40. }

④ Add annotations to controller

  1. @Controller
  2. public class TestController {
  3. @RequestMapping("/test.do")
  4. @ResponseBody
  5. public String testController() {
  6. TestController o = (TestController) AopContext.currentProxy();
  7. o.test();
  8. // System.out.println("tewt");
  9. return "ok";
  10. }
  11. @TestAnnotation
  12. public void test() {
  13. System.out.println("test running");
  14. }
  15. }

⑤ Testing