spring框架AOP即面向切面编程,与以往面向对象是一种相互补充,常见于日志功能和相同代码的抽离添加到业务层
xml中配置AOP
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置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:aspect id="logAdvice" ref="logger">
<aop:before method="beforeprintLog" pointcut-ref="pt1"></aop:before>
<aop:after-returning method="afterReturnprintLog" pointcut-ref="pt1"></aop:after-returning>
<aop:after-throwing method="afterThrowprintLog" pointcut-ref="pt1"></aop:after-throwing>
<aop:after method="afterprintLog" pointcut-ref="pt1"></aop:after>
<!-- 配置切入点表达式 id属性用于指定-->
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"/>
<!-- 配置环绕通知 -->
<aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
</beans>
AOP操作术语
Joinpoint(连接点),类里面可以被增强的方法,在Spring中,这些方法为连接点.
Pointcut(切入点);所谓切入点是指我们实际增强的方法.
增强(Advice);实际增强的逻辑,称之为增强
前置增强: 在方法开始前执行
后置增强: 在方法结束后执行
异常增强: 在方法出现异常时执行
最终增强: 在后置之后执行
环绕增强: 在方法之前和之后执行
切面(Aspect); 把增强应用到具体方法上面的过程称之为切面.
目标对象(Target); 增强逻辑的织入目标类。
引介(Introduction);引介是一种特殊的增强,它为类添加一些属性和方法。
织入(Weaving); 织入是将增强添加对目标类具体连接点上的过程。
代理(Proxy);一个类被AOP织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类。
其中环绕通知写入自己方法是没有准确的切入点所以控制台只会打印通知而不会执行业务层方法,需要如下方法实现
/**
* 环绕通知
*/
public void aroundPringLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try {
//1.得到方法执行所需的参数
Object[] args = pjp.getArgs();
System.out.println("此处是前置通知");
//2.明确业务层方法(切入点方法)
rtValue = pjp.proceed(args);
System.out.println("此处是后置通知");
} catch (Throwable t) {
System.out.println("此处是异常通知");
throw new RuntimeException(t);
}finally {
System.out.println("此处是最终通知");
}
}
xml配置切入点粒度表达式
- 常见的切点表达式
• 匹配方法签名
// 匹配指定包中的所有的方法
execution(* com.xys.service.*(…))// 匹配当前包中的指定类的所有方法
execution(* UserService.*(…))// 匹配指定包中的所有 public 方法
execution(public * com.xys.service.*(…))// 匹配指定包中的所有 public 方法, 并且返回值是 int 类型的方法
execution(public int com.xys.service.*(…))// 匹配指定包中的所有 public 方法, 并且第一个参数是 String, 返回值是 int 类型的方法
execution(public int com.xys.service.*(String name, …))匹配类型签名
// 匹配指定包中的所有的方法, 但不包括子包
within(com.xys.service.*)// 匹配指定包中的所有的方法, 包括子包
within(com.xys.service…*)// 匹配当前包中的指定类中的方法
within(UserService)// 匹配一个接口的所有实现类中的实现的方法
within(UserDao+)匹配Bean名字
// 匹配以指定名字结尾的 Bean 中的所有方法
bean(*Service)切点表达式组合
// 匹配以 Service 或 ServiceImpl 结尾的 bean
bean(*Service || *ServiceImpl)// 匹配名字以 Service 结尾, 并且在包 com.xys.service 中的 bean
bean(Service) && within(com.xys.service.)