切面
通常是一个类,里面定义切入点和通知
package biyeseason.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class loginProxy{
public static Object proxy(Object target){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new loginProxyHandler(target));
}
private static class loginProxyHandler implements InvocationHandler{
private Object target;
public loginProxyHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//通知:doBefore()前置增强
doBefore();
//服务
Object res = method.invoke(target,args);
//通知:doAfter()后置增强
doAfter();
return res;
}
private void doAfter() {
System.out.println("after...");
}
private void doBefore() {
System.out.println("before...");
}
}
}
连接点
程序执行过程中明确的点,一般是方法的调用
loginServiceImpl lSImpl = new loginServiceImpl();
loginService lS = (loginService) loginProxy.proxy(lSImpl);
login l = new login("17251102152","123456");
boolean a = lS.login(l.getUsername(),l.getPassword());
System.out.println(a);
前言
导包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
execution表达式
execution(* com.sample.service.impl..*.*(..))
解释如下:
符号 | 含义 |
---|---|
execution() | 表达式的主体 |
第一个*符号 | 表示返回值的类型任意 |
com.sample.service.impl | AOP所切的服务的包名,即,我们的业务部分 |
包名后面的”..“ | 表示当前包及子包 |
第二个*符号 | 表示类名,即所有类 |
.*(..) | 表示任何方法名,括号表示参数,两个点表示任何参数类型 |
基本语法格式为:
execution(<修饰符模式>? <返回类型模式> <类路径匹配>? <方法名模式>(<参数模式>)<异常模式>?) 除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。异常模式>参数模式>方法名模式>类路径匹配>返回类型模式>修饰符模式>
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?)
returning type pattern,name pattern, and parameters pattern是必须的. ret-type-pattern:可以为表示任何返回值,全路径的类名等. name-pattern:指定方法名,*代表所有,set*代表以set开头的所有方法. parameters pattern:指定方法参数(声明的类型),(..)代表所有参数,(*)代表一个参数,(*,String)代表第一个参数为任何值,第二个为String类型.
实现代码
package springMVCmybatis.com.my.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.springframework.core.annotation.Order;
@Aspect
// 切面执行顺序
@Order(3)
public class MyAopTest {
@Pointcut("execution(* springMVCmybatis..addController.addEmp(..))")
private void pointCutMethod() {
}
@Pointcut("execution(* springMVCmybatis.com.my.aop.UserServiceImp.*(..))")
private void testAOP() {
}
/*
* 声明前置通知 ,JoinPont是srpring提供的静态变量,
* 通过joinPoint参数可以获得目标方法的类名,方法参数,方法名等信息,这个参数可有可无。
*/
@Before("pointCutMethod() || testAOP()")
public void doBefore(JoinPoint joinPoint) {
System.out.println("@Before:开始添加--order=3");
}
//声明后置通知 ,如果result的类型与proceed执行的方法返回的参数类型不匹配那么就不会执行这个方法
@AfterReturning(pointcut = "pointCutMethod() || testAOP()", returning = "result")
public void doAfterReturning(String result) {
System.out.println("@AfterReturning:后置通知--order=3");
System.out.println("---" + result + "---");
}
//声明例外通知
@AfterThrowing(pointcut = "pointCutMethod() || testAOP()", throwing = "e")
public void doAfterThrowing(Exception e) {
System.out.println("@AfterThrowing:例外通知--order=3");
System.out.println(e.getMessage());
}
//声明最终通知
@After("pointCutMethod() || testAOP()")
public void doAfter() {
System.out.println("@After:最终通知--order=3");
}
/*
* 声明环绕通知
* 参数必须是ProceedingJoinPoint,通过该对象的proceed()方法来执行目标函数,
* proceed()的返回值就是环绕通知的返回值,proceedingJoinPoint是个接口,
* implement JoinPoint,所以也可以获得目标函数的类名,方法名等参数。
*/
@Around("pointCutMethod() || testAOP()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("@Around:进入方法---环绕通知--order=3");
Object o = pjp.proceed();
System.out.println("@Around:退出方法---环绕通知--order=3");
return o;
}
}
上面的例子中,定义了order=3,重新创建一个切面,定义order=6,执行的结果是:
@Around:进入方法---环绕通知--order=3
@Before:开始添加--order=3
@Around:进入方法---环绕通知--order=6
@Before:开始添加--order=6
============执行业务方法findUser,查找的用户是:张三=============
@Around:退出方法---环绕通知--order=6
@After:最终通知--order=6
@AfterReturning:后置通知--order=6
---张三---
@Around:退出方法---环绕通知--order=3
@After:最终通知--order=3
@AfterReturning:后置通知--order=3
---张三---
@Around:进入方法---环绕通知--order=3
@Before:开始添加--order=3
@Around:进入方法---环绕通知--order=6
@Before:开始添加--order=6
============执行业务方法addUser=============
@After:最终通知--order=6
@AfterThrowing:例外通知--order=6
null
@After:最终通知--order=3
@AfterThrowing:例外通知--order=3
null