简介
Aspect Oriented Programming(AOP)称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,如日志,事务,权限等等
相关概念
- 满足OCP开闭原则:对程序扩展打开,对程序修改关闭
- Aspect(切面):通常是一个类,在切面中定义通知和切入点
- JointPoint(连接点):需要拦截的点(方法类型)
- PointCut(切入点):指定连接点的规则,规定连接点连接位置以及对连接点进行筛选
- Advice(通知):决定增强业务的内容,有before(前置),after(后置),afterReturning(最终),afterThrowing(异常),around(环绕)
搭建
- 依赖包 spring-aop
- AspectJ组件
a.aopalliance (aop联盟规则)
b.spring-aspects(spring的aspectj集成包)
c.aspectj.weaver(AspectJ织入包)
连接点
自动记录对应方法的信息
方法名:jointPoint.getSignature().getName()
目标对象:jointPoint.getTarget().getClass().getName()
代理对象:jointPoint.getThis().getClass().getName()
方法的返回值(后置通知,环绕通知,最终通知) 要在配置文件中配置返回值绑定到后置通知的参数上
使用
applicationContext.xml
<!--业务层-->
<bean id="userService" class="com.service.UserServiceImpl"></bean>
<bean id="proService" class="com.service.ProServiceImpl"></bean>
<!--切面-->
<bean id="myAspect" class="com.aop.MyAspect"></bean>
<!--配置切入点和切面-->
<aop:config>
<aop:pointcut id="xxx1" expression="bean(proService)"/>
<!--1.规定切面 -->
<aop:aspect ref="myAspect">
<!--2.切入点 切入的规则-->
<aop:pointcut id="xxx" expression="bean(*Service)"/>
<!--3.配置通知的时间点-->
<!--
1.前置通知before 在进入连接点之前执行
2.后置通知AfterReturning 连接点执行之后通知再执行
3.环绕通知Around 连接点执行的整个过程
4.异常通知AfterThrowing 在连接点抛出异常之后
5.最终通知After 无论方法是否异常都一定会执行
-->
<aop:before method="beforeLogin" pointcut-ref="xxx" ></aop:before>
<aop:after-returning method="afterRetuturningLogin" pointcut-ref="xxx" returning="returnVal"></aop:after-returning>
<aop:around method="around" pointcut-ref="xxx"></aop:around>
<aop:after-throwing method="afterThrowing" pointcut-ref="xxx" throwing="ex"></aop:after-throwing>
<aop:after method="after" pointcut="bean(*Service)" ></aop:after>
</aop:aspect>
</aop:config>
MyAspect.java(切面类)
public class MyAspect {
//前置通知
public void beforeLogin(JoinPoint jointPoint){
//方法名
System.out.println("=============开始进入前置通知===============");
System.out.println("拦截的方法名是===" + jointPoint.getSignature().getName());
System.out.println("目标对象是==="+jointPoint.getTarget().getClass().getName());
System.out.println("代理对象是====" + jointPoint.getThis().getClass().getName());
System.out.println("当前方法的参数" + Arrays.toString(jointPoint.getArgs()));
System.out.println("进入了方法前的时间是" + CommmonUtil.getTime());
System.out.println("=============前置通知结束===============");
}
//后置通知
public void afterRetuturningLogin(JoinPoint jointPoint,Object returnVal){
System.out.println("=============开始进入后置通知===============");
System.out.println("拦截的方法名是===" + jointPoint.getSignature().getName());
System.out.println("目标对象是==="+jointPoint.getTarget().getClass().getName());
System.out.println("代理对象是====" + jointPoint.getThis().getClass().getName());
System.out.println("当前方法的返回值是" + returnVal);
System.out.println("出方法的时间是" + CommmonUtil.getTime());
System.out.println("=============后置通知结束===============");
}
//环绕通知(本质就是代理原来的方法)
public Object around(ProceedingJoinPoint jointPoint) throws Throwable {
System.out.println("=============开始进入环绕通知===============");
System.out.println("拦截的方法名是===" + jointPoint.getSignature().getName());
System.out.println("目标对象是==="+jointPoint.getTarget().getClass().getName());
System.out.println("代理对象是====" + jointPoint.getThis().getClass().getName());
System.out.println("当前方法的参数" + Arrays.toString(jointPoint.getArgs()));
System.out.println("进入了方法前的时间是" + CommmonUtil.getTime());
Object returnVal = jointPoint.proceed();
System.out.println("当前方法的返回值是" + returnVal);
System.out.println("出方法的时间是" + CommmonUtil.getTime());
System.out.println("=============环绕通知结束===============");
return returnVal;
}
//异常通知
public void afterThrowing(JoinPoint jointPoint,Throwable ex){
System.out.println("=============开始进入异常通知===============");
System.out.println("拦截的方法名是===" + jointPoint.getSignature().getName());
System.out.println("目标对象是==="+jointPoint.getTarget().getClass().getName());
System.out.println("代理对象是====" + jointPoint.getThis().getClass().getName());
System.out.println("异常信息为=====" + ex.getMessage());
System.out.println("异常时间是" + CommmonUtil.getTime());
System.out.println("=============异常通知结束===============");
}
//最终通知
public void after(JoinPoint jointPoint){
System.out.println("=============开始进入最终通知===============");
System.out.println("拦截的方法名是===" + jointPoint.getSignature().getName());
System.out.println("目标对象是==="+jointPoint.getTarget().getClass().getName());
System.out.println("代理对象是====" + jointPoint.getThis().getClass().getName());
System.out.println("最终的时间是" + CommmonUtil.getTime());
System.out.println("=============最终结束===============");
}
}
调用*Service实例中的方法则会完成AOP代理运行。