AOP基本知识
知识点1:概念
- AOP:面向切面编程,利用AOP可以对业务逻辑的各个部分隔离开,降低代码的耦合度,提高可复用性。
- 个人理解:不修改源代码,而是在主干功能里添加新的功能,很想设计模式中的装饰者设计。
知识点2:底层原理
- 使用到了动态代理
- 情况一:有接口,使用JDK动态代理;-->创建接口实现类代理对象,增强类的方法
- 情况二:无接口,使用CGLIB动态代理。-->创建子类的代理对象,增强类的方法
知识点3: JDK动态代理实现
代码:
package com.guodaxia.AOP.dao; //接口 public interface UserDao { int add(int a,int b); int id(int id); } //实现类 public class UserDaoImpl implements UserDao{ @Override public int add(int a, int b) { return a+b; } @Override public int id(int id) { id +=1; return id; } }
代理类
package com.guodaxia.AOP.dao; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Objects; public class JDKProxy { public static void main(String[] args) { //创建接口实现类代理对象 //实现类的接口 Class[] interfaces = {UserDao.class}; //第三个参数:代理类的接口InvocationHandler对象,由于接口不能直接创建对象,这里使用匿名内部类 UserDao dao= (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() { //将旧的业务逻辑对象传递 //匿名内部类不允许有构造方法,写一个静态代码块, // 在静态代码块new想要代理的对象,把他赋值给代码块外部的变量 UserDao userDao; { Objects obj; userDao = new UserDaoImpl(); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法之前执行..." + method.getName() + ":传递的参数..." + Arrays.toString(args)); //增强业务逻辑中 Object res = method.invoke(userDao, args); System.out.println("方法之后执行..." + method.getName() +":"+ res); return res; } }); int result = dao.add(1,1); System.out.println(result); System.out.println("-----------------"); int id = dao.id(006); System.out.println(id); } }
总结
- 动态代理的好处在于可以在源代码的基础上,实现添加新功能;
- java包下有Proxy类用于用于创建代理;
- newProxyInstance(classLoad,interfaces,增强业务类)。
知识点3:术语
- 连接点:能够被增强的方法;
- 切入点:实际被增强的方法;
- 通知(增强):实际增强的逻辑部分,如日志更新,事务;
通知类型:
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
- 切面:把通知应用到切入点的过程。
知识点4:AOP操作
准备
- 使用AspectJ框架+spring框架完成AOP操作
- 导入依赖
aop的jar包:
[com.springsource.net.sf.cglib-2.2.0.jar](......\dataFile\spring5\资料\资料\2 其他jar包\aop的jar包\com.springsource.net.sf.cglib-2.2.0.jar)
[com.springsource.org.aopalliance-1.0.0.jar](......\dataFile\spring5\资料\资料\2 其他jar包\aop的jar包\com.springsource.org.aopalliance-1.0.0.jar)
[com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar](......\dataFile\spring5\资料\资料\2 其他jar包\aop的jar包\com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar)
spring的jar包:
- 切入点的表达式:知道对哪个类里面的 哪个方法进行增强。
- 切入点语法结构:execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])
@Aspect注解**
步骤:
- 创建需要被增强的类和方法;
//被增强的类 @Component public class User { //被增强的方法 public void add(){ System.out.println("add.........."); } }
- 创建增强类,并编写增强业务逻辑代码;
//增强的类 @Component @Aspect public class UserProxy { //不同的方法代表着不同通知类型 //1. 前置通知 @Before(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())") public void before(){ System.out.println("before........."); } //2. 后置通知 //3. 环绕通知 //4. 异常通知 //5. 终止通知 }
- xml开启注解扫描 or 创建配置类开启注解扫描;
<?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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <!--开启注解扫描--> <context:component-scan base-package="com.guodaxia.AOP.aopaspect"></context:component-scan> </beans>
-
使用四大注解任何一个创建User和UserProxy对象;
-
在增强类上面添加注解@Aspect,自动生成代理对象;
-
在spring配置中开启生成代理对象;
-
配置不同类型的通知
- 即在增强类中的方法上方添加通知类型注解,使用切入点表达式配置。
//不同的方法代表着不同通知类型 //1. 前置通知 @Before(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())") public void before(){ System.out.println("before........."); } //2. 后置通知 @After(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())") public void after(){ System.out.println("after ......."); } //5. 最终通知 @AfterReturning(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())") public void afterReturning(){ System.out.println("afterReturning ......."); } //3. 环绕通知 @Around(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())") public void around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("Around before,,,,"); pjp.proceed();//被增强的方法执行 System.out.println("Around after......"); } //4. 异常通知 @AfterThrowing(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())") public void afterThrowing(){ System.out.println("AfterThrowing ......."); }
执行结果
Around before,,,, before......... add.......... Around after...... after ....... afterReturning .......
总结:
- 一步一步慢慢来,分开配置,总能分解一个复杂的问题,总能汇成解决一个复杂的问题。
- 有些bug很小,跟着步骤一步一步检验,总能找到问题所在。
比任何人都要努力
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)