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(环绕通知)==被拦截方法返回值为:==返回值为:你好,世界