Table of contents
1. Spring AOP based on XML configuration
2. Use annotations to configure AOP
3. AspectJ point-cut function
4. AspectJ notification notes
5. Zero configuration to implement Spring IoC and AOP
AOP (Aspect Oriented Programming) is a technology that implements horizontal multi-module unified control of program functions through precompilation methods and dynamic agents during runtime. AOP is a supplement to OOP and an important part of the spring framework. The various parts of the business logic can be isolated by using AOP, thereby reducing the coupling between the various parts of the business logic, improving the reusability of the program, and improving the efficiency of development. AOP can be divided into static weaving and dynamic weaving. Static weaving means writing the content to be weaving into the target module before compilation, which is very costly. Dynamic weaving does not require changing the target module. Spring framework implements AOP, and using annotation to configure AOP is more convenient and intuitive than using XML configuration.
1. Spring AOP based on XML configuration
Before explaining the annotation to implement the AOP function, first use the previous learning to configure the Spring AOP function using XML, so that it is for comparison and better understanding.
1.1. Create a new Maven project and add a reference. The project's pom.xml file is as follows:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zhangguo</groupId> <artifactId>Spring052</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Spring052</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.0.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> <version>4.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.4</version> </dependency> </dependencies></project>1.2. Create the Math class to be proxyed, the code is as follows:
package com.zhangguo.Spring052.aop01;/** * Target class being proxyed*/public class Math{ //Add public int add(int n1,int n2){ int result=n1+n2; System.out.println(n1+"+"+n2+"="+result); return result; } //Due to public int sub(int n1,int n2){ int result=n1-n2; System.out.println(n1+"-"+n2+"="+result); return result; } //Multiply public int mut(int n1,int n2){ int result=n1-n2; System.out.println(n1+"-"+n2+"="+result); return result; } //Multiply public int mut(int n1,int n2){ int result=n1*n2; System.out.println(n1+"X"+n2+"="+result); return result; } //Except public int div(int n1,int n2){ int result=n1/n2; System.out.println(n1+"/"+n2+"="+result); return result; }}1.3. Edit the notification class Advices.Java code that needs to be used in AOP is as follows:
package com.zhangguo.Spring052.aop01;import org.aspectj.lang.JoinPoint;/** * Notification class, cross-cut logic* */public class Advices { public void before(JoinPoint jp){ System.out.println("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------1.4. Configure the XML file required for container initialization. The content of the aop01.xml file is as follows:
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- proxy object --> <bean id="math"></bean> <!-- notification--> <bean id="advices"></bean> <!-- aop configuration--> <aop:config proxy-target-class="true"> <!-- section--> <aop:aspect ref="advices"> <!-- point--> <aop:pointcut expression="execution(* com.zhangguo.Spring052.aop01.Math.*(..))" id="pointcut1"/> <!--Connect notification method and point-cut--> <aop:before method="before" pointcut-ref="pointcut1"/> <aop:after method="after" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config></beans>
1.5. Test code Test.java is as follows:
package com.zhangguo.Spring052.aop01;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("aop01.xml"); Math math = ctx.getBean("math", Math.class); int n1 = 100, n2 = 5; math.add(n1, n2); math.sub(n1, n2); math.mut(n1, n2); math.div(n1, n2); }}Running results:
2. Use annotations to configure AOP
2.1. In the previous example, modify the proxy class Math. In order to implement IOC scanning, @Service is annotated on the Math class and named the bean as math. It is equivalent to adding a bean to the xml configuration file in the previous example, <!-- proxy object--><bean id="math"></bean>, and the code of the Math class is as follows:
package com.zhangguo.Spring052.aop02;import org.springframework.stereotype.Service;/** * Target class being proxyed*/@Service("math")public class Math{ //Add public int add(int n1,int n2){ int result=n1+n2; System.out.println(n1+"+"+n2+"="+result); return result; } //Substitute public int sub(int n1,int n2){ int result=n1-n2; System.out.println(n1+"-"+n2+"="+result); return result; } //Multiple public int mut(int n1,int n2){ int result=n1*n2; System.out.println(n1+"X"+n2+"="+result); return result; } //Disin public int div(int n1,int n2){ int result=n1/n2; System.out.println(n1+"/"+n2+"="+result); return result; }}2.2. Modify the notification class Advices, there are 3 annotations in the code. @Component means that the instance of this class will be managed by the Spring IOC container; @Aspect means that a section is declared; @Before means that before is a pre-notification, and a point is declared through the parameter execution. The Advices.java code is as follows:
package com.zhangguo.Spring052.aop02;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.stereotype.Component;/** * Notification class, cross-cut logic* */@Component@Aspectpublic class Advices { @Before("execution(* com.zhangguo.Spring052.aop02.Math.*(..))") public void before(JoinPoint jp){ System.out.println("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------The above code is basically the same as the following configuration
<!-- Notifications--> <bean id="advices"></bean> <!-- aop configuration--> <aop:config proxy-target-class="true"> <!-- Section--> <aop:aspect ref="advices"> <!-- Point--> <aop:pointcut expression="execution(* com.zhangguo.Spring052.aop01.Math.*(..))" id="pointcut1"/> <!-- Connect notification method and point--> <aop:before method="before" pointcut-ref="pointcut1"/> <aop:after method="after" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config>
2.3. Added the configuration file aop02.xml, and added the aop:aspectj-autoproxy node on the basis of configuring the IOC. The Spring framework will automatically create a proxy for the beans configured with AspectJ. The proxy-target-class="true" attribute indicates that the target object being proxy is a class, not a class that implements the interface, mainly to select different proxy methods.
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <context:component-scan base-package="com.zhangguo.Spring052.aop02"> </context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy></beans>
2.4. Test run code Test.java is as follows:
package com.zhangguo.Spring052.aop02;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("aop02.xml"); Math math = ctx.getBean("math", Math.class); int n1 = 100, n2 = 5; math.add(n1, n2); math.sub(n1, n2); math.mut(n1, n2); math.div(n1, n2); }}Running results:
3. AspectJ point-cut function
The tangent function can be positioned to an accurate transverse logical position. In the previous example, we have only used execution(* com.zhangguo.Spring052.aop02.Math.*(..)). execution is a tangent function, but the function is only at one level. If the range we want to weave is a class or annotation, the execution will not be so easy to use. In fact, there are 9 tangent functions in total, which have different targeting.
@AspectJ uses AspectJ's special point-cut expression to describe the section. The AspectJ expressions supported by Spring can be divided into four categories:
Method point-cut function: defines connection points by describing the target class method information.
Method parameter point-cut function: defines connection points by describing the parameter information of the target class method.
Target class point-cut function: defines connection points by describing the target class type information.
Agent class point-cut function: defines connection points by describing the proxy class information.
Common AspectJ expression functions:
The most commonly used point-cut function is: execution(<modifier mode>?<return type mode><method name mode>(<parameter mode>)<exception mode>?) point-cut function, which can meet most needs.
In order to show the functions of each point tangent function, a new class StrUtil is now added, the class is as follows:
package com.zhangguo.Spring052.aop03;import org.springframework.stereotype.Component;@Component("strUtil")public class StrUtil { public void show(){ System.out.println("Hello StrUtil!"); }}The test code is as follows:
package com.zhangguo.Spring052.aop03;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("aop03.xml"); IMath math = ctx.getBean("math", Math.class); int n1 = 100, n2 = 5; math.add(n1, n2); math.sub(n1, n2); math.mut(n1, n2); math.div(n1, n2); StrUtil strUtil=ctx.getBean("strUtil",StrUtil.class); strUtil.show(); }}3.1. The execution of the point-cut function, the definition of notification and section is as follows:
package com.zhangguo.Spring052.aop03;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.stereotype.Component;/** * Notification class, cross-cut logic* */@Component@Aspectpublic class Advices { @Before("execution(* com.zhangguo.Spring052.aop03.Math.*(..))") public void before(JoinPoint jp){ System.out.println("---------------------------------"); System.out.println(jp.getSignature().getName()); } //execution point-cut function // all methods of all classes under com.zhangguo.Spring052.aop03 package are cut into @After("execution(* com.zhangguo.Spring052.aop03.*.*(..))") public void after(JoinPoint jp){ System.out.println("-----------------------------------"); }}The operation results are as follows:
execution(<modifier mode>?<return type mode><method name mode>(<parameter mode>)<exception mode>?)
3.2. The point-cut function within
//within point-cut function//com.zhangguo.Spring052.aop03 package all methods of all classes are cut into @After("within(com.zhangguo.Spring052.aop03.*)") public void after(JoinPoint jp){ System.out.println("--------------------------------------------------"); }3.3. This point-cut function
//this point-cut function//Implements any connection point of the proxy object of the IMath interface @After("this(com.zhangguo.Spring052.aop03.IMath)") public void after(JoinPoint jp){ System.out.println("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------3.4. args point-cut function
//args point-cut function//Requires that the method has two int type references before it will be weaved into the cross-cutting logic @After("args(int,int)") public void after(JoinPoint jp){ System.out.println("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- If the parameter type is not the base data type, the package name is required.
3.5. @annotation point-cut function
First customize an annotation that can be annotated on the method
package com.zhangguo.Spring052.aop03;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MyAnno {} //@annotation point-cut function//Require the method must be annotated com.zhangguo.Spring052.aop03.MyAnno to be weaved into the transverse cut logic @After("@annotation(com.zhangguo.Spring052.aop03.MyAnno)") public void after(JoinPoint jp){ System.out.println("-------------------------------"); } package com.zhangguo.Spring052.aop03;import org.springframework.stereotype.Component;@Component("strUtil")public class StrUtil { @MyAnno public void show(){ System.out.println("Hello StrUtil!"); }}Running results:
Other point-cutting functions with @ are for annotation
4. AspectJ notification notes
AspectJ notification annotations have 6, 5 are commonly used, and less introductions are used.
First solve the problem of defining point tangent multiplexing, as shown in the following code, the content of the point tangent function is exactly the same:
package com.zhangguo.Spring052.aop04;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.stereotype.Component;/** * Notification class, cross-cut logic* */@Component@Aspectpublic class Advices { @Before("execution(* com.zhangguo.Spring052.aop04.Math.*(..))") public void before(JoinPoint jp){ System.out.println("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------You can first define a tangent and then multiplex it as follows:
package com.zhangguo.Spring052.aop04;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;/** * Notification class, cross-cut logic*/@Component@Aspectpublic class Advices { //切点@Pointcut("execution(* com.zhangguo.Spring052.aop04.Math.*(..))") public void pointcut(){ } @Before("pointcut()") public void before(JoinPoint jp){ System.out.println("----------前置通知----------"); System.out.println(jp.getSignature().getName()); } @After("pointcut()") public void after(JoinPoint jp){ System.out.println("-----------------------------------"); }}Modify the Advices.java file and add various notification types as follows:
package com.zhangguo.Spring052.aop04;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;/** * Notification class, cross-cut logic*/@Component@Aspectpublic class Advices { //Cut point @Pointcut("execution(* com.zhangguo.Spring052.aop04.Math.a*(..))") public void pointcut(){ } //Pre-Notice @Before("pointcut()") public void before(JoinPoint jp){ System.out.println(jp.getSignature().getName()); System.out.println("--------------------------------------------------"); } // Final notification @After("pointcut()") public void after(JoinPoint jp){ System.out.println("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Throwable{ System.out.println(pjp.getSignature().getName()); System.out.println("---------------------------------------------"); Object result=pjp.proceed(); System.out.println("---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- afterReturning(JoinPoint jp,Object result){ System.out.println(jp.getSignature().getName()); System.out.println("Result is: "+result); System.out.println("----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- System.out.println(jp.getSignature().getName()); System.out.println("Exception message: "+exp.getMessage()); System.out.println("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Running results:
5. Zero configuration to implement Spring IoC and AOP
In order to achieve zero configuration, based on the original example, we add a new User-like class as shown below:
package com.zhangguo.Spring052.aop05;public class User { public void show(){ System.out.println("A user object"); }}This class is not annotated and the container will not be automatically managed. Since there is no xml configuration file, use one as configuration information, and the ApplicationCfg.java file is as follows:
package com.zhangguo.Spring052.aop05;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration //Configuration class used to represent the current class as a container, similar to <beans/>@ComponentScan(basePackages="com.zhangguo.Spring052.aop05") //The scan range is equivalent to the node of the xml configuration <context:component-scan/>@EnableAspectJAutoProxy(proxyTargetClass=true) //Auto proxy, equivalent to <aop:aspectj-autopproxy proxy-target-class="true"></aop:aspectj-autopproxy>public class ApplicationCfg { //Declare a bean in the configuration, equivalent to <bean id=getUser/> @Bean public User getUser(){ return new User(); }}Each part of this class basically has a one-to-one relationship with the xml configuration. Please see the comments. This is more convenient than writing xml, but it is inconvenient to modify it after publishing. The test code is as follows:
package com.zhangguo.Spring052.aop05;import org.springframework.context.ApplicationContext;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test { public static void main(String[] args) { // Initialize containers through class ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationCfg.class); Math math = ctx.getBean("math", Math.class); int n1 = 100, n2 = 0; math.add(n1, n2); math.sub(n1, n2); math.mut(n1, n2); try { math.div(n1, n2); } catch (Exception e) { } User user=ctx.getBean("getUser",User.class); user.show(); }} advices.java is the same as above, without any changes, the running result is as follows:
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.