1. 原理
AOP切面编程分为静态编织和动态代理两种模式。AOP其实就是设计模式中代 理模式,代理类全权代理被代理类执行方法。调用方法的对象实际拿到的不是原始的类,而是被增强后的类。
静态编织:
在原始类进行编译的时候,进行编译生成新的类。Aspectj为代表。
动态代理:
在代码运行中进行动态的生成代理类。比如:java动态代理,CGLIB技术。
2. 分析
-
静态编织
编织后的代码通过字节码可以看到类似的代码:
public void ajc$around$com_listenzhangbin_aop_TxAspect$1$f54fe983(AroundClosure ajc$aroundClosure) {
System.out.println("开始事务 ...");
ajc$around$com_listenzhangbin_aop_TxAspect$1$f54fe983proceed(ajc$aroundClosure);
System.out.println("事务结束 ...");
}
-
动态代理
java动态代理:主要通过实现InvocationHandler和使用Proxy来生成新的代理类。
package jdkproxy;
/**
* 该类是所有被代理类的接口类,jdk实现的代理要求被代理类基于统一的接口
*
* @author typ
*
*/
public interface Service {
/**
* add方法
*/
public void add();
/**
* update方法
*/
public void update();
}
package jdkproxy;
/**
* 被代理类,即目标类target
*
* @author typ
*
*/
public class AService implements Service {
/*
* (non-Javadoc)
*
* @see jdkproxy.Service#add()
*/
public void add() {
System.out.println("AService add>>>>>>>>>>>>>>>>>>");
}
/*
* (non-Javadoc)
*
* @see jdkproxy.Service#update()
*/
public void update() {
System.out.println("AService update>>>>>>>>>>>>>>>");
}
}
package jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author typ
*
*/
public class MyInvocationHandler implements InvocationHandler {
private Object target;
MyInvocationHandler() {
super();
}
MyInvocationHandler(Object target) {
super();
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 程序执行前加入逻辑,MethodBeforeAdviceInterceptor
System.out.println("before-----------------------------");
// 程序执行
Object result = method.invoke(target, args);
// 程序执行后加入逻辑,MethodAfterAdviceInterceptor
System.out.println("after------------------------------");
return result;
}
}
public static void main(String[] args) {
Service aService = new AService();
MyInvocationHandler handler = new MyInvocationHandler(aService);
// Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例
Service aServiceProxy = (Service) Proxy.newProxyInstance(aService
.getClass().getClassLoader(), aService.getClass()
.getInterfaces(), handler);
// 由动态生成的代理对象来aServiceProxy 代理执行程序,其中aServiceProxy 符合Service接口
aServiceProxy.add();
System.out.println();
aServiceProxy.update();
// 以下是对B的代理
// Service bService = new BService();
// MyInvocationHandler handler = new MyInvocationHandler(bService);
// Service bServiceProxy = (Service) Proxy.newProxyInstance(bService
// .getClass().getClassLoader(), bService.getClass()
// .getInterfaces(), handler);
// bServiceProxy.add();
// System.out.println();
// bServiceProxy.update();
}
-
代码详解:
其实InvactionHandler的实现类就类似于Spring中的切面类。Proxy中代码就是Spring内部去做的事。这种java动态代理实际必须要按照设计模式中的UML图中的架构,需要被代理类实现一个接口。然后思考一个问题,Proxy到底做了什么?
其实他做了以下几件事:
- 创建一个新的类代码
- 实现原始类的接口和方法
- 使用反射获得方法,回调InvocationHandler的实现类的方法来增强方法
- 将这个类加载入内存
类似于下面的代码
package com.tgb.proxy;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
public class Proxy {
/**
*
* @param infce 被代理类的接口
* @param h 代理类
* @return
* @throws Exception
*/
public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {
String methodStr = "";
String rt = "\r\n";
//利用反射得到infce的所有方法,并重新组装
Method[] methods = infce.getMethods();
for(Method m : methods) {
methodStr += " @Override" + rt +
" public "+m.getReturnType()+" " + m.getName() + "() {" + rt +
" try {" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
" h.invoke(this, md);" + rt +
" }catch(Exception e) {e.printStackTrace();}" + rt +
" }" + rt ;
}
//生成Java源文件
String srcCode =
"package com.tgb.proxy;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class $Proxy1 implements " + infce.getName() + "{" + rt +
" public $Proxy1(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
" com.tgb.proxy.InvocationHandler h;" + rt +
methodStr + rt +
"}";
String fileName =
"d:/src/com/tgb/proxy/$Proxy1.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(srcCode);
fw.flush();
fw.close();
//将Java文件编译成class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(fileName);
CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
//加载到内存,并实例化
URL[] urls = new URL[] {new URL("file:/" + "d:/src/")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.tgb.proxy.$Proxy1");
Constructor ctr = c.getConstructor(InvocationHandler.class);
Object m = ctr.newInstance(h);
return m;
}
}
CGLIB代理:
它是基于继承来实现代理,java的动态代理是基于反射的。主要是使用MethodInterceptor 和工厂类Enhancer来实现,其实和java的代理差不多,限制少一点。
package cglibproxy;
/**
* 被代理类,即目标对象target
*
* @author typ
*
*/
public class Base {
/**
* 一个模拟的add方法
*/
public void add() {
System.out.println("add ------------");
}
}
package cglibproxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 此为代理类,用于在pointcut处添加advise
*
* @author typ
*
*/
public class CglibProxy implements MethodInterceptor {
public Object intercept(Object object, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
// 添加切面逻辑(advise),此处是在目标类代码执行之前,即为MethodBeforeAdviceInterceptor。
System.out.println("before-------------");
// 执行目标类add方法
proxy.invokeSuper(object, args);
// 添加切面逻辑(advise),此处是在目标类代码执行之后,即为MethodAfterAdviceInterceptor。
System.out.println("after--------------");
return null;
}
}
package cglibproxy;
import net.sf.cglib.proxy.Enhancer;
/**
* 工厂类,生成增强过的目标类(已加入切入逻辑)
*
* @author typ
*
*/
public class Factory {
/**
* 获得增强之后的目标类,即添加了切入逻辑advice之后的目标类
*
* @param proxy
* @return
*/
public static Base getInstance(CglibProxy proxy) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Base.class);
//回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法
enhancer.setCallback(proxy);
// 此刻,base不是单纯的目标类,而是增强过的目标类
Base base = (Base) enhancer.create();
return base;
}
}
package cglibproxy;
/**
* @author typ
*
*/
public class Test {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
// base为生成的增强过的目标类
Base base = Factory.getInstance(proxy);
base.add();
}
}
其实代码结构上和java动态代理一样的。
查看源码看不懂,也没搞明白它是怎么实现继承的。
以后再说吧。
引用以下文章:
Spring AOP的实现原理
Spring 容器AOP的实现原理——动态代理
Spring AOP 实现原理与 CGLIB 应用
AOP的底层实现-CGLIB动态代理和JDK动态代理