(12)Spring AOP通知

aspect定义切面,切面里面可以有多个通知,这些通知大概就是在被拦截的方法前,方法中,方法后执行,通知大概有这几种类型

修改被拦截类的接口

package shuai.spring.study.service;

public interface IHelloService {
	public void sayHello();

	public void sayHello(String param);

	public void sayHello(String param0, String param1);
}

修改实现

package shuai.spring.study.service.impl;

import shuai.spring.study.service.IHelloService;

public class HelloServiceImpl implements IHelloService {
	@Override
	public void sayHello() {
		System.out.println("============Hello World!");
	}

	@Override
	public void sayHello(String param) {
		System.out.println("一个参数:" + param);
	}

	@Override
	public void sayHello(String param0, String param1) {
		System.out.println("两个参数:" + param0 + "和" + param1);
	}
}

修改测试

package shuai.spring.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import shuai.spring.study.service.IHelloService;

public class HelloTest {

	@Test
	public void testHelloWorld() {

		@SuppressWarnings("resource")
		ApplicationContext context = new ClassPathXmlApplicationContext("HelloWorld.xml");

		IHelloService iHelloService = context.getBean("iHelloService", IHelloService.class);
		iHelloService.sayHello("hello", "world");

	}

}


1、前置通知,before,在被拦截的方法执行前执行,可以获取被拦截方法的参数值

修改配置文件HelloWorld.xml

<?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">
        
        <bean id="iHelloService" class="shuai.spring.study.service.impl.HelloServiceImpl"/>
        
        <bean id="helloAspect" class="shuai.spring.study.aop.HelloAspect"/>
        <!-- <aop:aspectj-autoproxy proxy-target-class="true"/> -->
        <aop:config>
        	<aop:pointcut expression="execution(* shuai.spring.study.service..*.*(..))" id="pointcut"/>
        	<aop:aspect ref="helloAspect">
        		<aop:before 
        			method="beforeHello(java.lang.String,java.lang.String)" 
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)" 
        			arg-names="param0,param1"/>
        	</aop:aspect>
        </aop:config>

</beans>

注意aop:before写法:如果要获取被拦截方法的传入参数就要在通知的方法里也配置参数,比如这里的:method="beforeHello(java.lang.String,java.lang.String)"

切点也要注意,不能再使用aop:pointcut配置的了,需要修改,大概意思就是拦截带两个参数的方法,比如这里的:pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)",注意后面的and args(param0,param1)

arg-names="param0,param1"要与method里的参数对应,也要与ang args 里的参数对应,and args里的参数是被拦截方法参数的顺序,arg-names里的顺序是通知方法里的顺序,所以这两个里面的值要一样,顺序可以不一样。

修改通知类

package shuai.spring.study.aop;

public class HelloAspect {
	// 前置通知
	public void beforeHello(String param0, String parm1) {
		System.out.println("===========beforeHello(前置通知)==" + param0 + "==" + parm1);
	}
}

测试输出结果:

===========beforeHello(前置通知)==hello==world
两个参数:hello和world

2、后置返回通知,after-returning,被拦截的方法正常输出返回结果后执行,可以获取方法的参数,返回值

接口

package shuai.spring.study.service;

public interface IHelloService {
	public void sayHello();

	public void sayHello(String param);

	public void sayHello(String param0, String param1);

	public String returnHello();

	public String returnHello(String param0, String param1);
}

实现

package shuai.spring.study.service.impl;

import shuai.spring.study.Info;
import shuai.spring.study.service.IHelloService;

public class HelloServiceImpl implements IHelloService {
	@Override
	public void sayHello() {
		System.out.println("============Hello World!");
	}

	@Override
	public void sayHello(String param) {
		System.out.println("一个参数:" + param);
	}

	@Override
	public void sayHello(String param0, String param1) {
		System.out.println("两个参数:" + param0 + "和" + param1);
	}

	@Override
	public String returnHello() {
		System.out.println("返回前输出");
		return Info.info();
	}

	@Override
	public String returnHello(String param0, String param1) {
		System.out.println("返回前输出,两个参数:" + param0 + "和" + param1);
		return Info.info();
	}
}

