代理在java语言中应用非常广泛,一个对象的功能借助另一个有相同功能的对象来完成,功能业务逻辑不变,这样可以添加一些额外的“轻逻辑”进去
这里的轻逻辑是指一些通用逻辑,比如在一个代理方法调用之前之后加一些日志,或者在执行数据库操作之前之后做一些事务处理
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);
return 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;
}
}
运行结果为:
开始导航 ...
路虎车开始行驶 ...
结束导航 ...
可以看出,借助代理,我们可以把程序业务逻辑和横向通用逻辑分开,把代码进行解耦,让代码编写人员可以分别关注不同的模块,让架构设计更灵活。