1. Preface
In previous projects, I rarely paid attention to the specific implementation and theory of spring aop. I just briefly understood what aop is and how to use it. I saw a blog post that was well written, so I came to learn it.
AOP
AOP (Aspect Oriented Programming), that is, aspect-oriented programming, can be said to be a supplement and improvement of OOP (Object Oriented Programming). OOP introduces concepts such as encapsulation, inheritance, and polymorphism to establish an object hierarchy that is used to simulate a collection of public behavior. However, OOP allows developers to define vertical relationships, but is not suitable for defining horizontal relationships, such as logging functions. Log code is often scattered horizontally in all object levels, and has nothing to do with the core functions of the corresponding object. This kind of unrelated code scattered everywhere is called cross cutting. In OOP design, it causes a large amount of code duplication, which is not conducive to the reuse of each module.
AOP technology, on the contrary, uses a technique called "crosscutting" to dissect the inside of an encapsulated object and encapsulate those common behaviors that affect multiple classes into a reusable module and name it "Aspect", which is the facet. The so-called "section" is simply encapsulated by logic or responsibilities that are not related to the business but are called jointly by the business module, which is convenient for reducing the system's duplicate code, reducing the coupling between modules, and conducive to future operability and maintainability.
Using the "crosscutting" technology, AOP divides the software system into two parts: core concern and cross-cutting concern. The main process of business processing is the core focus, and the part that has little to do with it is the cross-sectional focus. One feature of cross-cutting concerns is that they often occur in multiple core concerns, and are basically similar in various places, such as permission authentication, logs, and things. The role of AOP is to separate various concerns in the system and separate the core concerns from cross-cutting concerns.
AOP core concept
1. Cross-cut attention points
Which methods to intercept and how to deal with it after interception? These concerns are called cross-cutting concerns
2. Section (aspect)
Classes are abstractions of objects' features, and sections are abstractions of cross-cutting concerns
3. Joinpoint
The intercepted point, because Spring only supports method-type connection points, so the connection point in Spring refers to the method intercepted. In fact, the connection point can also be a field or a constructor.
4. Pointcut
Definition of intercepting connection points
5. Notification (advice)
The so-called notification refers to the code to be executed after intercepting the connection point. Notifications are divided into five categories: pre-set, post-set, exception, final, and surrounding notifications.
6. Target object
The target object of the proxy
7. Weave
The process of applying a slit to a target object and causing proxy object creation
8. Introduction
Without modifying the code, the introduction can dynamically add some methods or fields to the class during the runtime period
Spring's support for AOP
The AOP agent in Spring is responsible for generation and management of Spring's IOC container, and its dependencies are also managed by the IOC container. Therefore, the AOP proxy can directly target other bean instances in the container, and this relationship can be provided by dependency injection of the IOC container. The rules for creating a proxy in Spring are:
1. By default, Java dynamic proxy is used to create AOP proxy, so that you can create proxy for any interface instance.
2. When the class that needs a proxy is not a proxy interface, Spring will switch to using CGLIB proxy, and it can also force CGLIB to use.
AOP programming is actually a very simple thing. Looking at AOP programming, programmers only need to participate in three parts:
1. Define ordinary business components
2. Define the entry point, one entry point may cross-cut multiple business components
3. Define enhanced processing. Enhanced processing is the processing action that is weaved into ordinary business components in the AOP framework.
Therefore, the key to AOP programming is to define entry point and define enhancement processing. Once the appropriate entry point and enhancement processing are defined, the AOP framework will automatically generate an AOP proxy, that is, the method of proxy object = enhancement processing + method of proxy object.
Here is a Spring AOP .xml file template named aop.xml, and the subsequent contents are expanded on aop.xml:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> </beans>
Simple implementation of AOP based on Spring
Note that before explaining, let me explain: To successfully run the code, it is not enough to use the jar package provided by Spring to the developer. Please download two jar packages online:
1. aopalliance.jar
2. aspectjweaver.jar
Let’s start explaining the XML implementation method of Spring AOP, first define an interface:
public interface HelloWorld{ void printHelloWorld(); void doPrint();} Define two interface implementation classes:
public class HelloWorldImpl1 implements HelloWorld{ public void printHelloWorld() { System.out.println("Enter HelloWorldImpl1.printHelloWorld()"); } public void doPrint() { System.out.println("Enter HelloWorldImpl1.doPrint()"); return ; }} public class HelloWorldImpl2 implements HelloWorld{ public void printHelloWorld() { System.out.println("Enter HelloWorldImpl2.printHelloWorld()"); } public void doPrint() { System.out.println("Enter HelloWorldImpl2.doPrint()"); return ; }} Cross-cutting focus, here is the printing time:
public class TimeHandler{ public void printTime() { System.out.println("CurrentTime = " + System.currentTimeMillis()); }} With these three classes, you can implement a simple Spring AOP. Take a look at the configuration of aop.xml:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <bean id="helloWorldImpl1" /> <bean id="helloWorldImpl2" /> <bean id="timeHandler" /> <aop:config> <aop:aspect id="time" ref="timeHandler"> <aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" /> <aop:before method="printTime" pointcut-ref="addAllMethod" /> <aop:after method="printTime" pointcut-ref="addAllMethod" /> </aop:aspect> </aop:config></beans>
Write a main function to call it:
public static void main(String[] args){ ApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml"); HelloWorld hw1 = (HelloWorld)ctx.getBean("helloWorldImpl1"); HelloWorld hw2 = (HelloWorld)ctx.getBean("helloWorldImpl2"); hw1.printHelloWorld(); System.out.println(); hw1.doPrint(); System.out.println(); System.out.println(); hw2.printHelloWorld(); System.out.println(); hw2.doPrint();} The running result is:
CurrentTime = 1446129611993Enter HelloWorldImpl1.printHelloWorld()CurrentTime = 1446129611993CurrentTime = 1446129611994Enter HelloWorldImpl1.doPrint()CurrentTime = 1446129611994CurrentTime = 1446129611994Enter HelloWorldImpl2.printHelloWorld()CurrentTime = 1446129611994CurrentTime = 1446129611994Enter HelloWorldImpl2.doPrint()CurrentTime = 1446129611994
I saw that all methods of the two implementation classes of HelloWorld interface have been added to the proxy, and the proxy content is the printing time.
Additional details on Spring-based AOP usage
1. Add a cross-cutting concern and print the log. The Java class is:
public class LogHandler{ public void LogBefore() { System.out.println("Log before method"); } public void LogAfter() { System.out.println("Log after method"); }}<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <bean id="helloWorldImpl1" /> <bean id="helloWorldImpl2" /> <bean id="timeHandler" /> <bean id="logHandler" /> <aop:config> <aop:aspect id="time" ref="timeHandler" order="1"> <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.*(..))" /> <aop:before method="printTime" pointcut-ref="addTime" /> <aop:after method="printTime" pointcut-ref="addTime" /> </aop:aspect> <aop:aspect id="log" ref="logHandler" order="2"> <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.*(..))" /> <aop:before method="LogBefore" pointcut-ref="printLog" /> <aop:after method="LogAfter" pointcut-ref="printLog" /> </aop:aspect> </aop:config></beans>
The test class remains unchanged, and the print result is:
CurrentTime = 1446130273734Log before methodEnter HelloWorldImpl1.printHelloWorld()Log after methodCurrentTime = 1446130273735CurrentTime = 1446130273736Log before methodEnter HelloWorldImpl1.doPrint()Log after methodCurrentTime = 1446130273736CurrentTime = 1446130273736Log before methodEnter HelloWorldImpl2.printHelloWorld()Log after methodCurrentTime = 1446130273736CurrentTime = 1446130273737Log before methodEnter HelloWorldImpl2.doPrint()Log after methodCurrentTime = 1446130273737
There are two ways to use the logHandler before the timeHandler:
(1) There is an order attribute in aspect, and the number of the order attribute is the order of cross-cutting the focus points
(2) Define the logHandler before the timeHandler. Spring uses the definition order of aspect as the weaving order by default.
2. I just want to weave some methods into the interface
Just modify the pointcut expression:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <bean id="helloWorldImpl1" /> <bean id="helloWorldImpl2" /> <bean id="timeHandler" /> <bean id="logHandler" /> <aop:config> <aop:aspect id="time" ref="timeHandler" order="1"> <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.print*(..))" /> <aop:before method="printTime" pointcut-ref="addTime" /> <aop:after method="printTime" pointcut-ref="addTime" /> </aop:aspect> <aop:aspect id="log" ref="logHandler" order="2"> <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.do*(..))" /> <aop:before method="LogBefore" pointcut-ref="printLog" /> <aop:after method="LogAfter" pointcut-ref="printLog" /> </aop:aspect> </aop:config></beans>
It means that timeHandler will only weave methods that start at the beginning of HelloWorld interface print, logHandler will only weave methods that start at the beginning of HelloWorld interface do
3. Force CGLIB to generate proxy
As mentioned earlier, Spring uses dynamic proxy or CGLIB to generate proxy. Higher versions of Spring will automatically choose whether to use dynamic proxy or CGLIB to generate proxy content. Of course, we can also force CGLIB to generate proxy, that is, there is a "proxy-target-class" attribute in <aop:config>. If this attribute value is set to true, then the class-based proxy will work. If proxy-target-class is set to false or this attribute is omitted, then the interface-based proxy will work.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.