影分身之术-Java动态代理

影分身之术-Java动态代理动态代理是不通过硬编码,动态生成代理类的技术,分为JDK动态代理与CGlib动态代理两种方式;假设我们来到了火影忍者的世界,有一个Ninja(忍者)类,它实现了接口Warrior接口输出为:那么通过动

动态代理是不通过硬编码,动态生成代理类的技术,分为JDK动态代理与CGlib动态代理两种方式;

假设我们来到了火影忍者的世界,有一个Ninja(忍者)类,它实现了接口Warrior接口

public interface Warrior {
    public String fight(String args);
}
public class Ninja implements Warrior{
    public String name;
    public int chakra;
    public Ninja(String name,int chakar){
        this.name = name;
        this.chakra = chakar;
    }
    public String fight(String args){
        StringBuilder builder = new StringBuilder();
        builder.append(name).append("发动忍术:【").append(args).append("】,查克拉量:").append(chakra);
        String fighting_trick =builder.toString();
        System.out.print(fighting_trick);
        return fighting_trick;
    }
    public static void main(String[] args){
        Ninja ninja = new Ninja("长门",100);
        ninja.fight("地爆天星");
    }
}

输出为:

长门发动忍术:【地爆天星】,查克拉量:100

那么通过动态代理,给他进行增强(开挂)该怎么做呢?

影分身之术-JDK动态代理

忍术的施展(函数调用)交给InvocationHandler去处理,它只有一个函数invoke(...),函数签名如下;

Object invoke(Object proxy, Method method, Object[] args) 

而影分身(动态代理类)对象由:Proxy.newProxyInstance()生成,它会返回指定接口的代理类的实例; 它需要三个参数:

  • Classloader 类加载器
  • Interfaces 接口数组
  • 实现InvocationHandler 接口的类

代理对象会将方法调用(method invacation)分发到给定的调用处理器invocation handler上,原函数通过反射机制进行调用Method.invoke(...)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class NinjaHandler implements InvocationHandler {

    Ninja ninjaCopy;//分身
    public NinjaHandler(Ninja ninja){
        this.ninjaCopy=ninja;
    }
    /** * @param proxy 代理类 * @param method 正在调用的方法 * @param args 方法的参数 * @return obj * @throws Throwable */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before NinjaHandler Invoke");
        System.out.println("Call Method:"+method);
        ninjaCopy.chakra*=10;//将查克拉量*10
        Object obj=method.invoke(ninjaCopy,args);
        System.out.println("After NinjaHandler Invoke");
        System.out.println("Return Result:"+obj);
        return obj;
    }
}

我们在JDK动态代理中,将分身的查克拉量(属性)*10,然后我们开始调用使用JDK动态代理增强之后的影分身;

public class Test(){
    public static void main(String[] args){
        public static void main(String[] args){
        //要代理的真实对象
        Ninja Ninja=new Ninja("长门",100);
        InvocationHandler NinjaHandler=new NinjaHandler(Ninja);
        Warrior dynamicProxy=(Warrior)Proxy.newProxyInstance(
                NinjaHandler.getClass().getClassLoader(),
                Ninja.getClass().getInterfaces(),
                NinjaHandler
        );
        String result = dynamicProxy.fight("hello world");
        System.out.println("Result is: " + result);
        System.out.println(dynamicProxy.getClass().getName());
        System.out.println("是否为同一对象:"+dynamicProxy.getClass().isInstance(Ninja));
        System.out.println("是否继承自同一接口:"+(dynamicProxy instanceof Warrior));
    }
}

输出结果如下,可以看到原Ninja类被增强了:

Before NinjaHandler Invoke
Call Method:public abstract java.lang.String mock.dynamicProxy.Warrior.fight(java.lang.String)
长门发动忍术:【hello world】,查克拉量:1000
After NinjaHandler Invoke
Return Result:长门发动忍术:【hello world】,查克拉量:1000
Result is: 长门发动忍术:【hello world】,查克拉量:1000
=============
com.sun.proxy.$Proxy0
是否为同一对象:false
是否继承自同一接口:true

血继限界-CGlib代理

CGlib代理机制,主要是实现MethodInterceptor接口,intercept(...)方法,其函数签名如下:

Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;

然后由Enhancer生成动态代理,Enhancer负责制定父类setSuperclass,设定好方法回调setCallback

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
    private Object target;
    public CglibProxy(Object target){
        this.target=target;
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("### before invocation");
        Object result = method.invoke(target, objects);
        System.out.println("### end invocation");
        return result;
    }
    public static Object getProxy(Object target) {
        Enhancer ninjaChild = new Enhancer();
        // 设置需要代理的对象
        ninjaChild.setSuperclass(target.getClass());
        // 设置代理人
        ninjaChild.setCallback(new CglibProxy(target));
        return ninjaChild.create();
    }
}

测试函数:

Ninja ninjaSuccessor=(Ninja)CGlibProxy.getProxy(new Ninja("长门",100));
String res=ninjaSuccessor.fight("hello world");
System.out.println("Result is: " + res);

输出,这个类似于鸣人与博人的关系,继承其父类(血继限界):

### before invocation
长门发动忍术:【hello world】,查克拉量:100
### end invocation
Result is: 长门发动忍术:【hello world】,查克拉量:100

图示总结如下:

影分身之术-Java动态代理

今天的文章影分身之术-Java动态代理分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19799.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注