第十六章 Spring动态代理详解
1.额外功能详解#
-
MethodBeforeAdvice分析
public class Before implements MethodBeforeAdvice { /* 作用: 把需要在原始方法执行之前运行的额外功能,书写在before方法中 Method: 增加额外功能的那个原始方法 Object[]: 增加额外功能的那个原始方法的参数 Object: 增加额外功能的原始方法所在的原始对象 这些参数根据需要进行使用 */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("-----log:MethodBeforeAdvice-------"); } }
-
MethodInterceptor(方法拦截器)
public class Arround implements MethodInterceptor { /* invoke方法: 将额外功能书写在invoke方法中,额外功能可以运行在原始方法之前 之后 以及前后都可以运行 MethodInvocation: 额外功能所增加的那个原始方法 invocation.proceed()--->运行对应的原始方法 由这个方法,就可以区分额外功能的运行时机: 额外功能写在invocation.proceed()之前,表示先运行额外功能,再运行原始方法 额外功能写在invocation.proceed()之后.表示先运行原始方法,再运行额外功能 额外功能写在invocation.proceed()之前和之后,表示额外功能前后都执行 返回值: Object: 原始方法的返回值 invocation.proceed()代表原始方法的运行,我们只要返回该方法的执行结果即可 */ @Override public Object invoke(MethodInvocation invocation) throws Throwable { //额外方法 Object proceed = invocation.proceed(); //额外方法 return proceed; } }
Spring工厂配置与MethodBeforeAdvice一样 事务在原始方法执行之前之后,都要运行 额外功能可能运行在原始方法抛出异常的时候 @Override public Object invoke(MethodInvocation invocation) throws Throwable { Object proceed = null; try { proceed = invocation.proceed(); } catch (Throwable e) { System.out.println("原始方法抛出异常时运行额外方法!"); e.printStackTrace(); } return proceed; }
MethodInterceptor影响原始方法的返回值: 原始方法的返回值(invocation.proceed()),直接作为invoke方法的返回值返回,MethodInterceptor不会影响原始方法的返回值 invoke方法中,不要将原始方法的返回值作为invoke方法的返回值返回即可
2.切入点详解#
切入点决定额外功能加入的位置(哪些方法)
<aop:pointcut id="before" expression="execution(* *(..))"/>
1. execution(): 切入点函数
2. * *(..): 切入点表达式
2.1 切入点表达式#
-
方法切入点表达式
* *(..) --->所有方法 * -->修饰符返回值 * -->方法名 () -->参数列表 .. -->对于参数没有要求(个数,类型都没有要求)
-
定义login方法作为切入点
* login(..)
-
定义login方法, 且login方法有两个字符串类型的参数, 作为切入点
* login(String,String) # 注意: 非java.lang包中的类型,必须写全限定名 * register(com.dong.proxy.User) # 注意: ..可以和具体的参数连用 * login(String,..) -->login(String) login(String,String) login(String,com.dong.proxy.User)
-
这种切入点表达式不精准(同名干扰)
-
精准的切入点表达式
修饰符返回值 包.类.方法(参数) * com.baizhiedu.a.UserServiceImpl.login(String,String)
-
-
类切入点
指定类作为额外功能的切入点,这个类中所有方法都会添加额外功能 在调用这个类时,会添加额外功能,在调用其他类时,不会添加额外功能
-
语法1
# UserServiceImpl类中所有方法加入额外功能 * com.baizhiedu.a.UserServiceImpl.*(..)
-
语法2
# 忽略包,给不同包中的同名类中的所有方法添加额外功能 1. 类只存在一级包中 com.UserServiceImpl * *.UserServiceImpl.*(..) 2. 类在多级包 com.baizhiedu.proxy.UserServiceImpl * *..UserServiceImpl.*(..)
-
-
包切入点表达式
指定包作为额外功能的切入点,包中所有类所有方法,都将加入额外功能
-
语法1
* com.baizhiedu.proxy.*.*(..) # 注意: 切入点包中的所有类,必须在proxy包中,不能在proxy包的子包中
-
语法2
# 让当前包的子包生效 * com.baizhiedu.proxy..*.*(..)
-
2.2 切入点函数#
用于执行切入点函数
-
execution
最为重要的切入点函数,功能最全 可以执行 方法切入点表达式 类切入点表达式 包切入点函数 弊端: execution执行切入点表达式,书写麻烦 注意: 其他切入点函数 简化的是execution书写复杂度,功能一致
-
args
作用: 主要用于方法参数的匹配 切入点: 必须是两个字符串类型的参数 execution(* *(String,String)) args(String,String)
-
within
作用: 主要用于类\包切入点表达式的匹配 切入点: UserServiceImpl这个类 execution(* *..UserServiceImpl.*(..)) within(*..UserServiceImpl) 切入点: com.baizhiedu.proxy这个包 execution(* com.baizhiedu.proxy..*.*) within(com.baizhiedu.proxy..)
-
@annotation
作用: 为具有特殊注解的方法加入额外功能 切入点: 加有com.baizhiedu.Log这个注解的方法 @annotation(com.baizhiedu.Log)
-
切入点函数的逻辑运算
指的是 整合多个切入点函数一起配合工作,进而完成更为复杂的需求
-
and与操作
案例: 方法名为login,同时有两个字符串参数 1. execution(* login(String,String)) 2. execution(* login(..)) and args(String,String) 注意: 与操作不能用于同种类型的切入点函数
-
or或操作
案例: register方法和login方法作为切入点 execution(* register(..)) or execution(* login(..))
-
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步