面向切面编程已经在我们的平常工作中经常会用到, 平常我们在使用的都是使用spring封装的aop模块, 使用的时候只要配置几个注解就能实现逻辑了,非常的方便. 但是使用的方便也就意味着其封装的复杂, 另外spring的aop也是有其的演进,从最早的只能通过实现接口+xml配置,到现在@Aspect的支持来实现声明式的变成方式.
你能手写出来,自然证明你已经对其的很了解了, 那么再手写一遍更能加深你的印象, 下面我将会从原理介绍->类设计->接口设计->代码实现几个步骤来讲述手写的过程,顺便会讲一下我在写的过程中遇到的坑.
下面是我设计的uml类图,因为受spring aop的设计实现,所以在命名上进行了一定程度的借鉴.
主要的接口设计是跟AOP的概念想对应的,比如pointcut对应切点,advice对应增强(也就是横切逻辑),ProxyFactory对应织入器
接口或者类的设计还是比较简单的,下面看一下具体的接口和实现
// 切点接口
public interface PointCut {
Boolean match(Object object);
}
//目前就实现了切对应的类 和对应方法
public class MethodPointCut implements PointCut {
private Method method;
...
@Override
public Boolean match(Object object) {
return method.equals(object);
}
}
public class ClassPointCut<T> implements PointCut{
private Class<T> clazz;
...
@Override
public Boolean match(Object object){
if (object.getClass().equals(clazz)) return true;
for (Class<?> anInterface : object.getClass().getInterfaces()) {
if (anInterface.equals(clazz)) return true;
}
return false;
}
}
下面是横切逻辑的接口实现
//增强接口
public interface Advice {
}
//前置增强
public interface BeforeAdvice extends Advice{
<T> void invokeBefore(Class<T> clazz, Method method, Object[] args);
}
public interface AroundAdvice extends Advice{
// 注意这里使用了函数接口, 源方法的执行结果通过supplier.get() 进行获取结果
<T>Object invoke(Class<T> clazz, Method method, Object[] args, Supplier<Object> supplier) throws Exception;
}
public interface AfterAdvice extends Advice {
<T> Object invokeAfter(Class<T> clazz, Method method, Object[] args, Object result, Exception exception);
}
下面是用于汇聚切点和横切逻辑的类, 我实现了默认的实现,主要只是针对固定类和方法的aop增强
public interface Advisor {
}
// 这是默认的实现, 这个类主要是汇聚切点个横切逻辑的
public class DefaultAdvisor implements Advisor {
//类必须要匹配的,不然就不需要进行代理了
private ClassPointCut classPointCut;
//在拦截方法时,如果不包含在内就不进行前后增强,如果为空就默认全部都要增强
private List<MethodPointCut> methodPointCuts;
//增强列表
private List<Advice> adviceList;
public DefaultAdvisor(ClassPointCut classPointCut) {
this.classPointCut = classPointCut;
this.methodPointCuts = new ArrayList<>();
this.adviceList = new ArrayList<>();
}
/**
* 构建横切逻辑调用链
* @param supplier
* @return
*/
public AdviceChain buildChain(Supplier<Object> supplier) {
AdviceChain adviceChain = new AdviceChain(supplier);
for (Advice advice : adviceList) {
if (advice instanceof BeforeAdvice) {
adviceChain.addBeforeAdvice((BeforeAdvice) advice);
}
if (advice instanceof AroundAdvice) {
adviceChain.addAroundAdvice((AroundAdvice) advice);
}
if (advice instanceof AfterAdvice) {
adviceChain.addAfterAdvice((AfterAdvice) advice);
}
}
return adviceChain;
}
/**
* 添加方法切点,如果为空则默认拦截全部方法
* @param methodPointCut
* @return
*/
public DefaultAdvisor addMethodPointCut(MethodPointCut methodPointCut) {
methodPointCuts.add(methodPointCut);
return this;
}
public DefaultAdvisor addAdvice(Advice advice) {
adviceList.add(advice);
return this;
}
/**
* 判断是否需要构造代理对象
*
* @param object
* @return
*/
public Boolean matchClass(Object object) {
return classPointCut == null || classPointCut.match(object);
}
/**
* 判断是否需要拦截
*
* @param method
* @return
*/
public Boolean matchMethod(Method method) {
if (methodPointCuts.isEmpty()) return true;
for (MethodPointCut methodPointCut : methodPointCuts) {
Boolean match = methodPointCut.match(method);
if (match) return true;
}
return false;
}
}
下面是一个比较重要的类,就是横切逻辑的链,也就是责任链模式的实现
public class AdviceChain {
private List<BeforeAdvice> beforeAdvices;
private List<AroundAdvice> aroundAdvices;
private List<AfterAdvice> afterAdvices;
private Supplier<Object> supplier;
public AdviceChain( Supplier<Object> supplier) {
this.beforeAdvices = new ArrayList<>();
this.aroundAdvices =new ArrayList<>();
this.afterAdvices =new ArrayList<>();
this.supplier = supplier;
}
public void addBeforeAdvice(BeforeAdvice beforeAdvice){
beforeAdvices.add(beforeAdvice);
}
public void addAroundAdvice(AroundAdvice aroundAdvice){
aroundAdvices.add(aroundAdvice);
}
public void addAfterAdvice(AfterAdvice afterAdvice){
afterAdvices.add(afterAdvice);
}
public <T>Object doInvoke(Class<T> clazz, Method method, Object[] objects){
//首先执行所有的前置增强
beforeAdvices.forEach(e->e.invokeBefore(clazz, method, objects));
Object object = null;
Exception exception = null;
// 最初生产者指向原方法的执行
Supplier<Object> finalObjectSupplier = supplier;
for (AroundAdvice aroundAdvice : aroundAdvices) {
Supplier<Object> temp = finalObjectSupplier;
//替换旧的给下一个AroundAdvice使用
finalObjectSupplier = () -> {
try {
return aroundAdvice.invoke(clazz, method, objects, temp);
} catch (Exception e) {
return e;
}
};
}
//执行最后一个生成者
Object result = finalObjectSupplier.get();
if (result instanceof Exception) {
exception = (Exception) result;
} else {
object = result;
}
Exception finalException = exception;
Object finalObject = object;
//后置增强的顺序执行
afterAdvices.forEach(e->e.invokeAfter(clazz, method, objects, finalObject, finalException));
return object;
}
}
好了还剩下最后的织入器
public interface ProxyFactory {
<T> T generateProxy(T target, Advisor advisor);
default <T> Object doInterceptor(T target, DefaultAdvisor advisor, Method method, Object[] args) throws IllegalAccessException, InvocationTargetException {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (method.getDeclaringClass() == Object.class) {
return method.invoke(target, args);
}
if ("toString".equals(methodName) && parameterTypes.length == 0) {
return target.toString();
}
if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return target.hashCode();
}
if ("equals".equals(methodName) && parameterTypes.length == 1) {
return target.equals(args[0]);
}
if (!advisor.matchMethod(method)) return method.invoke(target, args);
Supplier<Object> supplier = () -> {
try {
return method.invoke(target, args);
} catch (Throwable throwable) {
return new RuntimeException(throwable);
}
};
AdviceChain adviceChain = advisor.buildChain(supplier);
return adviceChain.doInvoke(target.getClass(), method, args);
}
}
//jdk动态代理实现的织入器
public class JDKProxyFactory implements ProxyFactory {
@Override
public <T> T generateProxy(T target, Advisor advisor) {
DefaultAdvisor defaultAdvisor = (DefaultAdvisor) advisor;
if (!((DefaultAdvisor) advisor).matchClass(target)) return target;
Object proxyInstance = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> doInterceptor(target, (DefaultAdvisor) advisor, method, args));
return (T)proxyInstance;
}
}
//cglib实现逻辑类似
public class CglibProxyFactory implements ProxyFactory{
@Override
public <T>T generateProxy(T target , Advisor advisor){
DefaultAdvisor defaultAdvisor = (DefaultAdvisor) advisor;
if (!((DefaultAdvisor) advisor).matchClass(target)) return target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
// methodProxy.invokeSuper(o, objects);
enhancer.setCallback((MethodInterceptor) (o, method, args, methodProxy) ->
doInterceptor(target, (DefaultAdvisor) advisor, method, args));
return (T)enhancer.create();
}
}
// Javassist实现
public class JavassistProxyFactory implements ProxyFactory {
@Override
public <T> T generateProxy(T target, Advisor advisor) {
DefaultAdvisor defaultAdvisor = (DefaultAdvisor) advisor;
if (!((DefaultAdvisor) advisor).matchClass(target)) return target;
javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory();
factory.setInterfaces(target.getClass().getInterfaces());
Class<?> proxyClass = factory.createClass();
ProxyObject javassistProxy;
try {
javassistProxy = (ProxyObject) proxyClass.newInstance();
javassistProxy.setHandler((self, method, proceed, args) ->
doInterceptor(target, (DefaultAdvisor) advisor, method, args));
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
return (T) javassistProxy;
}
}
这里提醒一下,之前写jdk动态代理的使用,没有使用target作为执行的对象,然后遇到了未知错误, 所以要千万注意,不能写的太快了, 然后cglib那里我将原来的执行改成了method.invoke
, 是因为cglib的增强是支持方法嵌套增强的, 而jdk不支持, 所以为了统一就用method.invoke了, 另外cglib的底层是asm, javassist底层也是asm, 性能上的话我没有对比多.
测试类代码如下
public interface Sleep {
int sleep(int time);
}
public class SleepImpl implements Sleep{
@Override
public int sleep(int time) {
System.out.println(time);
return time;
}
}
public class MainTest {
public static void main(String[] args) {
Sleep sleep = new SleepImpl();
DefaultAdvisor advisor = new DefaultAdvisor(new ClassPointCut(Sleep.class)).addAdvice(new BeforeAdvice() {
@Override
public <T> void invokeBefore(Class<T> clazz, Method method, Object[] args) {
System.out.println("before");
}
}).addAdvice(new AfterAdvice() {
@Override
public <T> Object invokeAfter(Class<T> clazz, Method method, Object[] args, Object result, Exception exception) {
System.out.println("after");
return result;
}
}).addAdvice(new AroundAdvice() {
@Override
public <T> Object invoke(Class<T> clazz, Method method, Object[] args, Supplier<Object> supplier) throws Exception {
System.out.println("around before");
Object result = supplier.get();
System.out.println("around after");
return result;
}
}).addAdvice(new AroundAdvice() {
@Override
public <T> Object invoke(Class<T> clazz, Method method, Object[] args, Supplier<Object> supplier) throws Exception {
System.out.println("around before2");
Object result = supplier.get();
System.out.println("around after2");
return result;
}
});
ProxyFactory proxyFactory = new JavassistProxyFactory();
// ProxyFactory proxyFactory = new JDKProxyFactory();
// ProxyFactory proxyFactory = new CglibProxyFactory();
Sleep sleep1 = proxyFactory.generateProxy(sleep, advisor);
sleep1.sleep(100);
}
}
执行的结果如下
before
around before2
around before
100
around after
around after2
after
Process finished with exit code 0
可以看到执行的结果就是我想要的,进行aop增强后的结果, 虽然使用的时候用没有 spring的aop那么好用,但是实际上spring在启动的时候也会将基于注解的aop逻辑进行转换成具体的类, 所以让我们用的时候才会这么简单, 有了上面的这一套代码,就可以做很多的事情了,比如自己实现以个声明式的事务管理, 方法参数的日志打印等,都是可以的.