增加一个输出类

package shuai.spring.study;

public class Info {
	public static String info() {
		System.out.println("返回时输出:hello world 1");
		return "返回值:hello world 1";
	}

}

修改测试类

package shuai.spring.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import shuai.spring.study.service.IHelloService;

public class HelloTest {

	@Test
	public void testHelloWorld() {

		@SuppressWarnings("resource")
		ApplicationContext context = new ClassPathXmlApplicationContext("HelloWorld.xml");

		IHelloService iHelloService = context.getBean("iHelloService", IHelloService.class);
		iHelloService.returnHello("hello", "world");

	}

}

修改配置文件

<?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">
        
        <bean id="iHelloService" class="shuai.spring.study.service.impl.HelloServiceImpl"/>
        
        <bean id="helloAspect" class="shuai.spring.study.aop.HelloAspect"/>
        <!-- <aop:aspectj-autoproxy proxy-target-class="true"/> -->
        <aop:config>
        	<aop:pointcut expression="execution(* shuai.spring.study.service..*.*(..))" id="pointcut"/>
        	<aop:aspect ref="helloAspect">
        		<!-- <aop:before 
        			method="beforeHello(java.lang.String,java.lang.String)" 
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)" 
        			arg-names="param0,param1"/> -->
        		<aop:after-returning 
        			method="afterReturningHello(java.lang.String,java.lang.String,java.lang.String)"
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)"
        			returning="param"
        			arg-names="param,param0,param1"/>
        	</aop:aspect>
        </aop:config>

</beans>

注意afteri-returning里面多了一个returning,这个就是获取的返回值

修改通知类

package shuai.spring.study.aop;

public class HelloAspect {
	// 前置通知
	public void beforeHello(String param0, String parm1) {
		System.out.println("===========beforeHello(前置通知)==" + param0 + "==" + parm1);
	}

	// 后置返回通知
	public void afterReturningHello(String param, String param0, String parm1) {
		System.out.println("===========afterReturningHello(后置返回通知)==被拦截方法参数为:==" + param0 + "==" + parm1 + "==结果为:==" + param);
	}
}

测试输出结果:

返回前输出,两个参数:hello和world
返回时输出:hello world 1
===========afterReturningHello(后置返回通知)==被拦截方法参数为:==hello==world==结果为:==返回值:hello world 1

3、后置异常通知,after-throwing,被拦截的方法抛出异常时执行,可以获取参数,异常

修改实现类,随便加一个异常

@Override
public String returnHello(String param0, String param1) {
    System.out.println("返回前输出,两个参数:" + param0 + "和" + param1);
    int i = 1 / 0;
    return Info.info();
}

修改配置文件

<?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">
        
        <bean id="iHelloService" class="shuai.spring.study.service.impl.HelloServiceImpl"/>
        
        <bean id="helloAspect" class="shuai.spring.study.aop.HelloAspect"/>
        <!-- <aop:aspectj-autoproxy proxy-target-class="true"/> -->
        <aop:config>
        	<aop:pointcut expression="execution(* shuai.spring.study.service..*.*(..))" id="pointcut"/>
        	<aop:aspect ref="helloAspect">
        		<!-- <aop:before 
        			method="beforeHello(java.lang.String,java.lang.String)" 
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)" 
        			arg-names="param0,param1"/> -->
        		<!-- <aop:after-returning 
        			method="afterReturningHello(java.lang.String,java.lang.String,java.lang.String)"
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)"
        			returning="param"
        			arg-names="param,param0,param1"/> -->
        		<aop:after-throwing 
        			method="afterThrowingHello"
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)"
        			throwing="param"
        			arg-names="param,param0,param1"/>
        	</aop:aspect>
        </aop:config>

</beans>

注意:throwing的值就是异常的信息。method里面可以就写一个方法名,只有方法重载的时候需要写上参数类型,【遗留问题】写了参数类型,但是总是报错,所以就没写参数类型,以后再研究吧

修改通知类

package shuai.spring.study.aop;

