Spring AOP implementation principle and CGLIB application

AOP (Aspect Orient Programming), as a supplement of object-oriented Programming, is widely used to deal with some crosscutting system-level services, such as transaction management, security check, cache, object pool management, etc. The key of AOP implementation is the AOP proxy automatically created by AOP framework. AOP proxy can be divided into static proxy and dynamic proxy. Among them, static proxy refers to the use of the command provided by AOP framework to compile, so that the generation of AOP proxy class can be generated in the compilation stage, so it is also called compile-time enhancement; Dynamic proxies, on the other hand, generate AOP dynamic proxy classes “temporarily” in memory at run time with the help of JDK dynamic proxies, CGLIB, etc., and are therefore also known as runtime enhancement.

The value of AOP

In traditional OOP programming, the object is the core, and the whole software system is composed of a series of interdependent objects, and these objects will be abstracted into a class, and allows the use of class inheritance to manage the general and special relationships between classes. With the increase of software scale and the gradual upgrade of applications, some problems that OOP is difficult to solve gradually appear.

We can analyze and abstract out a series of objects with certain properties and behaviors, and form a complete software function through the cooperation between these objects. Because objects can be inherited, we can abstract properties that have the same functionality or properties into a hierarchical class structure. With the expansion of software specification, specialization and OOP application practice, some problems that OOP cannot solve are exposed.

Now assume that there are three pieces of code in the system that are exactly alike. These pieces of code are usually completed by “copy” and “paste”. The software developed by this “copy” and “paste” method is shown in Figure 1.

Figure 1. Software containing the same code in multiple places

Looking at the diagram shown in Figure 1, some readers may already see the downside of this approach: If one day, the dark code in Figure 1 needs to be modified, do you open the code in three places? What if, instead of three places containing this code, there were 100 places, or even 1,000 places containing this code?

To solve this problem, we typically define the dark part of the code shown in Figure 1 as a method and then call that method in each of the three code segments. In this way, the structure of the software system is shown in Figure 2.

Figure 2 implements system functionality through method calls

For software system is shown in figure 2, if need to modify the dark parts of the code, just change a place, no matter how many places in the whole system calls the method, the program does not need to modify the place, only need to modify the called method, in this way, greatly reduces the complexity of software maintenance.

For methods 1, 2, and 3 as shown in Figure 2, you still need to explicitly call the dark method, which solves most application scenarios. But for some more special cases: the application requires methods 1, 2, and 3 to be completely separated from the dark method — methods 1, 2, and 3 do not need to call the dark method directly.

Because the requirements of the software system change frequently, the system design method 1, method 2 and method 3 only realized the core business functions. After a period of time, we need to add transaction control for method 1, Method 2 and method 3. After a period of time, the customer proposed that method 1, method 2 and method 3 need to be validated by users, and only legitimate users can execute these methods. After a while, the customer suggested that methods 1, 2, and 3 should add logging. After a while, the client came up with… Faced with such a situation, what should we do? There are two ways to do this:

  • Reject customer request directly according to requirement specification.
  • Embrace needs and meet customer needs.

The first approach is obviously not good, the customer is god, we should try to meet the needs of customers. The second option is usually used, so what’s the solution? Do you define a new method each time, and then modify methods 1, 2, and 3 to add new method calls? That’s a lot of work! We want a special method: we just define the method, don’t call it explicitly in methods 1, 2, or 3, and the system will “automatically” execute the special method.

The above idea sounds fantastic, even a little impractical, but it is entirely possible, and the technology that implements this requirement is AOP. AOP is dedicated to processing system distributed in various modules (cross focus problem in different ways), in Java EE applications, often through AOP to handle some system-level services, with characteristics of crosscutting such as transaction management, security, caching, object pool management, AOP has become a very common solution.

AOP with AspectJ’s compile-time enhancements

AspectJ is an AOP framework based on the Java language that provides powerful AOP capabilities, some of which have been borrowed or adopted by many other AOP frameworks.

