1 aop编程的一些概念
2 使用 Spring 创建代理对象(注解方式)
3 关于切入点相关的参数的说明
4 环绕通知
一、AOP编程的一些概念
为什么要用AOP:可以看这篇文章(26条消息) 为什么需要使用Spring AOP(代理模式)_清思越的博客-CSDN博客
Aspect切面:横切性关注点的抽象
Joinpoint连接点:指的是拦截到的点,在spring中,指的就是被拦到的方法,比如addUser()等
pointCut 切入点:指的是对那些连接点进行拦截,比如,对所有的以get开头的方法进行计时
Advice 通知:拦到 Joinpoint 以后,要做的动作就叫通知,有前置通知、后置通知、最终通知、例外通知、环绕通知
Target 被代理的目标对象
Weave 织入:将Aspect 应用到目标对象的过程,经过织入以后,代理对象就产生了
二、使用 spring 创建代理对象(注解方式)
spring中进行AOP 编程,有两种方式:
注解方式
XML配置方式
1)注解方式:
(1) 要导入相应的jar,加入配置构建路径
aspectjweaver-1.8.9.jar
cglib-3.2.2.jar
如果用maven,则依赖如下
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.2</version>
</dependency>
(2)创建spring的主配置文件,打开AOP的名称空间
<?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 http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<context:component-scan base-package="com.dao"/>
<context:component-scan base-package="com.servlet"/>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
(3)切面类
package com.aop;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect //必须要加入切面注解
@Component //交给spring管理
public class Myaspect {
/*excution表示要拦截的正在执行的方法
excution(int)里面的int表示要拦截的方法的返回值
excution(*)表示不管什么样的返回值都拦截
*/
/*
* excution(“返回值 拦截的方法”)
excution("* com.dao.UserDao.*(int,String)")下面对应
excution("返回值 拦截那个类下的那个方法.*(*表示所有方法)(int,String代表这个方法的返回值是什么,不在意返回值的话就(..))
*/
@Pointcut("execution(* com.dao.UserDaoImpl.*(..))") //切入点,想要对那些方法进行拦截
private void anyMethod() {}
//我要拦的不是pointCut里面的这些方法吗,那么在拦截这些方法之前我要执行我下面这个事
@Before("anyMethod()")
public void beforeMethod() {
System.out.println("前置通知触发了");
}
//后置通知:和前置通知相对应
@AfterReturning("anyMethod()")
public void afterMethod() {
System.out.println("后置通知触发了");
}
//最终通知
@After("anyMethod()")
public void finallyMethod() {
System.out.println("最终通知触发了");
}
//例外通知
@AfterThrowing("anyMethod()")
public void execptionMethod() {
System.out.println("出现异常,例外通知触发了");
}
}
execution() //表示拦截正在执行的方法
* //表示不管方法的返回值是什么都拦
com.dao.UserDaoImpl //表示拦截哪个包下的哪个类
* 表示不管这个方法的名字是什么
(..) //表示不管方法的参数是什么
3 关于切入点相关的参数的说明
//例 通过 JoinPoint 叁数,得到方法的名称和得到目标对象
@Before("anyMethodAAA()")
public void beforMethod(JoinPoint point) {
//得到被拦截的方法的名称
String methodName=point.getSignature().getName();
if("delUser".equals(methodName)) {
System.out.println("将调用删除方法,日志已记录...");
}
//得到目标对象
UserDaoImpl imp=(UserDaoImpl)point.getTarget();
System.out.println("目标对象的userName属性值是:"+imp.getUserName());
//得到方法的参数
Object [] params =point.getArgs();
for(Object param:params) {
System.out.println(param);
}
System.out.println("前置通知触发了");
}
//例子 进一步限定切入点的条件 ,只拦截带两个参数的
@Before("anyMethodAAA()&&args(a,b)") //前置通知
public void beforMethod(String a,String b) {
System.out.println("得到的参数是"+ a +" 和 "+ b);
System.out.println("前置通知触发了");
}
这个通知,将只能作用于带两个 String 参数的方法
//例子 取得方法执行的返回值
@AfterReturning(pointcut = "anyMethodAAA()",returning = "result") //后置通知
public void afterMethod(int result) {
System.out.println("方法的返回值是 "+result);
System.out.println("后置通知触发了");
}
经过上面的处理以后,只有接口中有int型返回值的方法才能触发上面的后置通知,比如下面这个方法
public int getUserCount() {
System.out.println("getUserCount 执行了");
return 9/3;
}
//例子 取得异常信息
@AfterThrowing(pointcut="anyMethodAAA()",throwing = "ex")
public void exceptionMethod(Exception ex) {
System.out.println("出错,异常信息是"+ex.getMessage());
System.out.println("出现异常,例外通知触发了");
}
4、环绕通知
@Pointcut("execution(* com.dao.UserDaoImpl.*(..))")
private void anyMethodAAA() {}
@Around("anyMethodAAA()")
public Object aroundMethod(ProceedingJoinPoint point) {
Object result=null;
String methodName=point.getSignature().getName();
System.out.println("当前拦到的方法是:"+methodName);
try {
System.out.println("环绕通知 前置通知触发了");
//让目标方法执行
result=point.proceed();
System.out.println("环绕通知 后置通知触发了");
}catch(Throwable ex) {
ex.printStackTrace();
System.out.println("环绕通知 例通知触发了");
}finally {
System.out.println("环绕通知 最终知触发了");
}
return result;
}
实际项目中,我们哪些地方需要做切面呢?
1)数据访问层
2)控制层
3)业务层
一般来说AOP主要用于日志记录、权限控制