21.05.11
JoinPoint
指定通知方法中的参数:JoinPoint
* JoinPoint:业务方法,要加入切面功能的业务方法
* 作用是:可以在通知方法中获取方法执行时的信息,例如方法名称,方法的实参
* 如果你的切面功能中需要用到方法的信息,就加入JoinPoint
* 这个JoinPoint参数的值是由框架赋予,必须是第一个位置的参数
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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--声明目标对象-->
<bean id="someService" class="com.node.ba01.SomeServiceImpl"/>
<!--声明切面类对象-->
<bean id="myAspect" class="com.node.ba01.MyAspect" />
<!--声明自动代理生成器-->
<!--使用aspectj框架内部的功能,创建目标对象的代理对象
创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象,
所以目标对象就是被修改后的代理对象
aspectj-autoproxy:会把spring容器中的所有目标对象,一次性都生成代理对象
-->
<aop:aspectj-autoproxy />
</beans>
SomeService.java
package com.node.ba01;
public interface SomeService {
void doSome(String name,Integer age);
}
SomeServiceImpl.java
package com.node.ba01;
public class SomeServiceImpl implements SomeService {
@Override
public void doSome(String name,Integer age) {
//给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
System.out.println("===目标方法doSome===");
}
}
MyAspect.java
package com.node.ba01;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import java.util.Date;
@Aspect
public class MyAspect {
@Before(value="execution(void *..SomeServiceImpl.doSome(String,Integer))")
public void myBefore(JoinPoint jp){
//获取方法的完整定义
System.out.println("方法的前面(定义)="+jp.getSignature());
System.out.println("方法的名称="+jp.getSignature().getName());
//获取方法的实参
Object args[]=jp.getArgs();
for(Object arg:args){
System.out.println("参数="+arg);
}
//就是你切面要执行的功能代码
System.out.println("切面功能:在目标方法之前输出执行时间:"+ new Date());
}
}
测试代码
package com.node;
import com.node.ba01.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest01 {
@Test
public void test01(){
String config="applicationContext.xml";
ApplicationContext ac=new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeService proxy= (SomeService) ac.getBean("someService");
//通过代理的对象执行方法,事项目标方法执行时,增强了功能
proxy.doSome("lisi",20);
}
}
@AfterReturning 后置通知
@AfterReturning:后置通知
属性:
1. value 切入点表达式
2. returning 自定义的变量,表示目标方法的返回值的
自定义变量必须和通知方法的形参名一样
位置:在方法定义的上面
特点:1.在目标方法之后执行的
2.能够获取目标方法的返回值,可以根据这个返回值做不同的处理功能
3.可以修改这个返回值
SomeService.java
package com.node.ba02;
public interface SomeService {
void doSome(String name,Integer age);
String doOther(String name,Integer age);
}
SomeServiceImpl.java
package com.node.ba02;
public class SomeServiceImpl implements SomeService {
@Override
public void doSome(String name,Integer age) {
//给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
System.out.println("===目标方法doSome===");
}
@Override
public String doOther(String name, Integer age) {
System.out.println("===目标方法doOther===");
return "abcd";
}
}
MyAspect.java
package com.node.ba02;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import java.util.Date;
@Aspect
public class MyAspect {
@AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",
returning = "res")
public void myAfterReturning(Object res){
//Object res:是目标方法执行后的返回值,根据返回值做你的切面的功能处理
System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);
if(res.equals("abcd")){
//做一些功能
}else{
//做其他功能
}
}
}
测试代码
package com.node;
import com.node.ba02.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest02 {
@Test
public void test01(){
String config="applicationContext.xml";
ApplicationContext ac=new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeService proxy= (SomeService) ac.getBean("someService");
//通过代理的对象执行方法,事项目标方法执行时,增强了功能
String str= proxy.doOther("zhangsan",30);
System.out.println("str==="+str);
}
}
@Around 环绕通知
环绕通知方法的定义格式
* 1.public
* 2.必须有一个返回值,推荐使用Object
* 3.方法名称自定义
* 4.方法有参数,固定的参数 proceedingJoinPoint
*
@Around : 环绕通知
* 属性:value 切入点表达式
* 位置:在方法定义的上面
* 特点:1.它是功能最强的通知
* 2.在目标方法前和后都能增强功能
* 3.控制目标方法是否被调用执行
* 4.修改原来的目标方法发的执行结果。影响最后的调用结果
环绕通知,等同于jdk动态代理的,InvocationHandler接口
参数:ProceedingJoinPoint 就等同于Method
作用:执行目标方法的
返回值:就是目标方法的执行结果,可以被修改
环绕通知:经常做事务,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事务
SomeService.java
package com.node.ba03;
public interface SomeService {
void doSome(String name,Integer age);
String doOther(String name,Integer age);
String doFirst(String name,Integer age);
}
SomeServiceImpl.java
package com.node.ba03;
public class SomeServiceImpl implements SomeService {
@Override
public void doSome(String name,Integer age) {
//给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
System.out.println("===目标方法doSome===");
}
@Override
public String doOther(String name, Integer age) {
System.out.println("===目标方法doOther===");
return "abcd";
}
@Override
public String doFirst(String name, Integer age) {
System.out.println("===业务方法doFirst===");
return "doFirst";
}
}
MyAspect.java
package com.node.ba03;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import java.util.Date;
@Aspect
public class MyAspect {
@Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
String name=null;
Object args[]=pjp.getArgs();
if(args!=null && args.length>1){
Object arg=args[0];
name=(String) arg;
}
//实现环绕通知
Object result=null;
System.out.println("环绕通知:在目标方法前,输出时间"+new Date());
//1.目标方法调用
if("zhaosi".equals(name)){
//符合条件,调用目标方法
result =pjp.proceed();//等同于method.invoke();或Object result=doFirst();
}
System.out.println("环绕通知:在目标方法后,输出时间");
//2.在目标方法的前或后加入功能
//修改目标方法的执行结果,影响方法的最后调用结果
if(result!=null){
result="123123";
}
//返回目标方法的执行结果
return result;
}
}
测试代码
package com.node;
import com.node.ba03.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest03 {
@Test
public void test01(){
String config="applicationContext.xml";
ApplicationContext ac=new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeService proxy= (SomeService) ac.getBean("someService");
//通过代理的对象执行方法,事项目标方法执行时,增强了功能
String str= proxy.doFirst("zhaosi",40);//就是调用了myArround()
System.out.println("str==="+str);
}
}