2021SC@SDUSC
此篇记录:AOP by冰弦qwq
几个基础:
-
切入点(Pointcut)
在哪些类,哪些方法上切入(where)
通知(Advice)
在方法执行的什么实际(when:方法前/方法后/方法前后)做什么(what:增强的功能) -
切面(Aspect)
切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强! -
织入(Weaving)
把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成) -
1、使用JDK动态代理,使用Proxy类里面的方法创建代理对象
static newProxyInstance(ClassLoader, Class>[], InvocationHandler);
有三个参数:
- ClassLoader : 类加载器
- Class>[] : 多个接口
- InvocationHandler : 实现这个接口,创建代理对象,写增强方法
2、编写JDK动态代理
(1)创建接口,定义方法
(2)创建接口实现类,实现方法
(3)使用proxy
public class MyProxy {
public static void main(String[] args) {
Class[] interfaces = {UserInter.class};
UserImpl user = new UserImpl();
UserInter inter = (UserInter) Proxy.newProxyInstance(MyProxy.class.getClassLoader(), interfaces, new UserInterProxy(user));
inter.add(1, 2);
inter.update("123");
}
}
// 创建代理
class UserInterProxy implements InvocationHandler {
private Object object;
// 把需要代理的对象传入
// 通过有参构造进行传递
public UserInterProxy(Object o) {
this.object = o;
}
// 写增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在方法之前
System.out.println("invoke before method : " + method.getName() + ":传递的参数..." + Arrays.toString(args));
Object res = method.invoke(object,args);
System.out.println(res);
// 在方法之后
System.out.println("方法执行之后 : " + object.toString());
return res;
}
}
术语
- 连接点
类里面哪些方法可以被增强,这些方法称为连接点
- 切入点
实际被增强的方法,称为切入点
- 通知(增强)
(1)实际增强的逻辑部分称为通知
(2)通知有多种类型
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知 finally
- 切面
是一个动作:把通知应用到切入点的过程
Spring框架中,一般基于AspectJ实现AOP操作
(1)什么是AspectJ
- AspectJ不是Spring组成部分,是一个独立的AOP框架,一般把他和Spring一起使用,进行AOP操作
操作:
(1)基于xml配置文件实现
(2)基于注解方式实现(常用)
步骤:
- 引入依赖
切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构:
execution([权限修饰符][返回类型][类全路径][方法全名]([参数列表]))
示例一:
对com.company.dao.UserDao类里面的add进行增强
execution(* com.company.dao.UserDao.add(..)) // *号表示所有的修饰符
示例二:
对com.company.dao.UserDao类里面的所有方法进行增强
execution(* com.company.dao.UserDao.*(..)) // *号表示所有的修饰符
示例三:
对com.company.dao.包内所有类类里面的所有方法进行增强
execution(* com.company.dao.*.*(..)) // *号表示所有的修饰符基于注解操作AspectJ
-
创建类,在类里面定义方法
public class User { public void add() { System.out.println("User.add"); } } -
创建增强类(编写增强逻辑)
-
在增强类里面,创建方法,让不同方法代表不同通知类型
public class UserProxy { // 前置通知 public void before() { System.out.println("before..."); } }
-
-
使用注解创建User和UserProxy对象
-
在增强类中添加注解@Aspect
@Component public class User { public void add() { System.out.println("User.add"); } } @Component @Aspect public class UserProxy { // 前置通知 public void before() { System.out.println("before..."); } } -
在Spring配置文件中开启生成代理对象
-
配置不同类型的通知
在我们的增强类里面,在作为通知方法上面添加通知类型注释,使用切入点表达式配置
@Component @Aspect public class UserProxy { // 前置通知 // @Before注解表示作为前置通知 @Before(value = "execution(* AOP.User.add(..))") public void before() { System.out.println("before..."); } @AfterReturning(value = "execution(* AOP.User.add(..))") public void afterRet() { System.out.println("after Returning..."); } @After(value = "execution(* AOP.User.add(..))") public void after() { System.out.println("after..."); } @AfterThrowing(value = "execution(* AOP.User.add(..))") public void afterThrowing() { System.out.println("throw..."); } @Around(value = "execution(* AOP.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("around bef..."); proceedingJoinPoint.proceed(); System.out.println("around aft"); } } // ... 结果 : around bef... before... User.add after Returning... after... around aft
注意,如果报错,则afterReturning和aournd后半段不会执行,afterReturning表示方法执行成功才会执行。
而after可以成为最终通知,一定会执行
-
对于相同切入点进行抽取
// 相同切入点抽取 @Pointcut(value = "execution(* AOP.User.add(..))") public void pointDemo() { } // 前置通知 // @Before注解表示作为前置通知 @Before(value = "pointDemo()") public void before() { System.out.println("before..."); } -
多个增强类对同一个方法进行增强,可以设置优先级
在增强类上面添加注解@Order(数字值类型),数字越小优先级越高 高优先级会包裹低优先级.
注释实现扫描包配置和启动AspectJ服务:
@Configuration
@ComponentScan(value = {"AOP"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
...
ApplicationContext context = new AnnotationConfigApplicationContext(ConfigAop.class);
User user = context.getBean("user", User.class);
user.add();
基于配置文件操作AOP
by@冰弦qwq