AspectJ is an AOP implementation of the Java language, which mainly consists of two parts: the first part defines how to express and define the syntax specification in AOP programming, through this language specification, we can easily use AOP to solve the problem of cross-concerns in the Java language; The other part is the tools part, including compilers, debugging tools and so on.

AspectJ is one of the earliest and most powerful IMPLEMENTATIONS of AOP. It has a good implementation of the whole AOP mechanism, and many AOP implementations in other languages have borrowed or adopted many of AspectJ’s designs. In the Java world, many of the syntactic constructs in AspectJ have essentially become standards in the AOP world.

Download, install, AspectJ is simpler, readers login AspectJ’s official website (http://www.eclipse.org/aspectj), which can be downloaded to an executable JAR package, To install AspectJ, run the java-jar aspectj-1. X.x.jar jar command and click Next several times.

After you have successfully installed AspectJ, you will see the following file structure in the E:\Java\AOP\ AspectJ1.6 path (where AspectJ was installed) :

  • Bin: this directory stores aj, AJ5, AJC, ajdoc, and ajbrowser commands. Ajc is the most commonly used command. It is similar to javac and is used to enhance common Java classes during compilation.
  • Docs: Stores AspectJ usage instructions, reference manuals, and API documents.
  • Lib: The four JAR files in this path are AspectJ’s core class libraries.
  • Relevant authorization documents.

Some documents, some AspectJ introductory books, when it comes to using AspectJ, say you must use Eclipse tools, as if you can’t use AspectJ without them.

Although AspectJ is an open source project of the Eclipse Foundation, and Eclipse’s AJDT plug-in (AspectJ Development Tools) is provided to develop AspectJ applications, But AspectJ definitely doesn’t have to rely on Eclipse tools.

In fact, the use of AspectJ is as simple as compiling and running Java programs with the JDK. Here’s a simple program to demonstrate the use of AspectJ and examine how AspectJ can be enhanced at compile time.

Start by writing a simple Java class that simulates a business component.

Listing 1. Hello. Java
Public void sayHello(){system.out.println ("Hello AspectJ! ); Public static void main(String[] args) {Hello h = new Hello(); h.sayHello(); }}Copy the code

The Hello class above emulates a business logic component and compiles and runs the Java program. The result is unsurprising, and the program prints the “Hello AspectJ” string on the console.

Suppose that the client now needs to start the transaction before executing the sayHello() method and close it when it finishes. In traditional programming mode, we would have to manually modify the sayHello() method — we wouldn’t need to modify the sayHello() method above if we used AspectJ instead.

Let’s define a special Java class.

Listing 2. TxAspect. Java
Public aspect TxAspect {// Specifies that the hello.sayHello () method is executed with the following block void around():call(void) Hello.sayhello ()){system.out.println (" Start transaction... ); proceed(); System.out.println(" end of transaction... ); }}Copy the code

As the reader may have noticed, the above class file does not define Java classes using class, interface, or enum. Instead, it defines Java classes using aspects. No! The TxAspect above is not a Java class at all, so aspect is not a Java-supported keyword; it is only a keyword recognized by AspectJ.

The bold code above is also not a method; it simply specifies that when the program executes the sayHello() method of the Hello object, the system will instead execute a block of curly braces code in bold, where proceed() represents a callback to the original sayHello() method.

As mentioned earlier, Java does not recognize the contents of the txAspes.java file, so we will use the ajc.exe command to compile the Java program above. In order to use ajc.exe from the command line, you need to add the bin PATH in the AspectJ installation directory (such as E:\Java\AOP\ aspectJ1.6bin) to your system’s PATH environment variable. Run the following command to compile:

ajc -d . Hello.java TxAspect.java

Exe is used to compile Java programs. The difference is that ajc.exe recognizes AspectJ syntax. In this sense, we can think of ajc.exe as an enhanced javac.exe command.

Running the Hello class still doesn’t change anything, because the Hello class is under the Lee package. The program runs the Hello class with the following command:

java lee.Hello

Run the program and you will see a surprising result:

Start the transaction…

Hello AspectJ!

End of transaction…

From the above results, we can make no changes to the Hello. Java class and still meet the customer’s requirements: the program simply prints “start transaction…” at the console. “, “Closing of business…” In fact, we can use the actual transaction code to replace these two lines of simple statements, which can meet customer requirements.

If a client needs to add logging functionality to the sayHello() method, it’s easy to define a LogAspect as follows:

Listing 3. LogAspect. Java
Public aspect LogAspect {// Define a PointCut, PointCut logPointcut() :execution(void hello.sayHello ()); void hello.sayHello ()); // Execute the following code block after():logPointcut() {system.out.println (" Log... ); }}Copy the code

The boldface code for the above program defines a Pointcut: LogPointcut – Equivalent to executing the sayHello() method of the Hello object and specifying that a simple code block is executed after logPointcut, that is, the specified code block is executed after the sayHello() method. Use the following command to compile the Java program above:

ajc -d . *.java

Run the Hello class again and see the following:

Start the transaction…

Hello AspectJ!

Log…

End of transaction…

From the results of the above run, we can keep adding new functionality to the sayHello() method by using the AOP support provided by AspectJ.

Why does the Hello class keep adding new functionality on the fly, without making any changes to it? This doesn’t seem to follow basic Java syntax rules. Hello.class = hello. class = hello. class = hello. class = hello. class = hello. class = hello. class = hello. class = hello. class = hello. class = hello. class = hello. class

Listing 4. Hello, class
package lee; import java.io.PrintStream; import org.aspectj.runtime.internal.AroundClosure; public class Hello { public void sayHello() { try { System.out.println("Hello AspectJ!" ); } catch (Throwable localThrowable) { LogAspect.aspectOf().ajc$after$lee_LogAspect$1$9fd5dd97(); throw localThrowable; } LogAspect.aspectOf().ajc$after$lee_LogAspect$1$9fd5dd97(); }... private static final void sayHello_aroundBody1$advice(Hello target, TxAspect ajc$aspectInstance, AroundClosure ajc$AroundClosure) {system.out.println (" Start transaction... ); AroundClosure localAroundClosure = ajc$aroundClosure; sayHello_aroundBody0(target); System.out.println(" end of transaction... ); }}Copy the code

It’s not hard to see that the hello. class file is not compiled from the original Hello. Java file. This new class enhances the functionality of the original Hello.java class, so AspectJ is often referred to as a compile-time enhanced AOP framework.

Tip: relative another AOP and AspectJ framework, they do not need to enhance the target class at compile time, but the runtime target class generated proxy class, or the proxy class and target class implements the same interface, or is a subclass of the target class – in short, the proxy class instance can be used as the target class instance. In general, compile-time enhanced AOP frameworks have a performance advantage — because run-time dynamically enhanced AOP frameworks need to be dynamically enhanced every time they run.

In fact, AspectJ allows you to add new functionality to multiple methods at the same time, as long as we specify more methods that match when we define the Pointcut. Here’s the clip:

pointcut xxxPointcut() 
    :execution(void H*.say*());Copy the code

The xxxPointcut in the above program will match any method starting with say in any class starting with H, but it must return void; If you do not want to match arbitrary return value types, you can change the code to the following:

pointcut xxxPointcut()

:execution(* H*.say*());

For details on how to define AspectJ aspects, pointcuts, and so on, refer to the Quick5.pdf file in the Doc directory of the AspectJ installation path.

Using Spring AOP

Like AspectJ, Spring AOP also requires enhancements to the target classes, that is, generating new AOP proxy classes; Unlike AspectJ, Spring AOP does not require any special commands to compile Java source code. It generates AOP proxies dynamically at runtime, temporarily generating “proxy classes” in memory.

Spring allows AspectJ annotations to be used to define aspects, pointcuts, and Advice, and the Spring framework identifies and generates AOP proxies based on these annotations. Spring uses the same annotations as AspectJ 5, but instead of using AspectJ’s compiler or Weaver, it still uses Spring AOP underneath and generates AOP proxies dynamically at run time. A compiler or weaver that does not depend on AspectJ.

In short, Spring still enhances target objects by generating dynamic proxies at run time, so it doesn’t require additional compilation or AspectJ’s weavers support; AspectJ has compile-time enhancements, so AspectJ needs to use its own compiler to compile Java files, as well as a weaver.

To enable Spring’s support for the configuration of the @AspectJ aspect, and to ensure that the target Bean in the Spring container is automatically enhanced by one or more aspects, the following fragment must be configured in the Spring configuration file:

<? The XML version = "1.0" encoding = "GBK"? > <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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <! Aop: Aspectj-autoproxy /> </beans>Copy the code

Of course, if we want to fully enable Spring’s “zero configuration” feature, we also need to enable Spring’s “zero configuration” support to automatically search for Bean classes in the specified path.

Automatic enhancement means that Spring determines whether one or more aspects need to be enhanced for a given Bean, and automatically generates proxies accordingly so that enhancement processing can be invoked when appropriate.

If you do not intend to use Spring’s XML Schema configuration, you should add the following fragment to your Spring configuration file to enable @AspectJ support.

<! - start the @aspectj support - > < bean class = "org. Springframework. Aop. AspectJ. The annotation. AnnotationAwareAspectJAutoProxyCreator" / >Copy the code

Above AnnotationAwareAspectJAutoProxyCreator is a Bean in the configuration file after processor (BeanPostProcessor), after the Bean processors will be generated AOP agent for Bean in the container,

When @AspectJ support is enabled, whenever we configure a Bean with @aspect annotations in the Spring container, Spring will automatically recognize the Bean and treat it as an Aspect Bean.

Configuring Aspect beans (that is, beans annotated with @aspect) in the Spring container is no different from configuring regular beans, using the same < Bean… /> element, also supports dependency injection to configure attribute values; If we enable Spring’s “zero configuration” feature, we can also have Spring automatically search for and load aspect beans in the specified path.

Annotate a Java class with @Aspect that will act as an Aspect Bean, as shown in the following code snippet:

@aspect public class LogAspect {// Define the rest of the class... }Copy the code

Aspect classes (classes decorated with @aspect) can have methods, attribute definitions, and possibly pointcuts, enhanced processing definitions, just like any other class.

After we decorate a Java class with @Aspect, Spring will not treat the Bean as a component Bean, so the post-processing Bean responsible for automatic enhancement will skip the Bean and not do any enhancement to the Bean.

There is no need to worry about enhancing Aspect classes defined using @Aspect at development time. When the Spring container detects that a Bean class uses the @Aspect annotation, it does not enhance that Bean class.

We’ll consider using Spring AOP to rewrite the previous example:

The following example uses a simple Chinese class to simulate a business logic component:

Listing 5. Chinese. Java
@Component public class Chinese {// Implement the Person interface sayHello() method public String sayHello(String name) { System.out.println("-- executing sayHello --"); Return name + "Hello, Spring AOP"; } public void eat(String food) {system.out.println (" I am eating :"+ food); }}Copy the code

After providing the above Chinese classes, we should also add transaction control and logging for each method of the above Chinese classes. In this case, we can consider using Around and AfterReturning.

Take a look at the AfterReturning enhancement code.

Listing 6. AfterReturningAdviceTest. Java
/ / define a @ Aspect public class AfterReturningAdviceTest {/ / matching org. Crazyit. App. Service. Impl under the package all the classes, / / of all the methods to execute as a starting point @AfterReturning(returning="rvt", pointcut="execution(* org.crazyit.app.service.impl.*.*(..) )") public void log(Object RVT) {system.out.println (" return value :" + RVT); System.out.println(" Simulate logging...") ); }}Copy the code

The Aspect class above uses the @aspect modifier so that Spring treats it as an Aspect Bean. Bold in the program code will be specified in the call. Org crazyit. App. Service. Impl package after all methods of all classes of woven into the log (Object the modernization) method.

Take a look at the Around enhancement code:

Listing 7. AfterReturningAdviceTest. Java
/ / define a @ Aspect public class AroundAdviceTest {/ / matching org. Crazyit. App. Service. Impl under the package all the classes, / / of all the methods to execute as a starting point @Around("execution(* org.crazyit.app.service.impl.*.*(..) )") public Object processTx(ProceedingJoinPoint JP) throws java.lang.throwable {system.out.println (" Before executing the target method, Simulate start transaction..." ); Proceed (new String[]{" changed parameters "}); // Proceed (new String[]{" changed parameters "}); System.out.println(" Emulation ends transaction after execution of target method..." ); Return RVT + "new content "; }}Copy the code

Similar to the AfterReturning enhancement, @aspect is used to decorate the preceding Bean, The bold code specified in the call org. Crazyit. App. Service. Impl package of all methods of all classes “(Around) before and after” weave processTx (ProceedingJoinPoint jp) method

It is important to note that although only AfterReturning and Around enhancements are introduced here, Spring also supports Before, After, and AfterThrowing enhancements. For more detailed programming details on Spring AOP programming, see Lightweight Java EE Enterprise Applications in Action.

This example uses Spring’s zero configuration to turn on Spring AOP, so the Chinese class uses the @Component modifier and the Aspect Bean uses the @aspect modifier. Advice in aspect beans uses the @afterreturning and @around annotations, respectively. Next, simply provide the following configuration files for Spring:

Listing 8. Beans. XML
<? The XML version = "1.0" encoding = "GBK"? > <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <! <context:component-scan base-package="org.crazyit.app.service,org.crazyit.app.advice"> <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/> </context:component-scan> <! Aop: Aspectj-autoproxy /> </beans>Copy the code

Next, in the traditional way to get the Chinese Bean in the Spring container, and call the Bean’s two methods, the program code is as follows:

Listing 9. BeanTest. Java
Public class BeanTest {public static void main(String[] args) {// Create Spring container ApplicationContext CTX = new ClassPathXmlApplicationContext("bean.xml"); Chinese p = ctx.getBean("chinese" ,Chinese.class); System. The out. Println (p. ayHello (" * * ")); P.e at (" watermelon "); }}Copy the code

As you can see from the development process above, there is nothing special about the business components, aspect beans that the developer provides for Spring AOP. Only the Aspect Bean needs to be decorated with @aspect. Programs do not need to use a special compiler, weaver for processing.

If you run the above program, you should see the following result:

Before executing the target method, the simulation starts the transaction…

SayHello ()

After executing the target method, the simulation ends the transaction…

Gets the target method return value: the changed parameter Hello, new to Spring AOP

Analog logging function…

Changed parameter Hello, new to Spring AOP

Before executing the target method, the simulation starts the transaction…

I’m eating: Changed parameters

After executing the target method, the simulation ends the transaction…

Gets the target method return value :null new content

Analog logging function…

The sayHello and eat methods of the Chinese object are called, but it is not the Chinese object’s method that is actually executed. That is, Spring AOP also generates an AOP proxy class for the Chinese class. This can be seen by adding the following code to the program:

System.out.println(p.getClass());

Code above can output p variables referenced object implementation class, again executable program will have a class can see the code above, org. Crazyit. App. Service. Impl. Chinese? EnhancerByCGLIB? The output of 290441d2, which is the implementation class of the object referenced by the P variable, is Spring AOP’s dynamically generated AOP proxy class. As you can see from the class name of the AOP proxy class, the AOP proxy class is generated by CGLIB.

If you modify the above program slightly, simply let the above business logic Class Chinese implement an arbitrary interface — this approach is more in line with the principle of “interface oriented programming” advocated by Spring. Suppose our program provides the following Person interface to the Chinese class and lets the Chinese class implement it:

Listing 10. Person. Java
public interface Person 
{ 
String sayHello(String name); 
void eat(String food); 
}Copy the code

Next, make the BeanTest class program against the Person interface instead of the Chinese class. Change the BeanTest class to the following form:

Listing 11. BeanTest. Java
Public class BeanTest {public static void main(String[] args) {// Create Spring container ApplicationContext CTX = new ClassPathXmlApplicationContext("bean.xml"); Person p = ctx.getBean("chinese" ,Person.class); System. The out. Println (p. ayHello (" * * ")); P.e at (" watermelon "); System.out.println(p.getClass()); }}Copy the code

The original program will be oriented to The Chinese class programming, now change the program to face the Person interface programming, run the program again, the program running results have not changed. Just System. Out. Println (p.g etClass ()); Class $Proxy7 will be output, indicating that the AOP proxy is not generated by CGLIB at this point, but by the JDK dynamic proxy.

The Spring AOP framework treats AOP proxy classes as follows: If the target object’s implementation class implements an interface, Spring AOP will use JDK dynamic proxies to generate AOP proxy classes; If the implementation class of the target object does not implement an interface, Spring AOP will use CGLIB to generate the AOP proxy class — though the selection process is completely transparent and unconcerned to the developer.

Spring AOP dynamically chooses to use JDK dynamic proxies and CGLIB to generate AOP proxies. If the target class implements the interface, Spring AOP does not need CGLIB support. You can generate an AOP Proxy directly using the JDK supplied Proxy and InvocationHandler. How to use Proxy and InvocationHandler to generate dynamic proxies is beyond the scope of this article. If you are interested in using Proxy and InvocationHandler, refer to the Java API documentation or crazy Java Handouts.

Spring AOP principle analysis

As you can see from the previous introduction, an AOP proxy is actually an object dynamically generated by an AOP framework that can be used as a target object. An AOP proxy contains all the methods of the target object, but there are differences between the methods in an AOP proxy and the methods of the target object: THE AOP methods add enhanced processing at specific pointcuts and call back the methods of the target object.

An AOP proxy contains methods and a method diagram of the target object is shown in Figure 3.

Figure 3.AOP proxy methods versus target object methods

Spring’s AOP proxies are generated and managed by Spring’s IoC container, and their dependencies are also managed by the IoC container. Thus, AN AOP proxy can directly target other Bean instances in the container, and this relationship can be provided by the dependency injection of the IoC container.

There are only three parts of AOP programming that require programmer involvement:

  • Define common business components.
  • Define pointcuts, where a pointcut may crosscut multiple business components.
  • Define enhancements, which are processing actions woven into the AOP framework for common business components.

The first of the three sections above is the most mundane and needs no explanation. The key to AOP programming, then, is to define pointcuts and enhancements. Once the appropriate pointcuts and enhancements are defined, the AOP framework will automatically generate AOP proxies, and the methods of AOP proxies are roughly as follows:

Proxied object methods = enhanced processing + proxied object methods

From the above business definition, it’s easy to see how Spring AOP works: The AOP framework is responsible for dynamically generating an AOP proxy class, whose methods consist of Advice and methods that call back to target objects.

For the software call structure shown in Figure 2 above: When method 1, method 2, method 3… The traditional approach is for the programmer to manually modify methods 1, 2, 3… Call this crosscutting method through code, but this is not scalable because you change the code every time.

So AOP framework appeared, AOP framework can “dynamically” generate a new proxy class, and this proxy class contains methods 1, 2, 3… Calls to this “crosscutting” method have also been added — but these calls are handled by proxy classes automatically generated by the AOP framework, so they are extremely extensible. Instead of manually modifying the code for methods 1, 2, and 3, programmers define pointcuts — the AOP proxy classes generated by the AOP framework contain the new methods 1, 2, and 3, AOP frameworks, on the other hand, use pointcuts to decide whether to call back “crosscutting” methods in methods 1, 2, and 3.

In a nutshell: The essence of the AOP principle is to dynamically generate a proxy class that implements the invocation in Figure 2 — an invocation that does not require a programmer to modify the code. CGLIB is a proxy generation library. Here is how to use CGLIB to generate proxy classes.

Use CGLIB to generate proxy classes

CGLIB (Code Generation Library) is simply a Code Generation Library. It can dynamically subclass a class at run time.

Instead of using the Previously defined Chinese class to generate the proxy directly with CGLIB, this proxy class can also achieve the same effect as Spring AOP proxies.

An interceptor implementation class is provided for CGLIB:

Listing 12. AroundAdvice. Java
public class AroundAdvice implements MethodInterceptor { public Object intercept(Object target, Method method , Object[] args, MethodProxy proxy) throws java.lang.throwable {system.out.println (" Simulation starts transaction before executing target method..." ); Object RVT = proxy.invokesuper (target, new String[]{" changed parameter "}); System.out.println(" Emulation ends transaction after execution of target method..." ); Return RVT + "new content "; }}Copy the code

The aroundadvice. Java function is similar to AroundAdvice in that it can weave in enhanced processing before and after the target method is called.

The ChineseProxyFactory class generates a proxy class for Chinese using CGLIB: ChineseProxyFactory

Listing 13. ChineseProxyFactory. Java
public class ChineseProxyFactory { public static Chinese getAuthInstance() { Enhancer en = new Enhancer(); // Set the target class en.setsuperclass (chinese.class) to be proxied; // Set the interceptor to proxy en.setcallback (new AroundAdvice()); Return (Chinese)en.create(); }}Copy the code

CGLIB’s Enhancer object will use Chinese as the target class and AroundAdvice as the “Advice” object. This subclass is the CGLIB generation proxy class. It can be used as a Chinese object, but it enhances the Methods of the Chinese class.

The main program to test the Chinese proxy class is as follows:

Listing 14. The Main Java
public class Main { public static void main(String[] args) { Chinese chin = ChineseProxyFactory.getAuthInstance(); System.out.println(chin.sayhello (" sun Wukong ")); Chin. Eat (" watermelon "); System.out.println(chin.getClass()); }}Copy the code

Run the main program and see the following output:

Before executing the target method, the simulation starts the transaction…

SayHello ()

After executing the target method, the simulation ends the transaction…

Changed parameter Hello, new content of CGLIB

Before executing the target method, the simulation starts the transaction…

I’m eating: Changed parameters

After executing the target method, the simulation ends the transaction…

class lee.Chinese? EnhancerByCGLIB? 4bd097d9

The sayHello() and eat() methods of the CGLIB proxy object have been added with transaction control (only simulated). This CGLIB proxy is essentially the AOP proxy generated by Spring AOP.

From the program’s final output, it is easy to see that the implementation class of this proxy object is Lee.Chinese? EnhancerByCGLIB? 4bD097D9, this is the proxy class generated by CGLIB in exactly the same format as the previous Spring AOP proxy class.

This is the essence of Spring AOP: Spring AOP uses CGLIB to dynamically generate proxy objects, which are called AOP proxies, and AOP proxies’ methods enhance target methods by dynamically weaving enhancement processing into target object pointcuts.

summary

AOP is widely used to deal with cross-cutting system-level services. AOP is a nice complement to OOP, allowing developers to deal with cross-cutting services in a more elegant way. Either AOP implementation, AspectJ or Spring AOP, needs to generate an AOP proxy class on the fly. The only difference is when to generate an AOP proxy class: AspectJ provides better performance by using compile-time generation of AOP proxy classes, but requires a specific compiler for processing; Spring AOP, on the other hand, uses runtime generation of AOP proxy classes, so there is no need to use a specific compiler for processing. Because Spring AOP needs to generate an AOP proxy at every run time, performance is slightly worse.

On the topic

  • Li Gang edited “Crazy Java handout”, this book comprehensively introduces the Java language itself related knowledge.
  • Li Gang compiled lightweight Java EE Enterprise Application Practice (Third Edition). This book comprehensively introduces the knowledge of Struts 2.2, Spring 3.0 and Hibernate 3.6 integrated development, and introduces the application of the three frameworks in practical projects through practical cases.
  • Spring Framework Reference Documentation Java is a comprehensive introduction to the Spring Framework features and usage.
  • Spring JavaDoc is a reference document that describes the functions and usages of all the Spring 3.0 apis.
  • DeveloperWorks Java Technology zone: There are hundreds of articles on all aspects of Java programming.