Skip to content

Instantly share code, notes, and snippets.

@wutingjia
Last active April 2, 2019 13:47
Show Gist options
  • Save wutingjia/f7cdfbf60183af9a81290a45d4bb98c6 to your computer and use it in GitHub Desktop.
Save wutingjia/f7cdfbf60183af9a81290a45d4bb98c6 to your computer and use it in GitHub Desktop.
Spring切面

AOP术语

通知(Advice)
定义了 切面是什么以及何时使用。有五种类型的通知Before、After、After-returning、After-throwing、Around。
连接点(Join point)
定义了 应用 通知 的时机。是在应用执行过程中能够插入切面的一个点。 切点(Pointcut)
定义了 何处。匹配 通知 所要 织入 的一个或多个 链接点。
切面(Aspect)
切面是通知和切点的结合。
引入(Introduction)
引入允许我们向现有的类添加新方法或属性。
织入(Weaving)
织入是把切面应用到目标对象并创建新的代理对象的过程。

Spring对Aop的支持仅限于方法级别。Spring的切面由包裹了目标对象的代理类实现。

切点

AspectJ指示器
arg():限制连接点匹配 参数为指定类型的执行方法。
@arg():限制连接点匹配 参数由指定注解标注的执行方法。
execution():用于匹配是连接点的执行方法。
this():限制连接点匹配 AOP代理的Bean引用 为指定类型的类。
target:限制连接点匹配 目标对象为指定类型的类。
@target():限制连接点匹配 特定的执行对象,这些对象对应的类要具有指定类型的注解。
within():限制连接点匹配 指定的类型。
@within():限制连接点匹配 指定注解所标注的类型。
@annotation:限制匹配带有指定注解的连接点。 切点表达式

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
//?表示可省略
//*通配符,该通配符主要用于匹配单个单词,或者是以某个词为前缀或后缀的单词。
//..通配符,该通配符表示0个或多个项,主要用于declaring-type-pattern和param-pattern中,如果用于declaring-type-pattern中,则表示匹配当前包及其子包,如果用于param-pattern中,则表示匹配0个或多个参数。
execution(* com.test.ClassA.functionA(..))//第一个星号表示任意返回类型,(..)表示任意方法参数  

使用注解创建切面

切面类使用 @Aspect 进行注解。
切面类 被装配为一个Bean 在配置类中使用@Bean进行装配。
在配置类使用 @EnableAspectJAutoProxy 开启自动代理。

@Before("execution(* com.test.ClassA.functionA(..))")  
public void cutFoo(){  
  //.....  
}  
//或者  
@Pointcut("execution(* com.test.ClassA.functionA(..))")  
public void performance(){}//空方法  
  
@Before("performance()")  
public void beforeFoo(){  
  //.....  
}   
  
@Around("performance()")  
public void aroundFoo(ProceedingJoinPoint jp){  
  //...  
  jp.procceed():  //执行原本的方法
  //...  
}如果原方法有返回值,则不能为void 因设置为Object,并最后return jp.procceed()的值  

如果需要对方法的参数进行处理可以使用args参数进行针对性的处理,如果需要通用,可以使用反射。
例如:

Object[] args=jp.getArgs();
Class<?> clazz= args[0].getClass();//如果需要基类可以使用getSuperclass();
Field field= clazz.getDeclaredField(key);//获取所有field,包括private的,如果getField()则不返回private的。key代表字段名。如果需要所有的字段使用Field[] fields= clazz.getDeclaredFields(); 然后可以遍历。Method同理。
field.setAccessible(true);//将private的字段设置为可以访问。
field.get(args[0]).toString();//返回字段,注意args[0] 是一个具体的对象。

大坑!!!所有基于SpringAOP的框架的注解例如@Transcational、@HystrixCommand @Cacheable 当被加在一个类的内部函数中(被函数调用的函数)时或者访问修饰符为private 会不起效果!,由于不会被spring容器直接管理,被加注解的函数不会被代理!可以考虑使用AspectJ来代替SpringAop

原文:

the (springAop)aim is to provide a close integration between AOP implementation and Spring IoC.
the Spring Framework’s AOP functionality is normally used in conjunction with the Spring IoC container. Aspects are configured by using normal bean definition syntax (although this allows powerful “auto-proxying” capabilities). This is a crucial difference from other AOP implementations. You cannot do some things easily or efficiently with Spring AOP, such as advise very fine-grained objects (typically, domain objects). AspectJ is the best choice in such cases

Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied. Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than interfaces

It is important to grasp the fact that Spring AOP is proxy-based

Due to the proxy-based nature of Spring’s AOP framework, calls within the target object are, by definition, not intercepted. For JDK proxies, only public interface method calls on the proxy can be intercepted. With CGLIB, public and protected method calls on the proxy are intercepted (and even package-visible methods, if necessary). However, common interactions through proxies should always be designed through public signatures.

If your interception needs include method calls or even constructors within the target class, consider the use of Spring-driven native AspectJ weaving instead of Spring’s proxy-based AOP framework

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment