Spring AOP 切点详解
本文内容
- Spring 10种切点表达式详解
- 切点的组合使用
- 公共切点的定义
声明切点@Poincut
@Poincut 的使用格式如下:
@Poincut("PCD") // 切点表达式 表示对哪些方法进行增强
public void pc(){} // 切点签名,返回值必须为void
10种切点表达式
AspectJ的切点指示符AspectJ pointcut designators (PCD) ,也就是俗称的切点表达式,Spring中支持10种,如下表:
表达式类型 |
作用 |
匹配规则 |
execution |
用于匹配方法执行的连接点 |
|
within |
用于匹配指定类型内的方法执行 |
within(x)匹配规则target.getClass().equals(x) |
this |
用于匹配当前AOP代理对象类型的执行方法,包含引入的接口类型匹配 |
this(x)匹配规则: |
target |
用于匹配当前目标对象类型的执行方法,不包括引入接口的类型匹配 |
target(x)匹配规则:x.getClass().isAssignableFrom(target.getClass()); |
args |
用于匹配当前执行的方法传入的参数为指定类型的执行方法 |
传入的目标位置参数.getClass().equals(@args(对应的参数位置的注解类型))!= null |
@target |
用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解 |
target.class.getAnnotation(指定的注解类型) != null |
@args |
用于匹配当前执行的方法传入的参数持有指定注解的执行 |
传入的目标位置参数.getClass().getAnnotation(@args(对应的参数位置的注解类型))!= null |
@within |
用于匹配所有持有指定注解类型内的方法 |
被调用的目标方法Method对象.getDeclaringClass().getAnnotation(within中指定的注解类型) != null |
@annotation |
用于匹配当前执行方法持有指定注解的方法 |
target.getClass().getMethod("目标方法名").getDeclaredAnnotation(@annotation(目标注解))!=null |
bean |
Spring AOP扩展的,AspectJ没有对应的指示符,用于匹配特定名称的Bean对象的执行方法 |
ApplicationContext.getBean("bean表达式中指定的bean名称") != null |
简单介绍下AspectJ中常用的3个通配符:
- *:匹配任何数量的字符
- ..:匹配任何数量字符的重复,如任何数量子包,任何数量方法参数
- +:匹配指定类型及其子类型,仅作为后缀防过载类型模式后面。
execution
用于匹配方法执行,最常用。
格式说明
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?)
- 其中带 ?号的 modifiers-pattern?,declaring-type-pattern?,throws-pattern?是可选项
- ret-type-pattern,name-pattern, parameters-pattern是必选项
- modifier-pattern? 修饰符匹配,如public 表示匹配公有方法,*表示任意修饰符
- ret-type-pattern 返回值匹配,* 表示任何返回值,全路径的类名等
- declaring-type-pattern? 类路径匹配
- name-pattern 方法名匹配,* 代表所有,xx*代表以xx开头的所有方法
- (param-pattern) 参数匹配,指定方法参数(声明的类型),(..)代表所有参数,(*,String)代表第一个参数为任何值,第二个为String类型,(..,String)代表最后一个参数是String类型
- throws-pattern? 异常类型匹配
举例说明
public class PointcutExecution {// com.crab.spring.aop.demo02包下任何类的任意方法@Pointcut("execution(* com.crab.spring.aop.demo02.*.*(..))")public void m1(){}// com.crab.spring.aop.demo02包及其子包下任何类的任意方法@Pointcut("execution(* com.crab.spring.aop.demo02..*.*(..))")public void m2(){}// com.crab.spring.aop包及其子包下IService接口的任意无参方法@Pointcut("execution(* com.crab.spring.aop..IService.*(..))")public void m3(){}// com.crab.spring.aop包及其子包下IService接口及其子类型的任意无参方法@Pointcut("execution(* com.crab.spring.aop..IService+.*(..))")public void m4(){}// com.crab.spring.aop.demo02.UserService类中有且只有一个String参数的方法@Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(String))")public void m5(){}// com.crab.spring.aop.demo02.UserService类中参数个数为2且最后一个参数类型是String的方法@Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(*,String))")public void m6(){}// com.crab.spring.aop.demo02.UserService类中最后一个参数类型是String的方法@Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(..,String))")public void m7(){}
}
within
格式说明
within(类型表达式):目标对象target的类型是否和within中指定的类型匹配
匹配规则: target.getClass().equals(within表达式中指定的类型)
举例说明
public class PointcutWithin {// 匹配 com.crab.spring.aop.demo02包及其子包下任何类的任何方法@Pointcut("within(com.crab.spring.aop.demo02..*)")public void m() {}// 匹配m.crab.spring.aop.demo02包及其子包下IService类型及其子类型的任何方法@Pointcut("within(com.crab.spring.aop.demo02..IService+)")public void m2() {}// 匹配com.crab.spring.aop.demo02.UserService类中所有方法,不含其子类@Pointcut("within(com.crab.spring.aop.demo02.UserService)")public void m3() {}
}
this
格式说明
this(类型全限定名):通过aop创建的代理对象的类型是否和this中指定的类型匹配;this中使用的表达式必须是类型全限定名,不支持通配符。
this(x)的匹配规则是:x.getClass.isAssingableFrom(proxy.getClass)
举例说明
package com.crab.spring.aop.demo02.aspectj;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.ClassUtils;/*** @author zfd* @version v1.0* @date 2022/2/6 21:41*/
@Aspect
public class PointcutThis {interface I1{void m();}static class C1 implements I1{@Overridepublic void m() {System.out.println("C1 m()");}}// 匹配 I1类型或是其子类@Pointcut("this(com.crab.spring.aop.demo02.aspectj.PointcutThis.I1)")public void pc(){}@Before("pc()")public void before(JoinPoint joinPoint) {System.out.println("before: " + joinPoint);}public static void main(String[] args) {C1 target = new C1();AspectJProxyFactory proxyFactory = new AspectJProxyFactory();proxyFactory.setTarget(target);// proxyFactory.setProxyTargetClass(true);// 获取C1上所有接口 spring工具类提供的方法Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(target);// 设置代理接口proxyFactory.setInterfaces(allInterfaces);// 添加切面proxyFactory.addAspect(PointcutThis.class);// 获取代理I1 proxy = proxyFactory.getProxy();// 调用方法proxy.m();System.out.println("JDK代理? " + AopUtils.isJdkDynamicProxy(proxy));System.out.println("CGLIB代理? " + AopUtils.isCglibProxy(proxy));//判断代理对象是否是C1类型的System.out.println(C1.class.isAssignableFrom(proxy.getClass()));}}
来观察下输出
before: execution(void com.crab.spring.aop.demo02.aspectj.PointcutThis$C1.m())
C1 m()
JDK代理? false
CGLIB代理? true
true
使用JDK动态代理生成的代理对象,其类型是I1类型。
思考下:将切点表达式改成下面的输出结果是?
// 匹配 C1类型或是其子类
@Pointcut("this(
com.crab.spring.aop.demo02.aspectj.PointcutThis.C1)")
public void pc(){}
target
格式说明
target(类型全限定名):判断目标对象的类型是否和指定的类型匹配;表达式必须是类型全限定名,不支持通配符。
target(x)匹配规则:x.getClass().isAssignableFrom(target.getClass());
举例说明
@Aspect
public class PointcutTarget {interface I1{void m();}static class C1 implements I1{@Overridepublic void m() {System.out.println("C1 m()");}}// 匹配目标类型必须是@Pointcut("target(com.crab.spring.aop.demo02.aspectj.PointcutTarget.C1)")public void pc(){}@Before("pc()")public void before(JoinPoint joinPoint) {System.out.println("before: " + joinPoint);}public static void main(String[] args) {C1 target = new C1();AspectJProxyFactory proxyFactory = new AspectJProxyFactory();proxyFactory.setTarget(target);proxyFactory.setProxyTargetClass(true);// 获取C1上所有接口 spring工具类提供的方法Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(target);// 设置代理接口proxyFactory.setInterfaces(allInterfaces);// 添加切面proxyFactory.addAspect(PointcutTarget.class);// 获取代理I1 proxy = proxyFactory.getProxy();// 调用方法proxy.m();System.out.println("JDK代理? " + AopUtils.isJdkDynamicProxy(proxy));System.out.println("CGLIB代理? " + AopUtils.isCglibProxy(proxy));//判断代理对象是否是C1类型的System.out.println(C1.class.isAssignableFrom(target.getClass()));}}
输出结果
before: execution(void com.crab.spring.aop.demo02.aspectj.PointcutTarget$C1.m())
C1 m()
JDK代理? false
CGLIB代理? true
true
args
格式说明
args(参数类型列表)匹配当前执行的方法传入的参数是否为args中指定的类型;参数类型列表中的参数必须是类型全限定名,不支持通配符;args属于动态切入点,也就是执行方法的时候进行判断的,开销非常大,非特殊情况最好不要使用。
args(String) // 方法个数为1,类型是String
args(*,String) // 方法参数个数2,第2个是String类型
args(..,String) // 方法个数不限制,最后一个必须是String
举例说明
package com.crab.spring.aop.demo02.aspectj;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.ClassUtils;/*** @author zfd* @version v1.0* @date 2022/2/6 21:41*/
@Aspect
public class PointcutArgs {interface I1{void m(Object name);}static class C1 implements I1{@Overridepublic void m(Object name) {String type = name.getClass().getName();System.out.println("C1 m() 参数类型 " + type);}}// 匹配方法参数个数1且类型是必须是String@Pointcut("args(String)")public void pc(){}@Before("pc()")public void before(JoinPoint joinPoint) {System.out.println("before: " + joinPoint);}public static void main(String[] args) {C1 target = new C1();AspectJProxyFactory proxyFactory = new AspectJProxyFactory();proxyFactory.setTarget(target);proxyFactory.setProxyTargetClass(true);// 获取C1上所有接口 spring工具类提供的方法Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(target);// 设置代理接口proxyFactory.setInterfaces(allInterfaces);// 添加切面proxyFactory.addAspect(PointcutArgs.class);// 获取代理I1 proxy = proxyFactory.getProxy();// 调用方法proxy.m("xxxx");proxy.m(100L);System.out.println("JDK代理? " + AopUtils.isJdkDynamicProxy(proxy));System.out.println("CGLIB代理? " + AopUtils.isCglibProxy(proxy));//判断代理对象是否是C1类型的System.out.println(C1.class.isAssignableFrom(target.getClass()));}}
观察下输出
before: execution(void com.crab.spring.aop.demo02.aspectj.PointcutArgs$C1.m(Object))
C1 m() 参数类型 java.lang.String
C1 m() 参数类型 java.lang.Long
JDK代理? false
CGLIB代理? true
true
参数类型传递是String时候增强了,而Long的时候没有执行增强方法。
@within
格式说明
@within(注解类型):匹配指定的注解内定义的方法。
匹配规则: 被调用的目标方法Method对象.getDeclaringClass().getAnnotation(within中指定的注解类型) != null
举例说明
package com.crab.spring.aop.demo02.aspectj;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.ClassUtils;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author zfd* @version v1.0* @date 2022/2/6 21:41* @关于我 请关注公众号 螃蟹的Java笔记 获取更多技术系列*/
@Aspect
public class PointcutAnnWithin {@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@interface MyAnn {}interface I1 {void m();}@MyAnnstatic class C1 implements I1 {@Overridepublic void m() {System.out.println("C1 m()");}}// 匹配目标类型必须上必须有注解MyAnn@Pointcut("@within(com.crab.spring.aop.demo02.aspectj.PointcutAnnWithin.MyAnn)")public void pc() {}@Before("pc()")public void before(JoinPoint joinPoint) {System.out.println("before: " + joinPoint);}public static void main(String[] args) {C1 target = new C1();AspectJProxyFactory proxyFactory = new AspectJProxyFactory();proxyFactory.setTarget(target);proxyFactory.setProxyTargetClass(true);// 获取C1上所有接口 spring工具类提供的方法Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(target);// 设置代理接口proxyFactory.setInterfaces(allInterfaces);// 添加切面proxyFactory.addAspect(PointcutAnnWithin.class);// 获取代理I1 proxy = proxyFactory.getProxy();// 调用方法proxy.m();System.out.println("JDK代理? " + AopUtils.isJdkDynamicProxy(proxy));System.out.println("CGLIB代理? " + AopUtils.isCglibProxy(proxy));//判断代理对象是否是C1类型的System.out.println(C1.class.isAssignableFrom(target.getClass()));}}
输出
before: execution(void com.crab.spring.aop.demo02.aspectj.PointcutAnnWithin$C1.m())
C1 m()
JDK代理? false
CGLIB代理? true
true
思考下父类上有注解,子类继承父类的方法,同时考虑下注解@Inherited是否在切点注解的场景?
@target
格式说明
@target(注解类型):判断目标对象target类型上是否有指定的注解;@target中注解类型也必须是全限定类型名。
匹配规则: target.class.getAnnotation(指定的注解类型) != null
注意,如果目标注解是标注在父类上的,那么定义目标注解时候应使用@Inherited标注,使子类能继承父类的注解。
举例说明
package com.crab.spring.aop.demo02.aspectj;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.ClassUtils;import java.lang.annotation.*;/*** @author zfd* @version v1.0* @date 2022/2/6 21:41*/
@Aspect
public class PointcutAnnTarget {@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Inherited // 子类能继承父类的注解@interface MyAnn2 {}@MyAnn2 // 注解在父类上static class P1 {void m(){}}static class C1 extends P1 {@Overridepublic void m() {System.out.println("C1 m()");}}// 匹配目标类型必须上必须有注解MyAnn@Pointcut("@target(com.crab.spring.aop.demo02.aspectj.PointcutAnnTarget.MyAnn2)")public void pc() {}@Before("pc()")public void before(JoinPoint joinPoint) {System.out.println("before: " + joinPoint);}public static void main(String[] args) {C1 target = new C1();AspectJProxyFactory proxyFactory = new AspectJProxyFactory();proxyFactory.setTarget(target);proxyFactory.setProxyTargetClass(true);// 获取C1上所有接口 spring工具类提供的方法Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(target);// 设置代理接口proxyFactory.setInterfaces(allInterfaces);// 添加切面proxyFactory.addAspect(PointcutAnnTarget.class);// 获取代理C1 proxy = proxyFactory.getProxy();// 调用方法proxy.m();System.out.println("JDK代理? " + AopUtils.isJdkDynamicProxy(proxy));System.out.println("CGLIB代理? " + AopUtils.isCglibProxy(proxy));// 目标类上是否有切点注解System.out.println(target.getClass().getAnnotation(MyAnn2.class)!= null);}}
输出结果
before: execution(void com.crab.spring.aop.demo02.aspectj.PointcutAnnTarget$C1.m())
C1 m()
JDK代理? false
CGLIB代理? true
true
从结果最后一行看,目标对象继承了父类的注解,符合@target的切点规则。
@args
格式说明
@args(注解类型):方法参数所属的类上有指定的注解;注意不是参数上有指定的注解,而是参数类型的类上有指定的注解。和args类似,不过针对的是参数类型上的注解。
匹配规则: 传入的目标位置参数.getClass().getAnnotation(@args(对应的参数位置的注解类型))!= null
举例说明
package com.crab.spring.aop.demo02.aspectj;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.ClassUtils;import java.lang.annotation.*;/*** @author zfd* @version v1.0* @date 2022/2/6 21:41*/
@Aspect
public class PointcutAnnArgs {@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Inherited // 子类能继承父类的注解@interface MyAnn3 {}@MyAnn3static class MyParameter{}static class C1 {public void m(MyParameter myParameter) {System.out.println(myParameter.getClass().getAnnotation(MyAnn3.class));System.out.println("C1 m()");}}// 匹配方法上最后的一个参数类型上有注解MyAnn3@Pointcut("@args(..,com.crab.spring.aop.demo02.aspectj.PointcutAnnArgs.MyAnn3)")public void pc() {}@Before("pc()")public void before(JoinPoint joinPoint) {System.out.println("before: " + joinPoint);}public static void main(String[] args) {C1 target = new C1();AspectJProxyFactory proxyFactory = new AspectJProxyFactory();proxyFactory.setTarget(target);proxyFactory.setProxyTargetClass(true);// 获取C1上所有接口 spring工具类提供的方法Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(target);// 设置代理接口proxyFactory.setInterfaces(allInterfaces);// 添加切面proxyFactory.addAspect(PointcutAnnArgs.class);// 获取代理C1 proxy = proxyFactory.getProxy();// 调用方法MyParameter myParameter = new MyParameter();proxy.m(myParameter);System.out.println("JDK代理? " + AopUtils.isJdkDynamicProxy(proxy));System.out.println("CGLIB代理? " + AopUtils.isCglibProxy(proxy));// 目标类上是否有切点注解System.out.println(myParameter.getClass().getAnnotation(MyAnn3.class)!= null);}}
观察结果
before: execution(void com.crab.spring.aop.demo02.aspectj.PointcutAnnArgs$C1.m(MyParameter))
@com.crab.spring.aop.demo02.aspectj.PointcutAnnArgs$MyAnn3()
C1 m()
JDK代理? false
CGLIB代理? true
true
第二行中目标方法上输出了参数的注解。
最后一行判断参数类型上确实有注解。
@annotation
格式说明
@annotation(注解类型):匹配被调用的目标对象的方法上有指定的注解
匹配规则:target.getClass().getMethod("目标方法名").getDeclaredAnnotation(@annotation(目标注解))!=null
这个在针对特定注解的方法日志拦截场景下应用比较多。
举例说明
package com.crab.spring.aop.demo02.aspectj;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.ClassUtils;import java.lang.annotation.*;/*** @author zfd* @version v1.0* @date 2022/2/6 21:41*/
@Aspect
public class PointcutAnnotation {@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@interface MyAnn4 {}/*** 父类 方法上都有@MyAnn4*/static class P1{@MyAnn4public void m1(){System.out.println("P1 m()");}@MyAnn4public void m2(){System.out.println("P1 m2()");}}/*** 子类* 注意重新重写了父类的m1方法但是没有声明注解@Ann4* 新增了m3方法带注解@Ann4*/static class C1 extends P1 {@Overridepublic void m1() {System.out.println("C1 m1()");}@MyAnn4public void m3() {System.out.println("C1 m3()");}}// 匹配调用的方法上必须有注解@Pointcut("@annotation(com.crab.spring.aop.demo02.aspectj.PointcutAnnotation.MyAnn4)")public void pc() {}@Before("pc()")public void before(JoinPoint joinPoint) {System.out.println("before: " + joinPoint);}public static void main(String[] args) throws NoSuchMethodException {C1 target = new C1();AspectJProxyFactory proxyFactory = new AspectJProxyFactory();proxyFactory.setTarget(target);proxyFactory.setProxyTargetClass(true);// 获取C1上所有接口 spring工具类提供的方法Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(target);// 设置代理接口proxyFactory.setInterfaces(allInterfaces);// 添加切面proxyFactory.addAspect(PointcutAnnotation.class);// 获取代理C1 proxy = proxyFactory.getProxy();// 调用方法proxy.m1();proxy.m2();proxy.m3();System.out.println("JDK代理? " + AopUtils.isJdkDynamicProxy(proxy));System.out.println("CGLIB代理? " + AopUtils.isCglibProxy(proxy));// 目标对象的目标方法上是否直接声明了注解MyAnn4System.out.println(target.getClass().getMethod("m1").getDeclaredAnnotation(MyAnn4.class)!=null);System.out.println(target.getClass().getMethod("m2").getDeclaredAnnotation(MyAnn4.class)!=null);System.out.println(target.getClass().getMethod("m3").getDeclaredAnnotation(MyAnn4.class)!=null);}}
观察下结果
C1 m1()
before: execution(void com.crab.spring.aop.demo02.aspectj.PointcutAnnotation$P1.m2())
P1 m2()
before: execution(void com.crab.spring.aop.demo02.aspectj.PointcutAnnotation$C1.m3())
C1 m3()
JDK代理? false
CGLIB代理? true
false
true
true
简单分析下:
- C1中重写了m1方法,上面有没有 @Ann4,所有方法没有被拦截
- 其它的m2在父类上有注解@Ann4,m3在子类上也有注解@Ann4,所以拦截了。
- 最后3行输出了目标对象的3个方法上是否有注解的情况。
bean
格式说明
bean(bean名称):这个用在spring环境中,匹配容器中指定名称的bean。
匹配格式:ApplicationContext.getBean("bean表达式中指定的bean名称") != null
举例说明
定义一个bean
package com.crab.spring.aop.demo02.aspectj;/*** @author zfd* @version v1.0* @date 2022/2/6 23:30*/
public class MyBean {private String beanName;public MyBean(String beanName) {this.beanName = beanName;}public void m() {System.out.println("我是" + this.beanName);}
}
切面中的切点和通知定义
@Aspect
public class PointcutBean {// 容器中bean名称是"myBean1"的方法进行拦截@Pointcut("bean(myBean1)")public void pc() {}@Before("pc()")public void m(JoinPoint joinPoint) {System.out.println("start " + joinPoint);}
}
组合使用
@Aspect
@Configuration
@EnableAspectJAutoProxy // 自动生成代理对象
public class PointcutBeanConfig {// 注入 myBean1@Bean("myBean1")public MyBean myBean1() {return new MyBean("myBean1");}// myBean2@Bean("myBean2")public MyBean myBean2() {return new MyBean("myBean2");}// 注入切面@Bean("pointcutBean")public PointcutBean pointcutBean() {return new PointcutBean();}public static void main(String[] args) {AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(PointcutBeanConfig.class);MyBean myBean1 = context.getBean("myBean1", MyBean.class);myBean1.m();MyBean myBean2 = context.getBean("myBean2", MyBean.class);myBean2.m();}}
观察下结果
start execution(void com.crab.spring.aop.demo02.aspectj.MyBean.m())
我是myBean1
我是myBean2
myBean1的方法被拦截了。
上面介绍了Spring中10中切点表达式,下面介绍下切点的组合使用和公共切点的抽取。
切点的组合
切点与切点直接支持逻辑逻辑组合操作: && 、||、 !。使用较小的命名组件构建更复杂的切入点表达式是最佳实践。
同一个类内切点组合
public class CombiningPointcut {/*** 匹配 com.crab.spring.aop.demo02包及子包下任何类的public方法*/@Pointcut("execution(public * com.crab.spring.aop.demo02..*.*(..))")public void publicMethodPc() {}/*** com.crab.spring.aop.demo02.UserService类的所有方法*/@Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(..))")public void serviceMethodPc(){}/*** 组合的切点*/@Pointcut("publicMethodPc() && serviceMethodPc()")public void combiningPc(){}/*** 组合的切点2*/@Pointcut("publicMethodPc() || !serviceMethodPc()")public void combiningPc2(){}}
不同类之间切点组合
切点方法的可见性会影响组合但是不影响切点的匹配。
public class CombiningPointcut2 {/*** com.crab.spring.aop.demo02.UserService类的所有方法*/@Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(..))")public void serviceMethodPc2(){}/*** 组合的切点,跨类组合*/@Pointcut("com.crab.spring.aop.demo02.aspectj.reuse.CombiningPointcut.publicMethodPc() && serviceMethodPc2()")public void combiningPc(){}/*** 组合的切点,跨类组合,由于serviceMethodPc是private, 此处无法组合*/@Pointcut("com.crab.spring.aop.demo02.aspectj.reuse.CombiningPointcut.serviceMethodPc() && serviceMethodPc2()")public void combiningPc2(){}
}
切点的公用
在使用企业应用程序时,开发人员通常希望从多个方面引用应用程序的模块和特定的操作集。建议为此目的定义一个捕获公共切入点表达式的 CommonPointcuts 方面。直接看案例。
不同层的公共切点
/*** 公用的切点* @author zfd* @version v1.0* @date 2022/2/7 8:53*/
public class CommonPointcuts {/*** web层的通用切点*/@Pointcut("within(com.xyz.myapp.web..*)")public void inWebLayer() {}@Pointcut("within(com.xyz.myapp.service..*)")public void inServiceLayer() {}@Pointcut("within(com.xyz.myapp.dao..*)")public void inDataAccessLayer() {}@Pointcut("execution(* com.xyz.myapp..service.*.*(..))")public void businessService() {}@Pointcut("execution(* com.xyz.myapp.dao.*.*(..))")public void dataAccessOperation() {}
}
程序中可以直接引用这些公共的切点
/*** 使用公共的切点* @author zfd* @version v1.0* @date 2022/2/7 8:56*/
@Aspect
public class UseCommonPointcuts {/*** 直接使用公共切点*/@Before("com.crab.spring.aop.demo02.aspectj.reuse.CommonPointcuts.inWebLayer()")public void before(JoinPoint joinPoint){System.out.println("before:" + joinPoint);}
}
总结
本文介绍Spring中10种切点表达式,最常用的是execution,同时介绍切点如何组合使用和如何抽取公共的切点。
学习更多JAVA知识与技巧,关注与私信博主
免费学习领取JAVA 课件,源码,安装包等资料
Spring AOP 切点详解相关推荐
- Spring AOP知识详解
本文来详细说下spring中的aop内容 文章目录 Spring AOP概述 Spring AOP一代 Pointcut Jointpoint Advice Advisor 织入 Spring AOP ...
- spring注解:spring aop注解详解
一. AOP的基本概念 Aspect(切面):通常是一个类,里面可以定义切入点和通知 Pointcut(切点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式 JointPoint(连接点) ...
- Spring AOP全面详解(超级详细)
如果说IOC 是 Spring 的核心,那么面向切面编程AOP就是 Spring 另外一个最为重要的核心@mikechen AOP的定义 AOP (Aspect Orient Programming) ...
- Spring AOP代理详解
最近在看Spring这块,对AOP的代理有些疑惑,特整理如下. 1.*Java为什么要引入AOP代理的概念?* AOP(面向切面编程)通常,系统由很多组件组成,每个组件负责一部分功能,然而,这些组件也 ...
- spring aop使用详解
1 转载于:https://www.cnblogs.com/season1992/p/10007591.html
- spring框架 AOP核心详解
AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...
- Spring面向切面编程(AOP)详解
Spring面向切面编程(AOP)详解 面向切面编程(AOP)是Spring框架的另外一个重要的核心内容. 而在讲AOP之前,先来了解一下动态代理这个概念,因为AOP基于动态代理. 动态代理概念:在程 ...
- Spring事务管理详解_基本原理_事务管理方式
Spring事务管理详解_基本原理_事务管理方式 1. 事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象 ...
- Spring循环依赖详解
Spring循环依赖详解 什么是循环依赖 spring是如何解决循环依赖 循环源码分析 getSingletion方法 getSingleton spring开启代理对象的地方 循环依赖的限制条件 什 ...
最新文章
- Linux 终端访问 FTP 及 上传下载 文件
- strncpy与strcpy的区别与注意事项
- 随机化快速排序+快速选择 复杂度证明+运行测试
- 彩虹六号服务器显示,彩虹六号怎么看自己在什么服务器 | 手游网游页游攻略大全...
- ffmpeg和SDL学习笔记
- 【BZOJ1406】【codevs2478】密码箱,数论练习
- windows--bat--右键菜单
- 《Kotlin项目实战开发》第5章 函数与函数式编程
- miui11精简_MIUI11评测:真的是缺乏创新吗?
- 密码学加解密实训(墨者学院摩斯密码第2题)
- mac 系统下 刻录centos 系统到 U盘中
- 高等代数——大学高等代数课程创新教材(丘维声)——2.5笔记+习题
- 2019年末逆向复习系列之从猫眼字体反爬分析谈谈字体反爬的前世今生
- 第一章 核磁共振的物理学基础
- JavaWeb全套教程笔记_前端技术
- 彼得.得鲁克与因果定律
- b64_c3VuJTIwYm95 好看的电影推荐
- 狐表 mysql_狐表成功连接MySql方法教程小结,可查询 可回写 字段名可显示中文...
- 如何提升推荐系统的可解释性?京东智能推荐卖点技术全解析
- 春招攻略:我是怎样进入字节跳动做技术的