版权声明:Unruly https://blog.csdn.net/weixin_41660948/article/details/86606667
文章目录
一、声明式:Spring_OOP和AOP
使用maven引入:AOP需要在IOC的基础上进行添加
<dependencies>
<!-- 第一个会为程序引入基础的IOC和AOP核心包,第二个需要单独添加 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
</dependencies>
1、OOP和AOP的关系
AOP: aspect oriented programming 面向切面编程 (处理横向)
OOP: obkect orented programming 面向对象编程 (处理纵向)
- OOP和AOP的关系,互为补充。
- OOP和AOP没有谁厉害,谁不厉害。
- 不能说AOP是OOP的替代品。
- 无代码侵入性(即不需要修改原有的代码)。
- 实现原理:代理模式(代理)。
2、具体什么是AOP
面向切面编程,指扩展功能不修改源代码,将功能代码从业务逻辑代码中分离出来。
主要功能: 日志纪录、性能统计、安全控制、事务处理、异常处理等等。。
- 本质上就是方法拦截;相当于拦截器。
- 能够在方法执行之前,或者方法执行之后,自动完成某些事情(执行某些代码)。
- 拦截到方法以后,要做什么事情。(增强、通知、advice)
- 哪些方法会被拦截(即拦截的面有多大)
AOP特点: 采用横向抽取机制,代替传统纵向继承体系重复性代码,从而能更好的对方法进行扩展、复用、增加了灵活性。
织入: weaving(把通知和拦截的目标对象组织起来的过程)
说白了就是在什么地方什么方法进行了什么操作的过程。连接点: joinpoint(连接点可以是调用方法时、抛出异常时、甚至修改字段时。)
切入点: pointcut(说白了就是在哪些包下的哪些类的哪些方法,会被拦截。)
通知: advice(在什么时候拦截,拦截后做什么事情)
切面: aspect(切入点和通知的结合 、形成切面 – 注意引入委托类)
3、Spring_expression表达式
expression: 表达式,下面的是表达式编写语法规则:
execution(访问修饰符 返回值类型 方法名(参数列表)声明抛出异常的类型)
execution(public * add(*) )
注意:
- 返回值类型、方法名、参数是不可以省略的组成部分。
- 省略不写的部分,表示不做要求。
- 可以带上包名,对指定的包下的指定类进行拦截;方法名也可以使用通配符
execution(* com.dao.*.add*(..) )
- 可以对包下的子包进行拦截,用两个点表示。
execution(* com.dao..*.*(..))
注意:注意理解环绕通知;理解了环绕通知,也就知道了其他通知;其他类型的通知使用JoinPoint对象
二、注解型AOP
1.注解和xml的区别:
— XML AOP配置方式为Spring自带的方式。
— 注解 AOP配置方式为Spring引用Aspect。
<!-- 必须开启Aspectj的支持,并且扫描该aop包 -->
<context:component-scan base-package="com.dao,com.biz,com.advice"/>
<aop:aspectj-autoproxy/>
package aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
* 描述:用于日志切面记录
* @author Unruly
* @ClassName LogAop
* @create 2019-01-21 14:40
*/
@Aspect
@Component
public class LogImplAop {
private static Logger logger = Logger.getLogger(LogImplAop.class);
@Around("execution(* service..*.*(..))")
public Object around(ProceedingJoinPoint proceed) {
logger.info("程序执行开始 -------");
Object[] obj = proceed.getArgs();
for (Object anObj : obj) {
logger.info("参数:" + anObj);
}
Object result = null;
try {
logger.debug("目标类:" + proceed.getTarget());
logger.debug("方法名:" + proceed.getSignature().getName());
result = proceed.proceed(obj);
logger.debug("返回值:"+result);
} catch (Throwable e) {
logger.error("发生异常、错误信息:" + e.getMessage());
} finally {
logger.info("程序执行结束 -------");
logger.info("\n");
}
return result;
}
}
2.注解方式进行AOP切面编程总结:
/*
*
* 1.切面类需要添加两个注解
* @Aspect : 表示为AOP类
* @Component : 将此类交给Spring托管。
*
* 2.配置文件开启注解扫描,和对@AspectJ的支持。
* <aop:aspectj-autoproxy/> // @AspectJ支持
* <context:component-scan base-package="biz,advice"/>
*
* 环绕通知:重点理解包含(前置、后置、异常、最终);
* 1.环绕通知因为包含全面使用ProceedingJoinPoint对象,其余使用JoinPoint对象;
*
* 2.proceed()方法表示放行方法,此方法底层采用动态代理,实际上表示的为我们拦截到的方法。
* (说白了就是你拦截到的方法就是这个方法,只是方法名字换了而已。)
*
* 3.获取方法参数Object [] result = proceed.getArgs();
* 4.有参数则将获取的参数传入proceed(result);
*
* 5.环绕通知的组成:
* 在调用proceed()之前执行的操作 -- 前置通知
* 在调用proceed()之后执行的操作 -- 后置通知 (try)
* 在调用proceed()后执行发生异常 -- 异常通知 (catch)
* 在调用proceed()后包含在最终块 -- 最终通知 (finally)
*
* 还可以使用@Pointcut注解添加到类上定义一个全局的切入点
* @Pointcut("execution(* aop.dao.BillDao.*(..))")
* public void PointCut(){}
*
* 其余比如:
* -- 前置
* @Before("execution(PointCut())")
* public void before(){}
*
* -- 后置
* @After("execution(PointCut())")
* public void after(){}
*
* -- 后置返回
* @AfterReturning(pointcut = "PointCut()",returning = "result")
* public void AfterReturning(JoinPoint point,Object result){}
*
* -- 异常
* @AfterThrowing(pointcut = "PointCut()",throwing = "e")
* public void AfterThrowing(JoinPoint point,RuntimeException e){}
*/
SpringAOP可能出现的错误!
- execution表达式写错了。
- 配置文件忘记扫描aop包,忘记加<aop:aspectj-autoproxy/>
- 如果切入点没有实现接口使用cglib库动态代理,<aop:aspectj-autoproxy proxy-target-class=“true”/>