java代理机制
2015-06-08 22:48
411 查看
代理在java语言中应用非常广泛,一个对象的功能借助另一个有相同功能的对象来完成,功能业务逻辑不变,这样可以添加一些额外的“轻逻辑”进去
这里的轻逻辑是指一些通用逻辑,比如在一个代理方法调用之前之后加一些日志,或者在执行数据库操作之前之后做一些事务处理
java代理分为两种:静态代理和动态代理,静态代理就是在编译成字节码之前代理就已经发生了,动态代理就是字节码加载到内存的时候,根据是否需要再代理
首先我们定义一个接口:
package com.framework.common.java.delegate;
/**
* 横切逻辑,一般用作代码通用逻辑
*/
public class Navigator {
public static void start(){
System.out.println("开始导航 ... ");
}
public static void end(){
System.out.println("结束导航 ... ");
}
} 做一个静态代理:
package com.framework.common.java.delegate;
/**
* 被代理方
*/
class BaoMa implements ICar{
public void drive() {
System.out.println("宝马车开始行驶 ... ");
}
}
静态代理中,我们代理类和被代理类的代码都得自己写,而且一般至少要写两个类,而且在编写的时候,我们就要知道代理逻辑,并把代码逻辑编码到每个代理类中
幸好我们有动态代理技术,动态代理正好解决了这个问题,我们只需要编写一份代理逻辑,就可以动态代理一批类
动态代理有三种方式jdk动态代理,asm动态代理,cglib动态代理(实际来讲只有两种,cglib只是封装了前两种代理方式,但是用法上我们可以把它们当作三种)
jdk动态代理:
开始导航 ...
奔驰车开始行驶 ...
开始导航 ...
asm动态代理,asm是动态字节码技术,它操作java字节码文件,并动态定义各个方法指令,通过这种方式在代码中嵌入横向逻辑
asm代理需要引入asm相关的依赖这里面我引入的是spring自己集成的asm,其中用法跟asm原生的包是一样的:spring-asm-3.1.0.RELEASE.jar
运行结果为:
开始导航 ...
奥迪车开始行驶 ...
结束导航 ... cglib的代理封装了jdk和asm的逻辑,因此其代码看起来比asm要整洁得多,cglib代理需要引入cglib依赖,如:cglib-nodep-3.1.jar依赖
开始导航 ...
路虎车开始行驶 ...
结束导航 ... 可以看出,借助代理,我们可以把程序业务逻辑和横向通用逻辑分开,把代码进行解耦,让代码编写人员可以分别关注不同的模块,让架构设计更灵活。
这里的轻逻辑是指一些通用逻辑,比如在一个代理方法调用之前之后加一些日志,或者在执行数据库操作之前之后做一些事务处理
java代理分为两种:静态代理和动态代理,静态代理就是在编译成字节码之前代理就已经发生了,动态代理就是字节码加载到内存的时候,根据是否需要再代理
首先我们定义一个接口:
package com.framework.common.java.delegate; /** * 定义车的功能 */ public interface ICar { /** * 车可以行驶 */ void drive(); }再定义一些“轻逻辑”的小功能
package com.framework.common.java.delegate;
/**
* 横切逻辑,一般用作代码通用逻辑
*/
public class Navigator {
public static void start(){
System.out.println("开始导航 ... ");
}
public static void end(){
System.out.println("结束导航 ... ");
}
} 做一个静态代理:
package com.framework.common.java.delegate;
/**
* 被代理方
*/
class BaoMa implements ICar{
public void drive() {
System.out.println("宝马车开始行驶 ... ");
}
}
/** * 代理方 */ class Car1 implements ICar{ private ICar delegate; public Car1(ICar delegate){ this.delegate = delegate; } public void drive() { Navigator.start(); delegate.drive(); Navigator.end(); } }
/** * 静态代理 */ public class MyDelegate { public static void main(String[] args){ ICar car = new Car1(new BaoMa()); car.drive(); } }结果为:
开始导航 ... 宝马车开始行驶 ... 结束导航 ...
静态代理中,我们代理类和被代理类的代码都得自己写,而且一般至少要写两个类,而且在编写的时候,我们就要知道代理逻辑,并把代码逻辑编码到每个代理类中
幸好我们有动态代理技术,动态代理正好解决了这个问题,我们只需要编写一份代理逻辑,就可以动态代理一批类
动态代理有三种方式jdk动态代理,asm动态代理,cglib动态代理(实际来讲只有两种,cglib只是封装了前两种代理方式,但是用法上我们可以把它们当作三种)
jdk动态代理:
package com.framework.common.java.delegate; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 需要被切面的对象 */ class BenChi implements ICar { public void drive() { System.out.println("奔驰车开始行驶 ... "); } }
/** * jdk横向动态代理 */ public class JdkAspect { /** * jdk 的横切编程 */ public static void main(String[] args) { ICar car = (ICar) new Weaver().newInstance(new BenChi()); car.drive(); } } /** * 织入构造器 */ class Weaver implements InvocationHandler { private Object target; public Object newInstance(Object target) { this.target = target; Class<?> clasz = target.getClass(); return Proxy.newProxyInstance(clasz.getClassLoader(), clasz.getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Navigator.start(); Object result = method.invoke(target, args); Navigator.start(); return result; } }结果为:
开始导航 ...
奔驰车开始行驶 ...
开始导航 ...
asm动态代理,asm是动态字节码技术,它操作java字节码文件,并动态定义各个方法指令,通过这种方式在代码中嵌入横向逻辑
asm代理需要引入asm相关的依赖这里面我引入的是spring自己集成的asm,其中用法跟asm原生的包是一样的:spring-asm-3.1.0.RELEASE.jar
package com.framework.common.java.delegate; import org.springframework.asm.ClassAdapter; import org.springframework.asm.ClassReader; import org.springframework.asm.ClassVisitor; import org.springframework.asm.ClassWriter; import org.springframework.asm.MethodAdapter; import org.springframework.asm.MethodVisitor; import org.springframework.asm.Opcodes; import java.lang.reflect.Method; /** * 业务类 */ class AoDi { public void myDrive() { System.out.println("奥迪车开始行驶 ... "); } } /** * asm动态代理 */ public class AsmAspect { public static void main(String[] args) throws Exception { AoDi audi = (AoDi) new ClassTransformer().newInstance(AoDi.class); audi.myDrive(); } } /** * class解析 */ class ClassModifier extends ClassAdapter implements Opcodes { private String adviceName = Navigator.class.getName().replace(".", "/"); private String className; private String superName; public ClassModifier(ClassVisitor cv, String className, String superName) { super(cv); this.className = className.replace(".", "/"); this.superName = superName.replace(".", "/"); } @Override public void visit(int version, int access, String name, String signature, String objectName, String[] interfaces) { super.visit(version, ACC_PUBLIC, className, signature, superName, interfaces); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodModifier method = new MethodModifier(super.visitMethod(access, name, desc, signature, exceptions), name); if (name.equals("<init>")) { method.visitCode(); method.visitVarInsn(ALOAD, 0); method.visitMethodInsn(INVOKESPECIAL, superName, "<init>", "()V"); method.visitInsn(RETURN); method.visitMaxs(1, 1); method.visitEnd(); } return method; } /** * method 解析 */ class MethodModifier extends MethodAdapter implements Opcodes { private String methodName; public MethodModifier(MethodVisitor arg0, String methodName) { super(arg0); this.methodName = methodName; } @Override public void visitCode() { if (!methodName.equals("<init>")) { mv.visitMethodInsn(INVOKESTATIC, adviceName, "start", "()V");//织入逻辑 } } public void visitInsn(int opcode) { if (!methodName.equals("<init>")) { if ((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) { mv.visitMethodInsn(INVOKESTATIC, adviceName, "end", "()V");//织入逻辑 } } mv.visitInsn(opcode); } } } /** * 子类生成 */ class ClassTransformer { private Class<?> modifyClass(Class<?> targetClass) throws Exception { String superName = targetClass.getName(); String className = superName + "$asmProxy"; ClassLoader loader = targetClass.getClassLoader(); Method getClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class); getClass.setAccessible(true); Class<?> clasz = (Class<?>) getClass.invoke(loader, className); if (clasz == null) { ClassWriter classWriter = new ClassWriter(true); new ClassReader(targetClass.getResourceAsStream(targetClass.getSimpleName() + ".class")).accept(new ClassModifier(classWriter, className, targetClass.getName()), true); byte[] bytes = classWriter.toByteArray(); Method load = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); load.setAccessible(true); clasz = (Class<?>) load.invoke(loader, className, bytes, 0, bytes.length);//classloader加载重定义的字节码文件 } return clasz; } public Object newInstance(Class<?> targetClass) throws Exception { Class<?> clasz = modifyClass(targetClass); ret aad1 urn clasz.newInstance(); } }
运行结果为:
开始导航 ...
奥迪车开始行驶 ...
结束导航 ... cglib的代理封装了jdk和asm的逻辑,因此其代码看起来比asm要整洁得多,cglib代理需要引入cglib依赖,如:cglib-nodep-3.1.jar依赖
package com.framework.common.java.delegate; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * 业务类 */ class LuHu { public void myDrive(){ System.out.println("路虎车开始行驶 ... "); } } /** * cglib动态代理 */ public class CglibAspect { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(LuHu.class); enhancer.setCallback(new MethodInterceptorImpl()); LuHu car = (LuHu) enhancer.create(); car.myDrive(); } } /** * 方法适配器 */ class MethodInterceptorImpl implements MethodInterceptor { public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable { Navigator.start(); Object result = proxy.invokeSuper(obj, args); Navigator.end(); return result; } }运行结果为:
开始导航 ...
路虎车开始行驶 ...
结束导航 ... 可以看出,借助代理,我们可以把程序业务逻辑和横向通用逻辑分开,把代码进行解耦,让代码编写人员可以分别关注不同的模块,让架构设计更灵活。
相关文章推荐
- 依附品牌做代理 把握创业新机遇
- 代理区独立模式的说明
- http代理相关知识分析
- JavaScript的事件代理和委托实例分析
- asp代理采集的核心函数代码
- nginx 1.0.0配ngx_cache_purge实现高效的反向代理
- java实现动态代理方法浅析
- 用Python编写脚本使IE实现代理上网的教程
- 在python中的socket模块使用代理实例
- 仅用50行Python代码实现一个简单的代理服务器
- 在Nginx中拦截特定用户代理的教程
- 使用Nginx做WebSockets代理教程
- Windows下用Nginx代理Django安装配置实例
- 在VPS搭建自己的http代理服务器
- nginx学习总结五(nginx反向代理)
- linux命令行界面设置代理方法
- Squid-Linux下的使用详解
- iptables+squid透明代理+防火墙终极配置
- java代理模式