目录
本章学习源码Github地址:https://github.com/GuiZhouAndroid/MySpringAllProject/tree/master/SpringDemo09_AspectJ/src/main/java/com/dhrj/java/zsitking/afterreturn
一、前言
重点:后置通知是在目标方法执行后切入切面功能,可以得到目标方法的返回值。如果目标方法的返回值是简单类型(8种基本类型+String)则不可改变,如果目标方法的返回值是引用类型则可以改变——>根据返回值类型,决定是否具有资格重新改变目标方法执行之后最终接收的返回值。
实现步骤:
(1)创建业务接口
(2)创建业务实现
(3)创建切面类,实现切面方法
(4)在Spring的applicationContext.xml配置文件中进行切面绑定——>IOC+AspectJ内置代理模式(默认JDK动态代理+CGLib子类代理)
二、后置通知——>验证简单类型返回值不可变
(1)后置通知业务接口
//后置通知业务接口
public interface AfterReturningService {
//我的名字
String myName(String name);
}
(2)后置通知业务接口实现类
//后置通知业务接口实现
@Service //Spring的IOC注解式创建业务逻辑层实例
public class AfterReturningServiceImpl implements AfterReturningService {
@Override
public String myName(String name) {
System.out.println("AfterReturningServiceImpl中myName(String name)已执行...");
return "我的姓名:" + name;
}
}
(3)后置通知切面类
@Aspect //交给AspectJ的框架去识别切面类
@Component //切面实例注册加载到spring容器中
public class AfterReturningAspectJ {
/**
* 后置通知的方法的规范
* (1)访问权限是public
* (2)方法没有返回值void
* (3)方法名称自定义
* (4)方法有参数(也可以没有参数,如果目标方法没有返回值,则可以写无参的方法,但一般会写有参,这样可以处理无参可以处理有参),这个切面方法的参数就是目标方法的返回值
* (5)使用@AfterReturning注解表明是后置通知
* 参数:
* value:指定切入点表达式
* returning:指定目标方法的返回值的名称,则名称必须与切面方法的参数名称一致.
*/
@AfterReturning(value = "execution(* com.dhrj.java.zsitking.afterreturn.impl.AfterReturningServiceImpl.*(..))", returning = "obj")
//切面方法的注解
public void myAfterReturningAspectJ(Object obj) {
System.out.println("AspectJ后置通知已执行...在AfterReturningServiceImpl执行之后才执行");
if (obj != null) { //判断目标方法的返回值是否为空
if (obj instanceof String) { //判断目标方法返回值的引用是否指向String类型
System.out.println("AspectJ后置通知接收返回值是字符串:" + ((String) obj).toUpperCase());//全转为大写字母
}
}
}
}
(4)applicationContext.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:context="http://www.springframework.org/schema/context"
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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--基于注解的访问要添加包扫描-->
<context:component-scan base-package="com.dhrj.java.zsitking.afterreturn"/>
<!--业务实现绑定AOP,默认是JDK动态代理,取时必须使用接口类型-->
<aop:aspectj-autoproxy/>
</beans>
(5)junit代码测试
@Test
public void testAfterReturning1() {
ApplicationContext ac = new ClassPathXmlApplicationContext("afterreturn/applicationContext.xml");
AfterReturningService afterReturningService = (AfterReturningService) ac.getBean("afterReturningServiceImpl");
System.out.println("后置通知绑定切面后的对象类型:" + afterReturningService.getClass());
System.out.println("最终返回值:"+afterReturningService.myName("ZhangSong"));
}
结论:由此可见,切面方法中已经是全部大小写的“ZHANGSONG”,根据后置通知特性“目标方法的返回值是简单类型(8种基本类型+String)则不可改变”——>最终结果输出原本的“ZhangSong”,即验证了简单类型的返回值的不可变性。
三、后置通知——>验证引用类型返回值可变
(1)新增实体类
public class People {
//年龄
private int age;
public People() {
}
public People(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "People{" +
", age=" + age +
'}';
}
}
(2)修改后置通知业务接口
//后置通知业务接口
public interface AfterReturningService {
//我的名字
String myName(String name);
//我的年龄
People myAge(int age);
}
(3)修改后置通知业务接口实现类
//后置通知业务接口实现
@Service //Spring的IOC注解式创建业务逻辑层实例
public class AfterReturningServiceImpl implements AfterReturningService {
@Override
public String myName(String name) {
System.out.println("AfterReturningServiceImpl中myName(String name)已执行...");
return "我的姓名:" + name;
}
@Override
public People myAge(int age) {
System.out.println("AfterReturningServiceImpl中myAge(int age)已执行...");
return new People(age);
}
}
(4)修改后置通知切面类
@Aspect //交给AspectJ的框架去识别切面类
@Component //切面实例注册加载到spring容器中
public class AfterReturningAspectJ {
/**
* 后置通知的方法的规范
* (1)访问权限是public
* (2)方法没有返回值void
* (3)方法名称自定义
* (4)方法有参数(也可以没有参数,如果目标方法没有返回值,则可以写无参的方法,但一般会写有参,这样可以处理无参可以处理有参),这个切面方法的参数就是目标方法的返回值
* (5)使用@AfterReturning注解表明是后置通知
* 参数:
* value:指定切入点表达式
* returning:指定目标方法的返回值的名称,则名称必须与切面方法的参数名称一致.
*/
@AfterReturning(value = "execution(* com.dhrj.java.zsitking.afterreturn.impl.AfterReturningServiceImpl.*(..))", returning = "obj")
//切面方法的注解
public void myAfterReturningAspectJ(Object obj) {
System.out.println("AspectJ后置通知已执行...在AfterReturningServiceImpl执行之后才执行");
if (obj != null) { //判断目标方法的返回值是否为空
if (obj instanceof String) { //判断目标方法返回值的引用是否指向String类型
System.out.println("AspectJ后置通知接收返回值是字符串:" + ((String) obj).toUpperCase());//全转为大写字母
}
if (obj instanceof People) { //判断目标方法返回值的引用是否指向People类型
People people = (People) obj;
people.setAge(100);
System.out.println("AspectJ后置通知接收返回值是改变的People年龄:" + people.getAge());
}
}
}
}
(5)junit代码测试
@Test
public void testAfterReturning2() {
ApplicationContext ac = new ClassPathXmlApplicationContext("afterreturn/applicationContext.xml");
AfterReturningService afterReturningService = (AfterReturningService) ac.getBean("afterReturningServiceImpl");
System.out.println("后置通知绑定切面后的对象类型:" + afterReturningService.getClass());
System.out.println("最终返回改变的People年龄:"+afterReturningService.myAge(24).getAge());
}
结论:由此可见,调用目标方法Peole myAge(int age)时。传入年龄值为24,经过后置通知切面功能后,已经动态的将目标方法Peole myAge(int age) 人的年龄值改变成100了——>即验证了引用类型的返回值的可变性。
四、总结
仅自己学习记录,如有错误,敬请谅解~,谢谢~~~