2021SC@SDUSC 此篇记录:AOP by冰弦qwq
AOP
几个基础:
-
切入点(Pointcut) 在哪些类,哪些方法上切入(where) 通知(Advice) 在方法执行的什么实际(when:方法前/方法后/方法前后)做什么(what:增强的功能) -
切面(Aspect) 切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强! -
织入(Weaving) 把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成) -
实现底层原理(JDK动态代理)
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");
}
}
-
创建增强类(编写增强逻辑)
<!--开启注解扫描-->
<context:component-scan base-package="AOP"></context:component-scan>
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
配置不同类型的通知 在我们的增强类里面,在作为通知方法上面添加通知类型注释,使用切入点表达式配置 @Component
@Aspect
public class UserProxy {
@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(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
|