Java动态代理演化之:基于Class对象实际场景应用

如果对Class对象的原理和来龙去脉不清晰,请查看本人下面这篇文章,本文主要阐述基于Class对象应用场景

https://blog.csdn.net/u013620306/article/details/124466796

1:场景一:动态代理

1)DK提供了java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类,这两个类相互配合,入口是Proxy,所以我们先聊它。

2)Proxy有个静态方法:getProxyClass(ClassLoader, interfaces),只要你给它传入类加载器和一组接口,它就给你返回代理Class对象

3)Proxy还有一个静态方法:newProxyInstance(ClassLoader, interfaces, InvocationHandler),返回代理对象,代理对象在调用接口函数时,通过InvocationHandler 来回掉invoke()函数,这样就有在此函数中编写增强代码,最后通过 Method.invoke(interfaceImpl, args) 来回调接口实现类函数

1.1 :代码示例

通过Proxy的 getProxyClass(ClassLoader, interfaces)来实现

       // 1: ClassLoader加载字节码文件 得到 Class对象
        Class animalProxy = 
                Proxy.getProxyClass(Animal.class.getClassLoader(),Animal.class);
       
        // 得到有参构造器 $Proxy0(InvocationHandler h)
        try {
            Constructor constructor = 
                  animalProxy.getConstructor(InvocationHandler.class);
            
           // 2:反射获取代理实例
            try {
                Animal animalProxyImpl  = (Animal) constructor.newInstance(new 
                InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) 
                    throws Throwable {
                       
                       // 4: 回调 InvocationHandler的 invoke() 函数
                        Animal animalImpl = new AnimalImpl();
                        if (method.getName().equals("sleep")) {
                            System.out.println("睡觉盖被子");
                            try {
                                method.invoke(animalImpl,null);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        } else if (method.getName().equals("eat")) {
                            System.out.println("吃肉喝酒");
                            try {
                                method.invoke(animalImpl,null);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                        return null;
                    }
                });
                // 3: 代理对象 调用 Animal接口方法
                animalProxyImpl.eat();
                animalProxyImpl.sleep();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }


AnimalImpl.java
public class AnimalImpl implements Animal{
    @Override
    public void eat() {
        System.out.println("长高高");
    }

    @Override
    public void sleep() {
        System.out.println("身体好");
    }
}

Animal.java
public interface Animal {
    public void eat();
    public void sleep();
}



打印: 
吃肉喝酒
长高高
睡觉盖被子
身体好
  

通过 Proxy.newProxyInstance()函数来实现

        Class<Animal> animalClass = null;
        try {
            animalClass = (Class<Animal>) 
            Class.forName("io.reactivex.rxjava3.android.samples.proxy.Animal");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Class<?>[] classes = {animalClass};
        Animal animalImpl = new AnimalImpl();

        
        Object instance = Proxy.newProxyInstance(Animal.class.getClassLoader(),classes,
                new InterfaceInvocationHandler(animalImpl));
        Animal animal = (Animal) instance;
        animal.eat();
        animal.sleep();



public class InterfaceInvocationHandler implements InvocationHandler {

    private final Animal animalImpl;

    public InterfaceInvocationHandler(Animal animal) {
        this.animalImpl = animal;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        if (method.getName().equals("sleep")) {
            System.out.println("睡觉盖被子");
            try {
                method.invoke(animalImpl,null);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } else if (method.getName().equals("eat")) {
            System.out.println("吃肉喝酒");
            try {
                method.invoke(animalImpl,null);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

打印:
  吃肉喝酒
长高高
睡觉盖被子
身体好

上面两种方法,目标都像都是要预先构造出来,那么我们能不能再次优化下,封装函数,目标函数从外部引入

 public static void main(String[] args) throws Throwable {
            CalculatorImpl target = new CalculatorImpl();
            // 从外部传入 目标对象
            Calculator calculatorProxy = (Calculator) getProxy(target);
            calculatorProxy.add(1, 2);
            calculatorProxy.subtract(2, 1);
        }

        private static Object getProxy(final Object target) throws Exception {
            Object proxy = Proxy.newProxyInstance(
                    /*类加载器*/
                    target.getClass().getClassLoader(),
                    /*让代理对象和目标对象实现相同接口*/
                    target.getClass().getInterfaces(),

                    /*代理对象的方法最终都会被JVM导向它的invoke方法*/
                    new InvocationHandler(){
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println(method.getName() + "方法开始执行...");
                            Object result = method.invoke(target, args);
                            System.out.println(result);
                            System.out.println(method.getName() + "方法执行结束...");
                            return result;
                        }
                    }
            );
            return proxy;
        }

2 :场景二:载入数据库驱动的时候

Class.forName的一个非经常见的使用方法是在载入数据库驱动的时候

Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection con=DriverManager.getConnection("jdbc:sqlserver://localhost:1433;DatabaseName==JSP","jph","jph");  

3:场景三:使用AIDL与电话管理Servic进行通信

Method method =Class.forName("android.os.ServiceManager")
 
         .getMethod("getService",String.class);
 
// 获取远程TELEPHONY_SERVICE的IBinder对象的代理
 
IBinder binder =(IBinder) method.invoke(null, new Object[] { TELEPHONY_SERVICE});
 
// 将IBinder对象的代理转换为ITelephony对象
 
ITelephonytelephony = ITelephony.Stub.asInterface(binder);
 
// 挂断电话
 
telephony.endCall();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值