AOP:【动态代理】
指在程序运行期间动态的将某段代码切入到指定方法位置进行运行的编程方式
1、导入aop模块:Spring AOP: (Spring-aspects)
2、创建一个业务逻辑类(MathCalculator):在业务逻辑运行的时候将日志进行打印(方法运行之前,方法运行之后,异常,返回)
3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到那一步,然后执行;
通知方法:
前置通知(@Begore):logStart:在目标方法(div)运行之前运行
后置通知(@After):logEnd:在目标方法(div)运行结束之后运行
返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
异常通知(@AfterThrowing):logException :在目标方法(div)出现异常以后运行
环绕通知(@Around):动态代理,手动代理,手动推进目标方法运行(joinPoint.procced())
4、给切面类的目标方法何时何地运行(就是标注注解)
5、将切面类和业务逻辑类(目标方法类)都加入到容器中;
6、必须告诉spring那个是切面类,只需要在切面类加上一个注解@Aspect
7、给配置类中加@EnableAspectJAutoProxy【开启基于注解的aop模式】
在spring中很多的@EnableXXX;
第一步:环境搭建需要的依赖
<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.yu</groupId>
<artifactId>spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!--可以在spring官网看最新版本 https://spring.io/projects/spring-framework#learn-->
<!-- 用最新的spring5 2019年10月5日 21:21:39最新版 -->
<spring.version>5.2.0.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.16.RELEASE</version>
</dependency>
<!--spring 核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring web包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- springMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>
<!--jstl for jsp page-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency> -->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt
import org.aspectj.lang.annotation.Aspect
用于@Aspect
-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver
Aspect的依赖包
-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
</dependencies>
</project>
第二步:编写一个业务逻辑类MathCalculator
package com.condition;
public class MathCalculator {
public MathCalculator(){}
//除法的业务逻辑
public int div(int i,int j){
System.out.println("运行除法方法。div。。");
return i/j;
}
}
第三步:定义一个日志切面类LogAspects
package com.condition;
import java.util.Arrays;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
//@Aspect 告诉容器这是一个切面类
@Aspect
public class LogAspects {
@Pointcut("execution(public int com.condition.MathCalculator.*(..))")
public void pubv(){}
@Before("pubv()")
public void logStart(JoinPoint joinPoint){
Object[] objects = joinPoint.getArgs();
System.out.println("在目标方法.."+joinPoint.getSignature().getName()+"..执行前执行参数表:{"+Arrays.asList(objects)+"}");
}
@After("pubv()")
public void logEnd(JoinPoint joinPoint){
System.out.println("在目标方法.."+joinPoint.getSignature().getName()+"..执行后执行logEnd()方法");
}
@AfterReturning(value="pubv()",returning="object")
public void logReturn(JoinPoint joinPoint,Object object){
System.out.println("在目标方法.."+joinPoint.getSignature().getName()+"..返回时执行..{"+object+"}");
}
@AfterThrowing(value="pubv()",throwing="exception")
public void logException(JoinPoint joinPoint,Exception exception){
System.out.println("在目标方法.."+joinPoint.getSignature().getName()+"..抛出异常时执行..{"+exception+"}");
}
}
第四步:将切面类和业务逻辑类(目标方法类)都加入到容器中
package com.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import com.condition.LogAspects;
import com.condition.MathCalculator;
@Configuration //告诉容器这是注解类
@EnableAspectJAutoProxy //告诉容器开启aop注解模式
public class MianConfig3 {
@Bean
public MathCalculator mathCalculator(){
return new MathCalculator();
}
@Bean
public LogAspects getLogAspects(){
return new LogAspects();
}
}
第五步:测试
package com;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.condition.MathCalculator;
import com.config.MianConfig3;
public class DemoTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MianConfig3.class);
MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
mathCalculator.div(1, 1);
//关闭容器
applicationContext.close();
}
}
总结:
三步:
1、将业务逻辑组件和切面类都加入到容器中;告诉Spring那个是切面类(@Aspect)
2、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
3、开启基于注解的aop模式;@EnableAspectJAutoProxy