Spring AOP @AspectJ 入门基础
需要的类包:

1、一个简单的例子
package com.yyq.annotation;
public interface Waiter {
void greetTo(String name);
void serveTo(String name);
}
NaiveWaiter业务类:
package com.yyq.annotation;
public class NaiveWaiter implements Waiter {
@Override
public void greetTo(String name) {
System.out.println("NaiveWaiter:greet to " + name + "...");
}
@Override
public void serveTo(String name) {
System.out.println("NaiveWaiter:serving to " + name + "...");
}
}
PreGreetingAspect切面实现类:
package com.yyq.annotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//通过该注解将PreGreetingAspect标识为一个切面
@Aspect
public class PreGreetingAspect {
//定义切点和增强类型
@Before("execution(* greetTo(..))")
//增强的横切逻辑
public void beforeGreeting(){
System.out.println("How are you");
}
}
测试方法:
@Test
public void aspectJProxyTest(){
Waiter target = new NaiveWaiter();
AspectJProxyFactory factory = new AspectJProxyFactory();
//设置目标对象
factory.setTarget(target);
//添加切面对象
factory.addAspect(PreGreetingAspect.class);
//生成织入切面的代理对象
Waiter proxy = factory.getProxy();
proxy.greetTo("Anny");
proxy.serveTo("Mei");
}
输出结果:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--目标Bean-->
<bean id="waiter" class="com.yyq.annotation.NaiveWaiter"/>
<!--使用了@AspectJ注解的切面类-->
<bean class="com.yyq.annotation.PreGreetingAspect"/>
<!--自动代理创建器,自动将@AspectJ注解切面类织入到目标Bean中-->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
</beans>
测试方法:
@Test
public void aspectJProxyTest2(){
String configPath = "com\\yyq\\annotation\\beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter)ctx.getBean("waiter");
waiter.greetTo("John");
}
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="waiter" class="com.yyq.annotation.NaiveWaiter"/>
<bean class="com.yyq.annotation.PreGreetingAspect"/>
</beans>
测试方法:
@Test
public void aspectJProxyTest3(){
String configPath = "com\\yyq\\annotation\\beans2.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter)ctx.getBean("waiter");
waiter.greetTo("Herry");
}
Spring支持9个@ApsectJ切点表达式函数,它们用不同的方式描述目标类的连接点,根据描述对象的不同,可以将它们大致分为4种类型:
· 方法切点函数:通过描述目标类方法信息定义连接点;
· 方法入参切点函数:通过描述目标类方法入参的信息定义连接点;
· 目标类切点函数:通过描述目标类类型信息定义连接点;
· 代理类切点函数:通过描述目标类的代理类的信息定义连接点;
| 类别 | 函数 | 入参 | 说明 |
| 方法切点函数 | execution() | 方法匹配模式串 | 表示满足某一匹配模式的所有目标类方法连接点。如execution(* greetTo(..))表示所有目标类中的greetTo()方法。 |
| @annotation() | 方法注解类名 | 表示标注了特定注解的目标方法连接点。如@annotation(com.baobaotao.anno.NeedTest)表示任何标注了@NeedTest注解的目标类方法。 | |
| 方法入参切点函数 | args() | 类名 | 通过判别目标类方法运行时入参对象的类型定义指定连接点。如args(com.baobaotao.Waiter)表示所有有且仅有一个按类型匹配于Waiter的入参的方法。 |
| @args() | 类型注解类名 | 通过判别目标方法的运行时入参对象的类是否标注特定注解来指定连接点。如@args(com.baobaotao.Monitorable)表示任何这样的一个目标方法:它有一个入参且入参对象的类标注@Monitorable注解。 | |
| 目标类切点函数 | within() | 类名匹配串 | 表示特定域下的所有连接点。如within(com.baobaotao.service.*)表示 com.baobaotao.service包中的所有连接点,也即包中所有类的所有方法,而 within(com.baobaotao.service.*Service)表示在com.baobaotao.service包中,所有以 Service结尾的类的所有连接点。 |
| target() | 类名 | 假如目标类按类型匹配于指定类,则目标类的所有连接点匹配这个切点。如通过target(com.baobaotao.Waiter)定义的切点,Waiter、以及Waiter实现类NaiveWaiter中所有连接点都匹配该切点。 | |
| @within() | 类型注解类名 | 假如目标类按类型匹配于某个类A,且类A标注了特定注解,则目标类的所有连接点匹配这个切点。如@within(com.baobaotao.Monitorable)定义的切点,假如Waiter类标注了@Monitorable注解,则Waiter以及Waiter实现类NaiveWaiter类的所有连接点都匹配。 | |
| @target() | 类型注解类名 | 目标类标注了特定注解,则目标类所有连接点匹配该切点。如@target(com.baobaotao.Monitorable),假如NaiveWaiter标注了@Monitorable,则NaiveWaiter所有连接点匹配切点。 | |
| 代理类切点函数 | this() | 类名 | 代理类按类型匹配于指定类,则被代理的目标类所有连接点匹配切点。 |
- * 匹配任意字符,但它只能匹配上下文中的一个元素;
- .. 匹配任意字符,可以匹配上下文中的多个元素,但在表示时,必须和 * 联合使用,而在表示入参时则单独使用;
- + 表示按类型匹配指定类的所有类,必须跟在类名后面,如com.yyq.Car+。继承或扩展指定类的所有类,同时还包括指定类本身。
- 支持所有通配符:execution()、within(),如within(com.yyq.*)、within(com.yyq.service..*.*Service+)等;
- 仅支持 + 通配符:args()、this()、target(),如args(com.yyq.Waiter+)、target(java.util.List+)等。虽然这3个函数可以支持+通配符,但其意义不大,因为对于这些函数来说使用和不使用+都是一样的,如target(com.yyq.Waiter+)和target(com.yyq.Waiter)是等价的。
- 不支持通配符:@args()、@within()、@target()和@annotation(),如@args(com.yyq.anno.NeedTest)和@within(com.yyq.anno.NeedTest)。
- && 与操作符,相当于切点的交集运算,and是等效的操作符。如within(com.yyq..*) and args(String) 表示在com.yyq包下所有类(当前包以及子孙包)拥有一个String入参的方法;
- || 或操作符,相当于切点的并集运算,or是等效的操作符。如within(com.yyq..*) || args(String) 表示在com.yyq包下的所有类的方法,或者所有拥有一个String入参的方法;
- ! 非操作符,相当于切点的反集运算,not是等效的操作符。如!within(com.yyq.*) 表示所有不在com.yyq包下的方法。
- @Before
前置增强,相当于BeforeAdvice的功能,Before注解类拥有两个成员:
- value:该成员用于定义切点;
- argNames:由于无法通过Java反射机制获取方法入参名,所有如果在Java编译时未启动调试信息或者需要在运行期解析切点,就必须通过这个成员指定注解所标注增强方法的参数名(注意两者名字必须完全相同),多个参数名用逗号分隔。
- AfterReturning
后置增强,相当于AfterReturningAdvice,AfterReturning注解类拥有4个成员:
- value:该成员用于定义切点;
- pointcut:表示切点的信息,如果显式指定pointcut值,它将覆盖value的设置值,可以将pointcut成员看成是value的同义词;
- returning:将目标对象方法的返回值绑定给增强的方法;
- argNames:如前所述。
- Around
环绕增强,相当于MethodInterceptor,Around注解类拥有两个成员:
- value:该成员用于定义切点;
- argNames:如前所述。
- AfterThrowing
抛出增强,相当于ThrowsAdvice,AfterThrowing注解类拥有4个成员:
- value:该成员用于定义切点;
- pointcut:表示切点的信息,如果显式指定pointcut值,它将覆盖value的设置值,可以将pointcut成员看成是value的同义词;
- throwing:将抛出的异常绑定到增强方法中;
- argNames:如前所述。
- After
Final增强,不管是抛出异常或者是正常退出,该增强都会得到执行,该增强没有对应的增强接口,可以把它看成是ThrowsAdvice和AfterReturningAdvice的混合物,一般用于释放资源,相当于try{}finally{}的控制流。After注解类拥有两个成员:
- value:该成员用于定义切点;
- argNames:如前所述。
- DeclareParents
引介增强,相当于IntroductionInterceptor,DeclareParents注解类拥有两个成员:
- value:该成员用于定义切点,它表示在哪个目标类上添加引介增强;
- defaultImpl:默认的接口实现类。
package com.yyq.annotation;
public interface Seller {
int sell(String goods, String clientName);
}
SmartSeller实现类:
package com.yyq.annotation;
public class SmartSeller implements Seller {
public int sell(String goods,String clientName) {
System.out.println("SmartSeller: sell "+goods +" to "+clientName+"...");
return 100;
}
}
EnableSellerAspect切面实现类:
package com.yyq.annotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
@Aspect
public class EnableSellerAspect {
@DeclareParents(value = "com.yyq.annotation.NaiveWaiter",defaultImpl = SmartSeller.class)
public Seller seller;
}
beans3.xml配置文件:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="waiter" class="com.yyq.annotation.NaiveWaiter"/>
<bean class="com.yyq.annotation.EnableSellerAspect"/>
</beans>
测试方法:
@Test
public void aspectJProxyTest4(){
String configPath = "com\\yyq\\annotation\\beans3.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter)ctx.getBean("waiter");
waiter.greetTo("John");
Seller seller = (Seller)waiter; //成功进行强制类型转换
seller.sell("Beer","John");
}
package com.yyq.aspectJ;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface NeedTest {
boolean value() default true;
}
Waiter接口:
package com.yyq.aspectJ;
public interface Waiter {
void greetTo(String name);
void serveTo(String name);
}
NaiveWaiter实现类:
package com.yyq.aspectJ;
public class NaiveWaiter implements Waiter {
@Override
public void greetTo(String name) {
System.out.println("NaiveWaiter:greet to " + name + "...");
}
@Override
public void serveTo(String name) {
System.out.println("NaiveWaiter:serving to " + name + "...");
}
}
NaughtyWaiter实现类:
package com.yyq.aspectJ;
public class NaughtyWaiter implements Waiter {
@NeedTest
public void greetTo(String clientName) {
System.out.println("NaughtyWaiter:greet to "+clientName+"...");
}
public void serveTo(String clientName){
System.out.println("NaughtyWaiter:serving "+clientName+"...");
}
public void joke(String clientName,int times){
System.out.println("NaughtyWaiter:play "+times+" jokes to "+clientName+"...");
}
}
TestAspcet切面实现类:
package com.yyq.aspectJ;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class TestAspect {
@AfterReturning("@annotation(com.yyq.aspectJ.NeedTest)")
public void needTestFun(){
System.out.println("needTestFun() executed!");
}
}
Spring配置自动应用切面:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="naiveWaiter" class="com.yyq.aspectJ.NaiveWaiter"/>
<bean id="naughtyWaiter" class="com.yyq.aspectJ.NaughtyWaiter"/>
<bean class="com.yyq.aspectJ.TestAspect"/>
</beans>
测试方法:
package com.yyq;
import com.yyq.aspectJ.Waiter;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AspectJTest {
@Test
public void annotationAspectJTest() {
String configPath = "com\\yyq\\aspectJ\\beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter naiveWaiter = (Waiter) ctx.getBean("naiveWaiter");
Waiter naughtyWaiter = (Waiter) ctx.getBean("naughtyWaiter");
naiveWaiter.greetTo("John");
naiveWaiter.serveTo("John");
naughtyWaiter.greetTo("Tom");
naughtyWaiter.serveTo("Tom");
}
}
- 通过方法签名定义切点
· execution(public * *(..))
- 通过类定义切点
· execution(* com.baobaotao.Waiter.*(..))
- 通过类包定义切点
- 通过方法入参定义切点
- args()
- @args()
该函数接受一个注解类的类名,当方法的运行时入参对象标注发指定的注解时,方法匹配切点。如果在类继承树中注解点@M高于入参类型点fun(T1 t),则该目标方法不可能匹配切点@args(M);如果在类继承树中注解点@M低于入参类型点fun(T1 t),则注解点所在类及其子孙类作为方法入参时,该方法匹配@args(M)切点。
形如within(com.baobaotao.NaiveWaiter)是within()函数所能表达的最小粒度,如果试图用within()匹配方法级别的连接点,如within(com.baobaotao.NaiveWaiter.greet*)将会产生解析错误。
- within(com.baobaotao.NaiveWaiter)
匹配目标类NaiveWaiter的所有方法。如果切点调整为within(com.baobaotao.Waiter),则NaiveWaiter和 NaughtyWaiter中的所有方法都不匹配,而Waiter本身是接口不可能实例化,所以 within(com.baobaotao.Waiter)的声明是无意义的;
- within(com.baobaotao.*)
匹配com.baobaotao包中的所有类,但不包括子孙包,所以com.baobaotao.service包中类的方法不匹配这个切点;
- within(com.baobaotao..*)
匹配com.baobaotao包及子孙包中的类,所以com.baobaotao.service、com.baobaotao.dao以及com.baobaotao.service.fourm等包中所有类的方法都匹配这个切点。
- target()
target(M)表示如果目标类按类型匹配于M,则目标类所有方法匹配切点。
- this()
Spring AOP @AspectJ 入门基础的更多相关文章
- 关于 Spring AOP (AspectJ) 该知晓的一切
关联文章: 关于Spring IOC (DI-依赖注入)你需要知道的一切 关于 Spring AOP (AspectJ) 你该知晓的一切 本篇是年后第一篇博文,由于博主用了不少时间在构思这篇博文,加上 ...
- 关于 Spring AOP (AspectJ) 你该知晓的一切
版权声明:本文为CSDN博主「zejian_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/javazej ...
- Spring AOP初级——入门及简单应用
在上一篇<关于日志打印的几点建议以及非最佳实践>的末尾提到了日志打印更为高级的一种方式——利用Spring AOP.在打印日志时,通常都会在业务逻辑代码中插入日志打印的语句,这实际上是 ...
- Spring AOP + AspectJ annotation example
In this tutorial, we show you how to integrate AspectJ annotation with Spring AOP framework. In simp ...
- Spring AOP + AspectJ Annotation Example---reference
In this tutorial, we show you how to integrate AspectJ annotation with Spring AOP framework. In simp ...
- Spring学习(十八)----- Spring AOP+AspectJ注解实例
我们将向你展示如何将AspectJ注解集成到Spring AOP框架.在这个Spring AOP+ AspectJ 示例中,让您轻松实现拦截方法. 常见AspectJ的注解: @Before – 方法 ...
- 关于 Spring AOP (AspectJ) 你该知晓的一切 (转)
出处:关于 Spring AOP (AspectJ) 你该知晓的一切
- Spring AOP AspectJ Pointcut Expressions With Examples--转
原文地址:http://howtodoinjava.com/spring/spring-aop/writing-spring-aop-aspectj-pointcut-expressions-with ...
- Spring AOP AspectJ
本文讲述使用AspectJ框架实现Spring AOP. 再重复一下Spring AOP中的三个概念, Advice:向程序内部注入的代码. Pointcut:注入Advice的位置,切入点,一般为某 ...
随机推荐
- Zepto tap 穿透bug、解决移动端点击穿透问题
当两个层重叠在一起时,或是有个弹窗,使用Zepto的tap事件时,点击上面的一层时会触发下面一层的事件,特别是底层如果是input框时,必“穿 透”,“google”说原因是“tap事件实际上是在冒泡 ...
- 常见爬虫/BOT对抗技术介绍(一)
爬虫,是大家获取互联网公开数据的有效手段.爬虫.反爬虫技术.反-反爬虫技术随着互联网的不断发展,也在不断发展更新, 本文简要介绍现代的爬虫/BOT对抗技术,如有疏漏,多谢指正! 一.反爬虫/BOT技术 ...
- MAC终端密钥登录自动输入密码
升级MAC系统后,发现用于MAC终端ssh服务器的登录脚本无法正常执行了,表现为:需要手动输入密钥密码,于是重新整理一下,恢复正常,在此记录一下: #!/usr/bin/expect -fspawn ...
- java后台服务器启动脚本
最近由于经常在项目上线或者调试中启动服务,由于要设置环境变量这些,所以为了方便写了个启动脚本,希望能够帮助大家,也算是给自己做个小笔记: example_project_start.sh: # /bi ...
- C# Parallel.Invoke 实现
Parallel.Invoke应该是Parallel几个方法中最简单的一个了,我们来看看它的实现,为了方法大家理解,我尽量保留源码中的注释: public static class Parallel ...
- linux clamav 免费查毒工具
linux下需要杀毒工具吗?我一直认为是不要的,基于linux的病毒很少,linux 安全防护也做的很好,一般很难功破.我想那些黑客们更喜欢,写windows下的病毒,用的人多啊,传播也容易.下面的操 ...
- 配置带用户权限的docker registry v2
v1版本的docker registry用nginx配置,v2版本的用nginx有些问题,客户端总是会请求到v1/下面去, 以下从 http://blog.csdn.net/felix_yujing/ ...
- JSONObject、JSONArray、Map、JavaBean的相互转换
1,JSONObject json对象,就是一个键对应一个值,使用的是大括号{ },如:{key:value} 2,JSONArray json数组,使用中括号[ ],只不过数组里面的项也是json键 ...
- 前端切图实战(PSD设计稿转化为前端)
课程来源:https://www.imooc.com/learn/668 一:读设计稿 划分:头部.尾部.公共部分.大概分多少块.logo的重用.列表有哪些.各部分用什么技术实现等等. 二:建立项目目 ...
- windows10开启hyper-v虚拟化
windows积极融入虚拟化,对pc体验很不错的! 01.程序更新组件 控制面板--->程序-->打开/关闭 windwods功能--->更新完毕,重启windows 02.确认是否 ...