一、为什么会出现AOP
一个场景
把大象装进冰箱分三步:
(1)、打开冰箱
(2)、把大象装进冰箱
(3)、关上冰箱
把老虎装进冰箱分三步:
(1)、打开冰箱
(2)、把老虎装进冰箱
(3)、关上冰箱
如果把1000种动物装进冰箱,还需要计时怎么办?显然不能1000个类中都加代码
交叉业务逻辑,系统级的服务 类比 打开冰箱门,关闭冰箱门
主业务逻辑 类比 把动物放进冰箱,主业务执行前后添加系统级服务,比如要加事务,打印日志
优化:
1.将xxx放到冰箱中这个过程封装成标准的过程
2.为标准过程的开始通知开始计时
3.为标准过程的结束通知结束计时
4.关闭冰箱,输出计时结果
解决的几种思路方法:
1、可以写一个工具类,把重复的过程写工具类里
2、继承一个类,执行相同的方法
3、动态代理解决
4、AOP
AOP底层就是通过动态代理实现的。(JDK动态代理,CGLIB动态代理)
即通过一定手段将不同服务的公共的纵向处理逻辑提取出来,统一实现。
二、AOP是什么
AOP是面向切面编程,它是一种思想。交叉业务逻辑,系统级的服务是切面。把切面加入到主业务逻辑的过程就是织入。
连接点:可以被切面织入的方法,通常业务接口的方法都是连接点。final方法不能是连接。
切入点:具体被织入的方法就是切入点。
目标对象:别增强的对象,主业务逻辑类的对象
通知Advice通知是切面的一种实现,定义切入的时间
顾问Advisor顾问是切面的另一种实现,包装了通知,能够将通知以更为复杂的方式织入的目标对象。
可以说是OOP面向对象编程的一种完善和补充。面向对象更多的操作是纵向的(继承,接口),这就导致一些需要在横向上(即业务代码方法中的前后)嵌入的非核心代码得在每一个方法上都要去写(比如日志,权限,异常处理等)。它们散布在各方法的横切面上,造成代码重复,也不利于各个模块的重用。
AOP就是为了解决这种难题而生的。在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
三、AOP能做什么
1、降低模块之间的耦合度
2、使系统容易扩展
3、避免修改业务代码,避免引入重复代码,更好的代码复用
四、AOP怎么用
/* 前置通知:某方法调用之前发出通知。 后置通知:某方法完成之后发出通知 返回后通知:方法正常返回后,调用通知。在方法调用后,正常退出发出通知 异常通知:抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行 的通知。在方法调用时,异常退出发出通知 环绕通知:通知包裹在被通知的方法的周围知。 */
@Aspect
@Component
public class LogAspect {
private static final Logger logger=LoggerFactory.getLogger(LogAspect.class);
@Before("execution(* com.hbu.toutiao.controller.SettingController.*(..))")
public void beforeMethod(JoinPoint joinPoint){
logger.info("方法执行之前");
}
@AfterReturning(value="execution(* com.hbu.toutiao.controller.SettingController.*(..))",returning = "result")
public Object afterReturn(Object result){
logger.info("执行返回后通知");
return result+"返回后通知";
}
@After("execution(* com.hbu.toutiao.controller.SettingController.*(..))")
public void afterMethod(){
logger.info("执行后置通知方法执行之后");
}
@Around("poincut()")
public Object Around(ProceedingJoinPoint pjp) throws Throwable {
logger.info("环绕执行之前");
Object o=pjp.proceed();
logger.info("环绕执行之后"+o);
o="环绕通知:"+o;
return o;
}
@AfterThrowing(value = "execution(* com.hbu.toutiao.controller.SettingController.*(..))",throwing = "ex")
public void exceptinMethod(Exception ex){
logger.info("发生了异常"+ex.getMessage());
}
//定义一个切入点
@Pointcut(value="execution(* com.hbu.toutiao.controller.SettingController.around(..))")
public void poincut(){
}
}
参考链接:
https://blog.csdn.net/zhaoenweiex/article/details/78177481