public class HelloAspect {
    // 前置通知
    public void beforeHello(String param0, String parm1) {
        System.out.println("===========beforeHello(前置通知)==" + param0 + "==" + parm1);
    }

    // 后置返回通知
    public void afterReturningHello(String param, String param0, String parm1) {
        System.out.println("===========afterReturningHello(后置返回通知)==被拦截方法参数为:==" + param0 + "==" + parm1 + "==结果为:==" + param);
    }

    // 后置异常通知
    public void afterThrowingHello(Exception param, String param0, String parm1) {
        System.out.println("===========afterThrowingHello(后置异常通知)==被拦截方法参数为:==" + param0 + "==" + parm1 + "==异常为:==" + param);
    }
}

测试结果:

返回前输出,两个参数:hello和world
===========afterThrowingHello(后置异常通知)==被拦截方法参数为:==hello==world==异常为:==java.lang.ArithmeticException: / by zero


4、后置最终通知,after,不管正常返回还是抛出异常,都会执行,但是貌似好像获取不到返回值

修改测试文件

<?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">
        
        <bean id="iHelloService" class="shuai.spring.study.service.impl.HelloServiceImpl"/>
        
        <bean id="helloAspect" class="shuai.spring.study.aop.HelloAspect"/>
        <!-- <aop:aspectj-autoproxy proxy-target-class="true"/> -->
        <aop:config>
        	<aop:pointcut expression="execution(* shuai.spring.study.service..*.*(..))" id="pointcut"/>
        	<aop:aspect ref="helloAspect">
        		<!-- <aop:before 
        			method="beforeHello(java.lang.String,java.lang.String)" 
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)" 
        			arg-names="param0,param1"/> -->
        		<!-- <aop:after-returning 
        			method="afterReturningHello(java.lang.String,java.lang.String,java.lang.String)"
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)"
        			returning="param"
        			arg-names="param,param0,param1"/> -->
        		<!-- <aop:after-throwing 
        			method="afterThrowingHello"
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)"
        			throwing="param"
        			arg-names="param,param0,param1"/> -->
        		<aop:after
        			method="afterHello"
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)"
        			arg-names="param0,param1"/>
        	</aop:aspect>
        </aop:config>

</beans>

修改通知类

package shuai.spring.study.aop;

public class HelloAspect {
    // 前置通知
    public void beforeHello(String param0, String parm1) {
        System.out.println("===========beforeHello(前置通知)==" + param0 + "==" + parm1);
    }

    // 后置返回通知
    public void afterReturningHello(String param, String param0, String parm1) {
        System.out.println("===========afterReturningHello(后置返回通知)==被拦截方法参数为:==" + param0 + "==" + parm1 + "==结果为:==" + param);
    }

    // 后置异常通知
    public void afterThrowingHello(Exception param, String param0, String parm1) {
        System.out.println("===========afterThrowingHello(后置异常通知)==被拦截方法参数为:==" + param0 + "==" + parm1 + "==异常为:==" + param);
    }

    // 后置最终通知
    public void afterHello(String param0, String parm1) {
        System.out.println("===========afterHello(后置最终通知)==被拦截方法参数为:==" + param0 + "==" + parm1);
    }
}

不管被拦截的方法是否有异常,都会执行

用之前的测试方法

如果有异常,被拦截的方法加一句:int i = 1 / 0;输出如下:

返回前输出,两个参数:hello和world
===========afterHello(后置最终通知)==被拦截方法参数为:==hello==world

如果没有异常,输出如下:

返回前输出,两个参数:hello和world
返回时输出:hello world 1
===========afterHello(后置最终通知)==被拦截方法参数为:==hello==world

5、环绕通知,around,可以获取并改变被拦截方法的参数,从而改变方法的返回值,当然也可以获取到返回值。

修改一下Info类

package shuai.spring.study;

public class Info {
    public static String info() {
        System.out.println("返回时输出:hello world 1");
        return "返回值:hello world 1";
    }

    public static String info(String param0, String param1) {
        System.out.println("返回时输出:" + param0 + "," + param1);
        return "返回值为:" + param0 + "," + param1;
    }

}

