AOP:面向方面编程
切入点:
规定每次在哪个位置调用该方法。
一个普通的类 -> 有特定功能的类 方法:
a.继承
b.实现接口
c.注解
b.配置
类 -> “通知” 方法:
实现接口:
前置通知:
接口:org.springframework.aop.MethodBeforeAdvice
接口中方法:before()
执行时机:目标方法执行前
后置通知:
接口:org.springframework.aop.AfterReturningAdvice
接口中方法:afterRetuming()
执行时机:目标方法执行后
异常通知:
接口:org.springframework.aop.ThrowsAdvice
接口中的方法:无
执行时机:目标方法发生异常时
环绕通知:
接口:org.aopalliance.intercept.MethodInterceptor
接口中的方法:invoke()
执行时机:拦截对目标方法调用,即调用目标方法的整个过程
如:
前置通知实现步骤:
a.jar包
aopalliance.jar
aspectjweaver.jar
b.配置
如:
<!--配置前置通知-->
<!--addStudent()所在的方法-->
<!--学生Service实现类对象-->
<bean id="studentService" class="org.service.impl.StudentServiceImpl">
<property name="studentDao" ref="studentDao"></property>
</bean>
<!--“前置通知”类 (切面)-->
<bean id="logBefore" class="org.aop.LogBefore">
</bean>
<!--将addStudent() 和 通知LogBefore 进行关联 -->
<aop:config>
<!--配置切入点(在哪里执行通知)-->
<aop:pointcut
id="poioncut"
expression="execution(public void org.service.impl.StudentServiceImpl.addStudent(org.entity.Student))"/>
<aop:pointcut
id="poioncut1"
expression="execution(public void org.service.impl.StudentServiceImpl.deleteStudentByNo(int))"/>
<!--advisor:相当于链接切入点 和 切面的线-->
<aop:advisor
advice-ref="logBefore"
pointcut-ref="poioncut"/>
<aop:advisor
advice-ref="logBefore"
pointcut-ref="poioncut1"/>
</aop:config>
c.编写
aop: 在指定方法之前自动执行该前置通知方法。
如:
addStudent(): 业务方法;[IStudentService.java中的 addStudent();使用时可使用接口的具体实现方法]
before(): 自动执行的通知,即aop前置通知;[LogBefore.java中的 before()]
每当执行addStudent()之前 自动执行方法before();
后置通知:
1.通知类:普通类实现后置通知接口
如:
public class LogAfter implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("后置通知:目标对象:"+o1+
",调用的方法名:"+method.getName()+
",方法的参数个数:"+objects.length+
",方法得到返回值:"+o);
}
}
2.业务类:
如:
StudentServiceImpl中的addStudent()
3.配置:
a.将业务类和通知类纳入SpringIOC容器中
b.定义切入点(一端)、定义通知类(另一端),通过aop:advisor将两端连接起来
异常通知:
1.通知类:普通类实现异常通知接口
如:
public class LogException implements ThrowsAdvice {
//异常通知的具体方法(该类不用重写但是必须有)
public void AfterThrowing(Method method, Object[] args ,Object target, Throwable ex){
System.out.println("异常通知:\n**目标对象:"+target+
",\n**方法名:"+method.getName()+
",\n**方法的参数个数:"+args.length+
",\n**异常类型:"+ex.getMessage());
}
}
注:
根据异常接口的源码可以发现,异常通知的实现类,必须编写以下方法:
public void AfterThrowing([method, args ,target], ThrowableSubclass):
//四个参数都存在
a. public void AfterThrowing(method, args ,target, ThrowableSubclass)
//只存在一个参数
b. public void AfterThrowing(ThrowableSubclass)
2.业务类:
如:
StudentServiceImpl中的addStudent()
3.配置:
a.将业务类和通知类纳入SpringIOC容器中
b.定义切入点(一端)、定义通知类(另一端),通过aop:advisor将两端连接起来
环绕通知:
在目标方法的前后、异常发生时、最终等各个地方都可以进行的通知,最强大的一个通知;
可以获取目标方法的全部控制权(目标方法是否执行、执行之前、执行之后、参数、返回值等)
1.通知类:普通类实现异常通知接口
如:
public class LogAround implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object result = null;
try{
//方法体1...
System.out.println("用环绕通知实现的【前置通知...】");
/**
* 此 methodInvocation.proceed()方法之前(方法1体的位置)是前置通知
* 此 methodInvocation.proceed()方法之后(方法2体的位置)是后置通知
* catch中是异常通知
*
* result就是目标方法的返回值(如:addStudent()的返回值)
*/
result = methodInvocation.proceed();//控制着目标方法的执行(如:addStudent()的执行)
//方法体2...
System.out.println("用环绕通知实现的【后置通知...】:");
System.out.println("**目标对象:"+methodInvocation.getThis()+
",\n**调用的方法名:"+methodInvocation.getMethod().getName()+
",\n**方法的参数个数:"+methodInvocation.getArguments().length+
",\n**方法得到返回值:"+result);
}catch(Exception e){
//方法体3...
System.out.println("用环绕通知实现的【异常通知...】");
}
return result;
}
}
2.业务类/业务方法:
如:
StudentServiceImpl中的addStudent()
3.配置:
a.将业务类和通知类纳入SpringIOC容器中
b.定义切入点(一端)、定义通知类(另一端),通过aop:advisor将两端连接起来
注:
1.在使用环绕通知时,目标方法的一切信息,都可以通过环绕通知类中的 methodInvocation 参数获取。
2.环绕通知中的全部控制权体现:
a.可控制方法是否执行
当将环绕通知中的执行方法语句(如:result = methodInvocation.proceed();)注释掉,则该方法就不会执行。
b.可控制方法返回值类型
方法中的返回值类型在环绕通知中可以修改。
如:
StudentServiceImpl中的addStudent()方法返回值是:void
在环绕通知中:
正常返回:return result; 此时addStudent()返回值为:null
可修改:return "abc"; 此时addStudent()返回值:abc ,并且在对外显示的返回值是abc不再是null
3.环绕通知的底层是通过拦截器实现的。