Implementation principle of Spring AOP (ii) use Spring AOP
Like AspectJ, Spring AOP also needs to enhance the target class, that is, to generate a new AOP proxy class. Unlike AspectJ, Spring AOP does not need to use any special
The command is used to compile the Java source code. It dynamically generates a "proxy class" in the memory at runtime to generate the AOP proxy.
Spring allows the use of AspectJ Annotation for defining (Aspect), Pointcut, and Advice. The Spring framework can recognize and
Annotation to generate the AOP proxy. Spring only uses the same annotation as AspectJ 5, but does not use the AspectJ compiler or Weaver, and the underlying layer still uses
Spring AOP still dynamically generates the AOP agent at runtime, and does not depend on the AspectJ compiler or the Weaving Machine.
To put it simply, Spring still uses the dynamic proxy generated during runtime to enhance the target object, so it does not need to add additional compilation or support for AspectJ's knitting machine; and AspectJ
It is enhanced when compilation is used. Therefore, AspectJ needs to use its own compiler to compile Java files, and also needs to be woven into the machine.
To enable Spring support for @ AspectJ configuration and ensure that the target Bean in the Spring container is automatically enhanced by one or more aspects, you must configure the following in the Spring configuration file:
Fragment:
Of course, if we want to fully enable the "Zero Configuration" function of Spring, we also need to enable the "Zero Configuration" support of Spring to enable Spring to automatically search for Bean classes in the specified path.
The so-called automatic enhancement means that Spring will determine whether to enhance the specified Bean in one or more ways, and then automatically generate the corresponding proxy accordingly, so that the enhancement processing can be appropriate.
Called.
If you do not want to use Spring's XML Schema configuration method, add the following snippet to the Spring configuration file to enable @ AspectJ support.
In the configuration file above, AnnotationAwareAspectJAutoProxyCreator is a BeanPostProcessor, which will be
Bean generates the AOP proxy,
After @ AspectJ is enabled, Spring will automatically identify the Bean and use it as an Aspect as long as we configure a Bean with @ Aspect annotation in the Spring container.
Bean processing.
Bean configuration in Spring containers (that is, Bean with @ Aspect annotation) is similar to configuring common beans. Element configuration.
Use dependency injection to configure the attribute values. If we enable the "Zero Configuration" feature of Spring, we can also enable Spring to automatically search and load the Bean in the specified path.
Use @ Aspect to label a Java class, which serves as an Aspect Bean, as shown in the following code snippet:
// Use @ Aspect to define an Aspect class @ Aspect public class LogAspect {// define other content of this class ...}
Similar to other classes, you can define methods and attributes, and also include entry points and enhanced processing definitions.
After we use @ Aspect to modify a Java class, Spring will not treat this Bean as a component Bean, so the post-processing Bean responsible for automatic enhancement will skip this Bean,
The Bean is not reinforced.
During development, you do not need to worry about enhanced processing of the Aspect classes defined by @ Aspect. When the Spring container detects that a Bean class uses @ Aspect annotation, the Spring container does not
Class.
We will consider using Spring AOP to rewrite the previous example:
The following example uses a simple Chinese class to simulate the business logic component:
@ Component public class Chinese {// sayHello () public String sayHello (String name) {System. out. println ("-- The sayHello method is being executed --"); // return a simple string return name + "Hello, Spring AOP" ;}// define an eat () method public void eat (String food) {System. out. println ("I am eating:" + food );}}
After providing the Chinese class above, we assume that we also need to add transaction control and logging for each method of the Chinese class above. In this case, we can consider using Around und,
AfterReturning two types of enhancement processing.
First look at the AfterReturning enhanced processing code.
// Define an Aspect @ Aspect public class AfterReturningAdviceTest {// match org. crazyit. app. service. the execution of all classes and // methods under the impl package serves as the starting point @ AfterReturning (returning = "rvt", pointcut = "execution (* org. crazyit. app. service. impl. *. *(..)) ") public void log (Object rvt) {System. out. println ("Return Value of the target method:" + rvt); System. out. println ("log simulation function... ");}}
The above Aspect class is modified with @ Aspect, so that Spring will treat it as an Aspect Bean for processing. The bold characters in the program are specified in
All methods of all classes under the org. crazyit. app. service. impl package are woven into the log (Object rvt) method.
Let's look at the help code:
// Define an Aspect @ Aspect public class AroundAdviceTest {// match org. crazyit. app. service. the execution of all classes and // methods under the impl package serves as the starting point @ Around ("execution (* org. crazyit. app. service. impl. *. *(..)) ") public Object processTx (ProceedingJoinPoint jp) throws java. lang. throwable {System. out. println ("simulate start transaction before executing the target method... "); // execute the target method and save the returned Object rvt = jp. proceed (new String [] {"changed parameter"}); System. out. println ("simulate the end of the transaction after the target method is executed... "); return rvt +" new content ";}}
Similar to the previous AfterReturning enhancement, @ Aspect is also used to modify the previous Bean. The bold text Code specifies that
All the methods of all classes under the org. crazyit. app. service. impl package are woven into the processTx (ProceedingJoinPoint jp) Method
It should be noted that, although only AfterReturning and Around of Spring AOP are introduced here, Spring also supports Before, After,
For more details about Spring AOP programming, see the book lightweight Java EE Enterprise Application Practice.
This example uses Spring's Zero Configuration to enable Spring AOP. Therefore, the above Chinese class uses @ Component modifier, while Bean uses @ Aspect modifier.
The Advice in Bean uses @ AfterReturning and @ Around for modification respectively. Next, you only need to provide the following configuration file for Spring:
Next, we use the traditional method to obtain the chinese Bean in the Spring container and call the Bean's two methods. The program code is as follows:
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. out. println (p. sayHello ("James"); p. eat ("watermelon ");}}
From the above development process, we can see that for Spring AOP, there is nothing special about the service components and aspect beans provided by developers. Only Bean needs to use @ Aspect
. The program does not need to use special compilers or splitters for processing.
Run the above program and you will see the following execution results:
Simulate start transaction before executing the target method... -- The sayHello method is being executed. After the target method is executed, the transaction is simulated and ended... get the returned value of the target method: the modified parameter Hello, the new content simulation Logging Function of Spring AOP... the changed parameter Hello, before the new content of Spring AOP executes the target method, simulate the start of the transaction... I am eating: After the modified parameter executes the target method, it simulates and ends the transaction... return Value of the target method: null new content log simulation function...
Although the program is calling the sayHello and eat methods of the Chinese object, it is not difficult to see from the running result that the actual execution is definitely not the method of the Chinese object, but the method of the AOP proxy. 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 ());
The above code can output the implementation class of the object referenced by the p variable. When you execute the program again, you can see that the above Code generates the class
Org. crazyit. app. service. impl. Chinese $ EnhancerByCGLIB $290441d2 output. This is the implementation class of the object referenced by the p variable. This class is Spring AOP
The generated AOP proxy class. From the Class Name of the AOP proxy class, we can see that the AOP proxy class is generated by CGLIB.
If the above program is slightly modified: as long as the above business logic class Chinese class implements an arbitrary interface-this approach is more in line with the "interface-oriented programming" principle advocated by Spring. False
The program provides the following Person interface for the Chinese class, and enables the Chinese class to implement this interface:
public interface Person { String sayHello(String name); void eat(String food); }
Next, let the BeanTest class face the Person interface instead of Chinese programming. Change the BeanTest class to the following format:
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. out. println (p. sayHello ("James"); p. eat ("watermelon"); System. out. println (p. getClass ());}}
The original program is to program the Chinese language. Now, the program is changed to the Person interface programming, and the program runs again. The program running result has not changed. Just
System. out. println (p. getClass (); class $ Proxy7 will be output. This indicates that the AOP proxy is not generated by CGLIB, but by JDK dynamic proxy.
The principles of the Spring AOP framework for the AOP proxy class are as follows: if the implementation class of the target object implements the interface, Spring AOP will use the JDK dynamic proxy to generate the AOP proxy class.
The implementation class of the standard object does not implement the interface. Spring AOP will use CGLIB to generate the AOP proxy class. However, this selection process is completely transparent to developers and developers do not need to worry about it.
Spring AOP dynamically selects JDK dynamic proxy and CGLIB to generate the AOP proxy. If the target class implements the interface, Spring AOP does not need the support of CGLIB.
Provide Proxy and InvocationHandler to generate the AOP Proxy.
Spring AOP Principle Analysis
We can see from the previous introduction that the AOP proxy is actually an object dynamically generated by the AOP framework. This object can be used as the target object. The AOP proxy contains all the methods of the target object,
Methods In the AOP agent differ from the methods of the target object: The AOP method adds enhanced processing to a specific entry point and calls back the methods of the target object.
The methods contained by the AOP proxy and method 3 of the target object are shown in.
Figure 3.method of AOP proxy and method of target object
The Spring AOP proxy is generated and managed by the Spring IoC container, and its dependency is also managed by the IoC container. Therefore, the AOP proxy can directly use other Bean instances in the container.
This relationship can be provided by the dependency injection of the IoC container.
Throughout AOP programming, there are only three parts that require the participation of programmers:
Define common business components. Define an entry point. A single entry point may cross multiple business components. Define the enhancement processing. The enhancement processing is the processing action that is woven into common business components in the AOP framework.
The first part of the above three parts is the most common thing, and there is no need to explain it. The key to AOP programming is to define the starting point and enhance the definition processing. Once an appropriate cut-in is defined
For vertices and enhancements, the AOP framework will automatically generate the AOP proxy, and the methods of the AOP proxy are roughly as follows:
Proxy object method = enhanced processing + method of the proxy object
In the above business definition, it is not difficult to find that the implementation principle of Spring AOP is actually very simple: the AOP framework is responsible for dynamically generating the AOP proxy class, and the method of this proxy class is determined by Advice and
The method that calls the target object.
For the software call structure shown in Figure 2 above: When method 1, method 2, method 3 ...... When you need to call a method with the "cross-cutting" nature, the traditional approach is to manually repair
Method 1, method 2, method 3 ...... , Calling this method with the "cross-cutting" nature through code, but the scalability of this method is not good, because every time you change the code.
As a result, the AOP framework emerged, and the AOP framework could "dynamically" generate a new proxy class, which includes method 1, method 2, and method 3 ...... It also adds
Cut-off method-but this call is the responsibility of the proxy class automatically generated by the AOP framework, so it has excellent scalability. Programmers do not need to manually modify the generation of method 1, method 2, and method 3
The programmer only needs to define the starting point. The AOP proxy class generated by the AOP framework contains the new method 1, method 2, and method 3. The AOP framework determines whether to use the new method based on the starting point.
In method 1, method 2, and method 3, callback has a "cross-cutting" nature.
In short: the secret of the AOP principle lies in the dynamic generation of proxy classes.