环绕通知
执行目标方法之前,之后,异常,最终等各个地方都可以进行的通知,
1、编写实现接口 MethodInterceptor 的类 LogAround 重写 public Object invoke(MethodInvocation methodInvocation) throws Throwable 方法.
i.使用环绕通知时,目标方法的一切信息都可以用 methodInvocation 参数来获取
ii.环绕通知可以获取目标对象的一切控制权。
package com.demo.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LogAround implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object result = null;
try{
System.out.println("环绕的前置通知。。。。。"); //在 methodInvocation.proceed() 前的就是前置通知
result = methodInvocation.proceed(); //控制目标方是否执行,写了这就就会执行 add|()方法,不写就不会执行该方法
// result目标方法的返回值 add()的返回值
System.out.println("环绕的后置通知。。。。。"); //在 methodInvocation.proceed() 后的就是后置通知
}catch (Exception e){
System.out.println("环绕的在catch的异常通知.....");
}
return result;
}
}
业务类
package dao.entity;
import org.springframework.stereotype.Component;
/**
* @Component("studentdao")相当于
* <bean id="studentdao" class="dao.entity.serviceImpl">
*/
@Component("studentdao")
public class serviceImpl {
public void add(){
System.out.println("zengjia ...............");
}
public void delete(){
System.out.println("删除了。。。。。。。。。。");
}
}
2、application.xml中配置
<!-- 环绕通知-->
<bean id="LogAround" class="com.demo.aop.LogAround"></bean>
<aop:config>
<aop:pointcut id="pointcut3" expression="execution(public void dao.entity.serviceImpl.add())"/>
<aop:advisor advice-ref="LogAround" pointcut-ref="pointcut3"/>
</aop:config>
3、测试Test类
package demo;
import com.entity.Course;
import com.entity.Student;
import dao.entity.serviceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student s = (Student)context.getBean("student");
context.getBean("teacher");
Course c = (Course)context.getBean("course");
System.out.println(c);
}
public static void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
serviceImpl s = (serviceImpl)context.getBean("studentdao");
s.add();
s.delete();
}
public static void main(String[] args){
test2();
}
}
二、注解实现AOP
1、jar包
2、配置
将业务类,通知 纳入到IOC容器中,开启注解对AOP的支持
<context:component-scan base-package="dao.entity,com.zhujie.aop"></context:component-scan>
<aop:aspectj-autoproxy> </aop:aspectj-autoproxy>
3、编写业务类
package com.zhujie.aop;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component("LogAnnotation") //<bean id="LogAnnotation" class="com.zhujie.aop.LogBefore"><bean>
@Aspect //此类是一个通知
public class LogBefore {
@Before("execution(public void dao.entity.serviceImpl.add())") //定义切点
public void myBefore(){
System.out.println("注解形式的前置通知。。。。。。。");
}
@AfterReturning("execution(public void dao.entity.serviceImpl.add())")
public void myAfter(){
System.out.println("注解形式的后置通知.........");
}
}
如何获取自定义函数的参数,返回值??
需要使用一个对象,JoinPoint
package com.zhujie.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import java.lang.reflect.Array;
import java.util.Arrays;
@Component("LogAnnotation") //<bean id="LogAnnotation" class="com.zhujie.aop.LogBefore"><bean>
@Aspect //此类是一个通知
public class LogBefore {
@Before("execution(public void dao.entity.serviceImpl.add())") //定义切点
public void myBefore(JoinPoint jp){
System.out.println("注解形式的前置通知。。。。。。。"+"目标对象"+jp.getTarget()+"调用的方法名"+jp.getSignature().getName()
+"方法的参数"+ Arrays.toString(jp.getArgs()));
}
//returning = "returningValue" 指明这个方法的返回值是 returningValue
@AfterReturning(pointcut="execution(public void dao.entity.serviceImpl.add())",returning = "returningValue")
public void myAfter(JoinPoint jp,Object returningValue){
System.out.println("注解形式的前置通知。。。。。。。"+"目标对象"+jp.getTarget()+",调用的方法名"+jp.getSignature().getName()
+"方法的参数"+ Arrays.toString(jp.getArgs())+",返回值"+returningValue);
}
}
各种异常示例:
package com.zhujie.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Array;
import java.util.Arrays;
@Component("LogAnnotation") //<bean id="LogAnnotation" class="com.zhujie.aop.LogBefore"><bean>
@Aspect //此类是一个通知
public class LogBefore {
// 前置通知
@Before("execution(public void dao.entity.serviceImpl.add())") //定义切点
public void myBefore(JoinPoint jp){
System.out.println("注解形式的前置通知。。。。。。。"+"目标对象"+jp.getTarget()+"调用的方法名"+jp.getSignature().getName()
+"方法的参数"+ Arrays.toString(jp.getArgs()));
}
//后置通知
//returning = "returningValue" 指明这个方法的返回值是 returningValue
@AfterReturning(pointcut="execution(public void dao.entity.serviceImpl.add())",returning = "returningValue")
public void myAfter(JoinPoint jp,Object returningValue){
System.out.println("注解形式的前置通知。。。。。。。"+"目标对象"+jp.getTarget()+",调用的方法名"+jp.getSignature().getName()
+"方法的参数"+ Arrays.toString(jp.getArgs())+",返回值"+returningValue);
}
// 环绕通知
@Around("execution(public void dao.entity.serviceImpl.add())")
public void myAround(ProceedingJoinPoint pjp){ //环绕通知方法的参数是 ProceedingJoinPoint pjp
//前置通知
System.out.println("前置通知........");
try{
pjp.proceed(); //执行方法
// 方法执行之后
System.out.println("后置通知........");
}catch (Throwable e){
// 发生异常时
System.out.println("发生异常时,异常通知");
}finally {
System.out.println("最终通知,最终通知可以单独写");
}
}
// 异常通知
@AfterThrowing("execution(public void dao.entity.serviceImpl.add())")
public void myException(){
System.out.println("异常通知、、");
}
// 最终通知
@After("execution(public void dao.entity.serviceImpl.add())")
public void myAfter(){
System.out.println("单独写的最终通知");
}
}
三、基于 Schema形式的AOP
类似于实现接口的方式,
i .编写一个普通类
ii.