AOP 概述
1.什么是 AOP
2. AOP 的作用及优势
作用:
在程序运行期间,不修改源码对已有方法进行增强。
优势:
减少重复代码
提高开发效率
维护方便
3 AOP 的实现方式
使用动态代理技术
4.下面是一个简单案例代码(有助于理解AOP):
IAccountService.java
/**
- @author lixiang1234
- @site www.lixiang.com
- @create 2019-09-21 15:43
*/
/**
-
账户的业务层接口
*/
public interface IAccountService {/**
- 模拟保存账户
*/
void saveAccount();
/**
- 模拟更新账户
- @param i
*/
void updateAccount(int i);
/**
- 删除账户
- @return
*/
int deleteAccount();
}
- 模拟保存账户
AccountServiceImpl.java
/**
- @author lixiang1234_李祥
- @site www.lixiang.com
- @create 2019-09-21 15:49
*/
import com.itheima.service.IAccountService;
/**
-
账户的业务层实现类
*/
public class AccountServiceImpl implements IAccountService {public void saveAccount() {
System.out.println(“执行了保存”);
}public void updateAccount(int i) {
System.out.println(“执行了更新”+i);
}public int deleteAccount() {
System.out.println(“执行了删除”);
return 0;
}
}
logger.java
/**
- @author lixiang1234_李祥
- @site www.lixiang.com
- @create 2019-09-21 15:51
*/
import org.aspectj.lang.ProceedingJoinPoint;
import java.security.PublicKey;
/**
-
用于记录日志的工具类,它里面提供了公共代码
*/
public class logger {/**
- 前置通知
/
public void beforePrintLog(){
System.out.println(“前置通知类中的printLog方法开始记录日志了。。。”);
}
/* - 后置通知
/
public void afterReturningPrintLog(){
System.out.println(“后置通知类中的afterReturningPrintLog方法开始记录日志了。。。”);
}
/* - 异常通知
/
public void afterThrowingPrintLog(){
System.out.println(“异常通知类中的agterThrowingPrintLog方法开始记录日志了。。。”);
}
/* - 最终通知
*/
public void afterPrintLog(){
System.out.println(“最终通知类中的printLog方法开始记录日志了。。。”);
}
public Object aroundPrintLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try {
Object[] args = pjp.getArgs();//得到方法运行所需的参数System.out.println("Logger类中的aroundPrintLog方法开始记录日志了。。。前置"); rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法) System.out.println("Logger类中的aroundPrintLog方法开始记录日志了。。。后置"); return rtValue; }catch (Throwable t){ System.out.println("Logger类中的aroundPrintLog方法开始记录日志了。。。异常"); throw new RuntimeException(t); }finally { System.out.println("Logger类中的aroundPrintLog方法开始记录日志了。。。最终"); }
}
} - 前置通知
bean.xml
<?xml version="1.0" encoding="UTF-8"?><!--配置spring的Ioc,把Service对象配置进来-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<!--配置Logger类-->
<bean id="logger" class="com.itheima.utils.logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切面-->
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
<aop:aspect id="logAdvice" ref="logger">
<!--配置前置通知,在切入点方法执行之前执行-->
<!--<aop:before method="beforePrintLog" pointcut-ref="pt1"></aop:before>-->
<!--配置后置通知,在切入点方法执行之后执行,它和异常通知永远只能执行一个-->
<!--<aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>-->
<!--配置异常通知,在切入点方法执行产生异常之后执行,它和后置通知永远只能执行一个-->
<!--<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>-->
<!--配置最终通知,无论切入点方法是否正常执行它都会在其后面执行-->
<!--<aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>-->
<!--配置切入点表达式,id属性用于指定表达式的唯一标志
此标签写在aop:aspect标签内部只能当前切面使用。
它可以写在aop:aspect外面,此时变成所有切面可用
-->
<!--配置环绕通知 详细的注释请看LOgger类中-->
<aop:around method="aroundPrintLog" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
测试类AOPTest.java
/**
- @author lixiang1234_李祥
- @site www.lixiang.com
- @create 2019-09-21 16:35
*/
import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
-
测试AOP配置
*/
public class AOPTest {public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext(“bean.xml”);
//2.获取对象
IAccountService as = (IAccountService)ac.getBean(“accountService”);
//3.执行方法
as.saveAccount();}
}
总结:
* 环绕通知
* 问题:
* 当我们配置了环绕通知之后,切入点方法没有执行,而通知方法执行了。
* 分析:
* 通过对比动态代理中的环绕通知代码,发现动态代理的环绕通知有明确的切入点方法调用,而我们的代码中没有。
* 解决:
* spring框架为我们提供了一个接口,ProceedingJoinPoint.该接口有一个方法proceed(),此方法就相当与明确调用切入点方法。
* 该接口可以作为环绕通知的方法参数,在程序执行时,spring框架为我们提供该接口的是实现类供我们使用。
*
* spring中的环绕通知:
* 它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。