AOP
为什么要使用AOP?
有三个类,每个类里都有一个add Student()方法,如果我们每次执行addStudent()前都需要检查数据库内是否已经存在我们要增加的学生,就需要分别在三个方法前添加check()方法,很麻烦,不是吗?
so…
有了AOP(当然远不止这点功能呢),可以指定那谁谁,虚拟机你在每次跑addStudent()前都来给我调用check()来检查下,哈哈,苦逼的虚拟机。
简单的前置通知
1、xml配置
<!-- 配置前置通知-->
<!-- addPerson所在方法-->
<bean id="personServiceImpl" class="com.itheima.service.PersonServiceImpl">
<property name="personDao" ref="personDao">
</property>
</bean>
<!-- 前置通知类-->
<bean id="logBefore" class="com.itheima.aop.LogBefore">
</bean>
<!-- 关联-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(public void com.itheima.service.PersonServiceImpl.deletePerson(int)) or execution(public void com.itheima.service.PersonServiceImpl.addPerson(com.itheima.entity.Person))"/>
<aop:advisor advice-ref="logBefore" pointcut-ref="pointcut"/>
</aop:config>
expresstion表达式举例说明:
1、任意公共方法的执行:
execution(public * (…))
2、任何一个以“set”开始的方法的执行:
execution( set*(…))
3、AccountService
接口的任意方法的执行:
execution(* com.xyz.service.AccountService.(…))
4、定义在service包里的任意方法的执行:
execution( com.xyz.service..(…))
5、定义在service包和所有子包里的任意类的任意方法的执行:
execution(* com.xyz.service….(…))
6、定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:
execution(* com.test.spring.aop.pointcutexp…JoinPointObjP2.(…))")
最靠近(…)的为方法名,靠近.(…))的为类名或者接口名
2、前置通知类
LogBefore.java实现MethodBeforeAdvice接口
public class LogBefore implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("前置通知!");
}
}
后置通知就不写了,大同小异,赶时间。
异常通知:
在容器中配置异常通知
<bean id="logException" class="com.itheima.aop.LogException"/>
<!-- 异常通知-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(public void com.itheima.service.PersonServiceImpl.deletePerson(int)) or execution(public void com.itheima.service.PersonServiceImpl.addPerson(com.itheima.entity.Person))"/>
<aop:advisor advice-ref="logException" pointcut-ref="pointcut"/>
</aop:config>
异常通知类,注意,我们在实现接口的时候并没有提示我们要实现哪个方法,但是我们仍要实现以下方法:
package com.itheima.aop;
import org.springframework.aop.ThrowsAdvice;
import java.lang.reflect.Method;
public class LogException implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target, Throwable throwable){
System.out.println("异常通知:目标对象," + target + "方法名," + method.getName() + "方法的参数个数:" + args.length + "异常类型:" + throwable.getMessage());
}
}
故意在添加人类中让personDao空指针后,执行:
环绕通知:是一个功能最强大的通知,可以在任何地方通知,可以获得目标方法的全部控制权。
新建环绕类:LogArround .java
package com.itheima.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LogArround implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation){
Object result = null;
try {
// 前置通知
System.out.println("环绕前置");
result = invocation.proceed();//控制目标方法的执行,前面是前置通知,后面是后置通知
//后置通知
System.out.print("环绕后置通知:");
System.out.println("目标对象," + invocation.getThis() + "方法名," + invocation.getMethod().getName() + "方法的参数个数:" + invocation.getArguments().length + "返回参数:" + result);
} catch (Throwable throwable) {
//环绕异常通知
System.out.println("环绕异常通知");
}
return result;
}
}