修改一下被拦截的方法

@Override
public String returnHello(String param0, String param1) {
    System.out.println("返回前输出,两个参数:" + param0 + "和" + param1);
    return Info.info(param0, param1);
}

测试类不变

package shuai.spring.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import shuai.spring.study.service.IHelloService;

public class HelloTest {

    @Test
    public void testHelloWorld() {

        @SuppressWarnings("resource")
        ApplicationContext context = new ClassPathXmlApplicationContext("HelloWorld.xml");

        IHelloService iHelloService = context.getBean("iHelloService", IHelloService.class);
        iHelloService.returnHello("hello", "world");

    }

}

修改配置文件

<?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">
        
        <bean id="iHelloService" class="shuai.spring.study.service.impl.HelloServiceImpl"/>
        
        <bean id="helloAspect" class="shuai.spring.study.aop.HelloAspect"/>
        <!-- <aop:aspectj-autoproxy proxy-target-class="true"/> -->
        <aop:config>
        	<aop:pointcut expression="execution(* shuai.spring.study.service..*.*(..))" id="pointcut"/>
        	<aop:aspect ref="helloAspect">
        		<!-- <aop:before 
        			method="beforeHello(java.lang.String,java.lang.String)" 
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)" 
        			arg-names="param0,param1"/> -->
        		<!-- <aop:after-returning 
        			method="afterReturningHello(java.lang.String,java.lang.String,java.lang.String)"
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)"
        			returning="param"
        			arg-names="param,param0,param1"/> -->
        		<!-- <aop:after-throwing 
        			method="afterThrowingHello"
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)"
        			throwing="param"
        			arg-names="param,param0,param1"/> -->
        		<!-- <aop:after
        			method="afterHello"
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)"
        			arg-names="param0,param1"/> -->
        		<aop:around
        			method="aroundHello" 
        			pointcut="execution(* shuai.spring.study.service..*.*(..)) and args(param0,param1)"
        			arg-names="param0,param1"/>
        	</aop:aspect>
        </aop:config>

</beans>

修改通知类

package shuai.spring.study.aop;

import org.aspectj.lang.ProceedingJoinPoint;

public class HelloAspect {
    // 前置通知
    public void beforeHello(String param0, String parm1) {
        System.out.println("===========beforeHello(前置通知)==" + param0 + "==" + parm1);
    }

    // 后置返回通知
    public void afterReturningHello(String param, String param0, String parm1) {
        System.out.println("===========afterReturningHello(后置返回通知)==被拦截方法参数为:==" + param0 + "==" + parm1 + "==结果为:==" + param);
    }

    // 后置异常通知
    public void afterThrowingHello(Exception param, String param0, String parm1) {
        System.out.println("===========afterThrowingHello(后置异常通知)==被拦截方法参数为:==" + param0 + "==" + parm1 + "==异常为:==" + param);
    }

    // 后置最终通知
    public void afterHello(String param0, String parm1) {
        System.out.println("===========afterHello(后置最终通知)==被拦截方法参数为:==" + param0 + "==" + parm1);
    }

    // 环绕通知
    public void aroundHello(ProceedingJoinPoint pjp, String param0, String parm1) throws Throwable {
        System.out.println("===========aroundHello(环绕通知)==被拦截方法参数为:==" + param0 + "==" + parm1);
        Object retVal = pjp.proceed(new Object[] { "你好", "世界" });
        System.out.println("===========aroundHello(环绕通知)==被拦截方法返回值为:==" + retVal);
    }
}

注意:环绕通知的第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型,而且在配置文件里也不用配置,Object retVal = pjp.proceed(new Object[] { "你好", "世界" });这句话就是替换新的参数执行被拦截的方法,所以参数要对应。返回值就是被拦截的方法带入新的参数的返回值。

测试结果:

===========aroundHello(环绕通知)==被拦截方法参数为:==hello==world
返回前输出,两个参数:你好和世界
返回时输出:你好,世界
===========aroundHello(环绕通知)==被拦截方法返回值为:==返回值为:你好,世界








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值