AOP
指在程序运行期间动态的将某段代码切入到指定方法位置进行运行的编程方式
静态代理:需要事先写好代理类,缺点是每个业务类度需要一个代理类,不灵活
动态代理:运行时动态生成代理类。缺点生成代理类和调用方法需要额外花费时间
JDK动态代理:基于Java反射机制,必须要实现接口的业务类才能用这种方法生成代理类。
cglib动态代理:基于ASM机制实现,通过生成业务类的子类作为代理类
AOP当中的概念:
1、切入点(Pointcut):在哪些类,哪些方法上切入(where);
2、增强(Advice):早期翻译为通知,在方法执行的什么时机(when:方法前/方法后/方法前后)做什么(what:增强的功能);
3、切面(Aspect):切面=切入点+通知,通俗点就是:什么时机,什么地点,做什么!
4、织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)。
步骤:
1.导入aop模块:spring-aspects依赖
2.定义一个业务逻辑类(MathCaculator);在运行时将日志打印
3.定义一个日志切面类(LogAspects);切面类的方法需要动态感知MathCaculator里的方法运行到哪里了,然后执行
通知方法:
前置通知(@Before):在目标方法运行之前运行
后置通知(@After):在目标方法运行结束后运行。无论方法正常还是异常
返回通知(@AfterReturning):在目标方法正常返回之后运行
异常通知(@@AfterThrowing):在目标方法出现异常之后运行
环绕通知(@Around):在目标方法执行前和执行后执行
4.通知注解,告诉切面类在何时何地切入
5.然后把切面类和业务逻辑类加入容器
6.告诉spring哪个是切面类(给切面类贴上@Aspect)
7.给配置类贴上@EnableAspectJAutoProxy【开启基于注解的AOP模式】
例子:
@Component
public class MathCaculator {
public int calculator(int i, int j) {
System.out.println("MathCaculator.calculator()");
return i/j;
}
}
切面类
@Aspect//切面类
public class LogAspects {
@Pointcut("execution(public int com.zxc.aop.MathCaculator.calculator(..))")
public void pointCut() {}
//前置通知
@Before("pointCut()")
public void logStart(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
System.out.println("@Before.."+joinPoint.getSignature().getName()+"方法参数{"+args+"}");
}
//后置通知,出现异常也会调用
@After("pointCut()")
public void logEnd() {
System.out.println("@After..");
}
//返回通知
@AfterReturning(value="pointCut()",returning="obj")
public void logReturn(Object obj) {
System.out.println("@AfterReturning.."+"LogAspects.logReturn()..返回值:"+obj);
}
//异常通知
//注意JoinPoint一定要出现在 参数表第一位,不然异常
@AfterThrowing(value="pointCut()",throwing="e")
public void logException(JoinPoint joinPoint,Exception e) {
System.out.println("@AfterThrowing.."+joinPoint.getSignature().getName()+"LogAspects.logException()..异常信息"+e);
}
}
配置类,将切面类和业务逻辑类都加入到容器中,给配置类加 @EnableAspectJAutoProxy 注解
@Configuration
@EnableAspectJAutoProxy//开启基于注解的AOP模式
public class MainConfigOfAop {
@Bean
public MathCaculator mathCal() {
return new MathCaculator();
}
@Bean
public LogAspects logAspects() {
return new LogAspects();
}
}
测试
@Test
public void test1() throws Exception {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MainConfigOfAop.class);
MathCaculator bean = ac.getBean(MathCaculator.class);
bean.calculator(2, 0);
}
结果
@Before..calculator方法参数{[Ljava.lang.Object;@63070bab}
MathCaculator.calculator()
@After..
@AfterThrowing..calculatorLogAspects.logException()..异常信息java.lang.ArithmeticException: / by zero
xml开启基于注解的AOP模式
<aop:aspectj-autoproxy/>