AOP的实现有两种,一种是接口的实现,一种是产生自己实现,分别的代表为JDK的Proxy和CGLIB的Proxy
下面是模拟接口代理实现 ,通过模拟JDK的动态代理,更深刻的理解
通过动态代理可以面向切面编程
1 定义被代理的对象和接口
public interface BookInterface {
void selling();
}
public interface PhoneInterface {
void selling();
}
public class Book implements BookInterface {
@Override
public void selling() {
System.out.println("books selling.....");
}
}
public class VivoPhone implements PhoneInterface {
@Override
public void selling() {
System.out.println("selling vivo x5");
}
}
2 定义切面类
public class TimeAspect {
static long bgn;
public static void before(){
bgn = System.currentTimeMillis();
System.out.println("begin time... " + bgn);
}
public static void after(){
long end = System.currentTimeMillis();
System.out.println("end time... " + (end-bgn));
}
}
public class LogAspect{
public static void before(){
System.out.println("begin log...");
}
public static void after(){
System.out.println("finish log...");
}
}
3 定义InvocationHander 代理接口
import java.lang.reflect.Method;
public interface InvocationHander {
public void invoke(Object o,Method m);
}
代理类(切面编程里面也可以做一些特殊的处理)
import java.lang.reflect.Method;
public class ProxyHander implements InvocationHander {
private Object target;
public ProxyHander(Object target) {
this.target = target;
}
@Override
public void invoke(Object o, Method m) {
try {
TimeAspect.before();
if(!(o instanceof BookInterface)){//只有非BookInterface接口调用日志
LogAspect.before();
}
m.invoke(target);
if(!(o instanceof BookInterface)){
LogAspect.after();
}
TimeAspect.after();
} catch (Exception e) {
e.printStackTrace();
}
}
}
动态代理类
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import org.apache.commons.io.FileUtils;
public class Proxy {
/*
* 空的构造函数
*/
private Proxy(){
}
/*
* 返回代理类
*/
public static Object newProxyInstance(Class inter,InvocationHander h){
String packageName = inter.getPackage().getName();
// String temp = new String(packageName);
String proxyClassName = "$"+packageName.replace(".","_") + "_" + inter.getSimpleName() +"Proxy";
String InHanderPackage = h.getClass().getPackage().getName();
String rt = "\r\n";// 换行
String methodCode = "";
for (Method method:inter.getMethods()) {
methodCode+=" @Override"+rt+
" public void "+ method.getName()+"() {"+rt+
" try{"+rt+
" Method method = "+inter.getName()+".class.getMethod(\""
+ method.getName()+ "\");"+rt+
" h.invoke(this,method); "+rt+
" }catch(Exception e ){" +rt+
" e.printStackTrace();" +rt+
" }"+rt+
" }";
}
/*
* 总的java代码
*/
String javaCode=
"package "+packageName+";"+rt+
"import "+InHanderPackage+".InvocationHander;"+rt+
"import java.lang.reflect.Method;"+rt+
"public class "+proxyClassName+" implements "+inter.getName()+" {"+rt+
" public "+proxyClassName+"("+InHanderPackage+".InvocationHander h) {"+rt+
" super();"+rt+
" this.h = h;"+rt+
" }"+rt+
" private "+InHanderPackage+".InvocationHander h;"+rt+
methodCode+rt+
"}";
/*
* 生成java文件
*/
// 生成文件路径
String filename = System.getProperty("user.dir")+"/bin/"+packageName.replace(".", "//")+"/"+proxyClassName+".java";
File file = new File(filename);
try {
// 需要commons-io的jar方便的操作文件
FileUtils.writeStringToFile(file, javaCode);
} catch (IOException e) {
e.printStackTrace();
}
// 编译 拿到编译器
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);
// call进行编译
t.call();
try {
fileMgr.close();
} catch (IOException e) {
e.printStackTrace();
}
// load到内存
ClassLoader cl = ClassLoader.getSystemClassLoader();
try {
Class c = cl.loadClass(packageName+"."+proxyClassName);
Constructor ctr = c.getConstructor(InvocationHander.class);
return ctr.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
4 测试
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestProxy {
@Before
public void before(){
System.out.println("-----------------start-------------------");
}
@Test
public void test() {
Book book = new Book();
InvocationHander h = new ProxyHander(book);
BookInterface bi = (BookInterface)Proxy.newProxyInstance(BookInterface.class,h);
bi.selling(); // 没有日志打印
System.out.println("==================分割==============================");
PhoneInterface car = new VivoPhone();
h = new ProxyHander(car);
PhoneInterface pi = (PhoneInterface)Proxy.newProxyInstance(PhoneInterface.class,h);
pi.selling(); // 有日志打印
}
@After
public void after(){
System.out.println("-----------------end-------------------");
}
}
Proxy类里面生成代理类名称的方法是根据包名来的,全类名长度加起来超过250多个长度可能会让java类无法编译,那就需要特殊处理了。超过250个长度的全类名那种项目没见过,不考虑
上面是他的原理,spring中如何使用aop呢?
请参考