Spring Aop之外的新选择Gadtry-Aop
作者: harbby(github) email: yezhixinghai@gmail.com 日期: 2018.12
简介
Gadtry 是一个构建于java8之上的工具库, 涵盖了Ioc
Aop
exec
graph
等等工具库,几乎涵盖了日常开发中非常多工具类,当然它还在不断丰富中.
Aop
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。(来自百度百科)
Spring-Aop和Ioc组合可以说非常漂亮和完美, Spring-Aop中定义了非常好注解和概念,可以说是对Aop模式完美诠释,Spring体系本身也非常全面, 但是Spring体系过于庞大
, 且现实中我们有太多的非Spring项目.
Gadtry-Aop
Gadtry-Aop是 Gadtry 1.1版本开始加入全新功能,旨在降低Aop使用难度,同时尽量小巧简单, 提供在Spring-Aop之外的新选择.在依赖上除了字节码操作器javassist
外无任何依赖.
Gadtry-Aop 诞生有两个目的:
其一是非spring项目 也能尽量获得Spring-Aop相似Aop体验
其二: 我非常讨厌Spring-Aop 的expression 字符串表达式和一堆的注解.它难以记忆和阅读, Gadtry-Aop 为了简化使用采用了链式(函数式)Api设计,你只需参照下demo,然后借助ide就预览和使用所有功能,一切都是点点点
下载:
maven:
<dependency>
<groupId>com.github.harbby</groupId>
<artifactId>gadtry</artifactId>
<version>1.1.0</version>
</dependency>
非容器场景代理
这种场景非常多,就是你的项目中没有使用任何Ioc容器.
举个栗子:
T proxy = AopFactory.proxy(Class<T>)
.byInstance(instance)
.around(proxyContext -> {
String name = proxyContext.getInfo().getName();
System.out.println(name);
Object value = proxyContext.proceed();
switch (name) {
case "add":
Assert.assertEquals(true, value); //Set or List
break;
case "size":
Assert.assertTrue(value instanceof Integer);
break;
}
});
这个例子中 Class<T>
指类或接口, instance这个具体的实现类活子类实现类.这个例子中用到了 环绕通知(around)
模式. 这里注意如果Class<T>
是接口,则默认使用jdk动态代理, 否则使用字节码技术生成动态代理类.
我们在来看个结合Gadtry-Ioc容器例子
IocFactory iocFactory = GadTry.create(binder -> {
binder.bind(Map.class).byCreator(HashMap::new).withSingle();
binder.bind(HashSet.class).by(HashSet.class).withSingle();
}).aop(binder -> {
binder.bind("point1")
.withPackage("com.github.harbby")
//.subclassOf(Map.class)
.classAnnotated()
.classes(HashMap.class, HashSet.class)
.whereMethod(methodInfo -> methodInfo.getName().startsWith("add"))
.build()
.before((info) -> {
Assert.assertEquals("add", info.getName());
System.out.println("before1");
})
.after(() -> {
Assert.assertTrue(true);
System.out.println("after2");
});
}).initialize();
Set set = iocFactory.getInstance(HashSet.class);
这个例子中结合了Ioc容器来使用Aop, 在Spring开发中基本都是结合Ioc容器来使用的Aop的.
这个例子中我们 使用了扫包,过滤器等来定位需要被代理类和方法, 最后添加了 前置通知(before)
和后置通知(after)
基本概念
这篇文章中我们不会着重介绍IOC, 我们来重点感谢Aop的几个概念:
-
- Gadtry-Aop支持通知类型
-
前置通知(Before) 指: 在目标方法被调用之前调用通知功能。
-
后置通知(After)指: 在目标方法完成之后调用通知,无论方法正确执行与否。
-
返回通知 (after-Returning) 指: 在目标方法成功执行之后调用通知。
-
异常通知(After-throwing):在目标方法抛出异常后调用通知。
-
环绕通知(Around):通知包裹了被通知的方法,由使用者决定和调用目标方法
*** 关于通知类型须知: **
()->{} ,切入逻辑中无法获取目标方法相关信息,如args[]名称等
(info)->{info.getArgs()} , 这样就可以获取目标方法相关信息
-
切点(pointcut)
组成切面的最小单位, 我们通常使用明确的类和方法名称,或是利用扫描和过滤所匹配的类和方法名称来指定切点.
切点定义:
binder.bind("point1")
.withPackage("com.github.harbby")
//.subclassOf(Map.class)
.classAnnotated()
.classes(HashMap.class, HashSet.class)
.whereMethod(methodInfo -> methodInfo.getName().startsWith("add"))
.build()
.before((info) -> {
Assert.assertEquals("add", info.getName());
System.out.println("before1");
})
.after(() -> {
Assert.assertTrue(true);
System.out.println("after2");
});
-
切面(pointcut)
切面用来组织一组相关的切点.一个切面中可以定义多个切点
public class DemoAspect implements Aspect {
@Override
public void register(Binder binder) {
binder.bind("point1")
.classes(HashSet.class).build()
.after(() -> {
System.out.println("after");
});
binder.bind("point2")
.classes(Map.class).build()
.after(() -> {
System.out.println("after");
});
}
}
-
动态代理
Gadtry-Aop 优先使用jdk动态代理,如果遇到非接口无法代理时则使用Javassist动态字节码技术来代理
最后
Spring-Aop太权威了,您可能无权对它做出任何改变,但是Gadtry-Aop才刚诞生不久, 如果您对Aop有什么自己的见解和想法欢迎一起来讨论和完善, 我们的地址是: https://gitee.com/mirrors/Gadtry 欢迎您的访问,里面还有更多精彩!