java使用动态代理Proxy

System.out.println(“判断天气是否良好”);

System.out.println(“路况是否良好”);

System.out.println(“控制谷歌的汽车启动”);

//调用谷歌汽车提供的C语言函数

}

@Override

public void run() {

System.out.println(“控制谷歌的汽车运行”);

}

@Override

public void stop() {

System.out.println(“控制谷歌汽车停止”);

}

}

一般上方的代码是不对外公开的所以无法直接通过new的方式来创建对象并调用其中的方法,并该类是通过final 修饰的所以也无法继承。

这个时候可以通过装着模式来对其类进行功能的增加,并丰富其中的方法

public class MyCar implements ICar{//实现其GoogleCar 类电实现的接口对应的方法

ICar car;

//虽然无法调用Google当中的方法也无法继承GoogleCar类,将GoogleCar通过参数的形式传递到对应的方法当中,将其GoogleCar的对象传递给GoogleCar的接口,通过接口来调用实现类当中的方法

public MyCar(ICar car) {

this.car=car;

}

@Override

public void start() {

// TODO Auto-generated method stub

System.out.println(“检查天气是否良好”);

System.out.println(“检查路况是否拥堵”);

car.start();

}

@Override

public void run() {

// TODO Auto-generated method stub

car.run();

}

@Override

public void stop() {

// TODO Auto-generated method stub

car.start();

}

}

public class TestCar {

public static void main(String[] args) {

ICar car = new MyCar(new GoogleCar());

car.start();

car.run();

car.stop();

}

}

输出结果为:

检查天气是否良好

检查路况是否拥堵

判断天气是否良好

路况是否良好

控制谷歌的汽车启动

控制谷歌的汽车运行

判断天气是否良好

路况是否良好

控制谷歌的汽车启动

(装饰着模式)弊端:

如果被实现的方法过多,装饰类当中的方法过多,需要动态代理的方式解决装饰着模式的弊端

动态代理模式

原理:通过虚拟机在内存当中创建类似与MyCar.class文件。

要创建这个文件MyCar.class文件要告诉虚拟机:

1、被创建的字节码文件上应该有多少方法。

2、

利用Java的反射技术(JavaReflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象),代理的是接口(Interfaces),不是类(Class),也不是抽象类。在运行时才知道具体的实现,spring aop就是此原理。

public static Object newProxyInstance(ClassLoader loader,

Class<?>[] interfaces,

InvocationHandler h)

throws IllegalArgumentException;

newProxyInstance,方法有三个参数:

loader: 用哪个类加载器去加载代理对象:孤单值,告诉虚拟机字节码加载器用哪个字节码加载器加载内存当中创建出的字节码文件

interfaces:动态代理类需要实现的接口:告诉虚拟机内存当中正在被创建的字节码文件当中应该有哪些

h:获取接口当中的方法,并且动态代理方法在执行时,会调用h里面的invoke方法去

TestCar.class.getClassLoader()将下面获取到的字节码对应的接口加载到本类的字节码当中,

GoogleCar.class.getInterfaces(),告诉虚拟机创建并获取GoogleCar字节码文件当中的所有接口 ,并不能获取其特有的方法

InvocationHandler()从接口当中获取那个方法,如何获取方法,复制那个方法,并执行新增的方法和特性

最后

通过上方一系列操作创建了一个对象ICar car = (ICar)需要强转

测试类方便理解GoogleCar.class.getInterfaces();获取到的是结构是什么

import java.lang.reflect.Method;

public class Test {

public static void main(String[] args) {

//获取GoogleCar googleCar.class字节码文件上所有的接口吗,googleCar上可能实现了多个接口

Class[] clazz = GoogleCar.class.getInterfaces();

for (Class cla : clazz) {

//获取到ICar.class对应的接口当中所有的方法

Method[] mds = cla.getMethods();

for (Method method : mds) {

System.out.println(method.getName());

}

}

}

}

运行结果

在这里插入图片描述

动态代理模式的实现


Proxy.newProxyInstance在内存当中创建字节码

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

public class TestCar {

public static void main(String[] args) {

//TestCar.class.getClassLoader()将下面获取到的字节码对应的接口加载到本类的字节码当中

//GoogleCar.class.getInterfaces(),告诉虚拟机创建并获取GoogleCar字节码文件当中的所有接口

//new InvocationHandler()从接口当中获取那个方法,如何获取接口对应方法,复制那个接口对应方法,并执行新增的方法和特性

//最后通过上方一系列操作创建了一个对象ICar car = (ICar)需要强转

ICar car = (ICar)Proxy.newProxyInstance(TestCar.class.getClassLoader(),

GoogleCar.class.getInterfaces(),

new InvocationHandler()

{

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

//经过测试得知:method代表当前正在执行每个方法

//System.out.println(method.getName());//获取到是是字节码文件GoogleCar当中的所有方法名称

//执行当前的方法

//method.invoke(new GoogleCar(), args);

if(method.getName().equalsIgnoreCase(“start”)) {//equalsIgnoreCase忽略大小写比较

//执行当前method对应的方法

System.out.println(“判断天气是否良好”);

System.out.println(“路况是否良好”);

method.invoke(new GoogleCar(), args);

}else {

//获取接口当中的方法,放到正在执行的方法当中

method.invoke(new GoogleCar(), args);

}

return null;

}

});

car.start();

car.run();

car.stop();

}

}

//也可以实现该接口然后将MyCC传入到第三个参数当中

class MyCC implements InvocationHandler{

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// TODO Auto-generated method stub

return null;

}

}

执行结果:

判断天气是否良好

路况是否良好

控制谷歌的汽车启动

控制谷歌的汽车运行

控制谷歌汽车停止

解析动态代理


TestCar.class.getClassLoader(),

GoogleCar.class.getInterfaces(),

new InvocationHandler()

在这里插入图片描述

上方代码生成TestCar$1.class字节码文件

TestCar$1.class生成上方代码当中的ICar对象的对象car

GoogleCar.class.getInterfaces():TestCar$1.class内放了GoogleCar的一堆方法

动态代理内的参数:

TestCar.class.getClassLoader():

字节码加载器:

jdk有一些程序,专业将各种字节码文件加载到内存当中,这里程序简称为字节码加载器。

如何将字节码文件class文件加载到内存当中?

底层实现的过程,利用IO流这种技术,获取到文件当中的数据,加载到内存当中。

字节码加载器:

在这里插入图片描述

TestCar.class.getClassLoader()将下面获取到的字节码对应的接口加载到本类的字节码当中。

GoogleCar.class.getInterfaces(),告诉虚拟机创建并获取GoogleCar字节码文件当中的所有接口 ,并不能获取其特有的方法。

InvocationHandler()从接口当中获取那个方法,如何获取方法,复制那个方法,并执行新增的方法和特性

Method:正在执行的方法

args:参数

改进上方代码验证各种参数的作用:

public interface ICar {

public String start(int a,int b);

public void run();

public void stop();

}

//相当于mysql的驱动包,是由谷歌汽车的开发人员来实现类

public class GoogleCar implements ICar {

@Override

public String start(int a,int b) {

System.out.println(“控制谷歌的汽车启动”);

//调用谷歌汽车提供的C语言函数

return “start…”+a+" "+b;

}

@Override

public void run() {

System.out.println(“控制谷歌的汽车运行”);

}

@Override

public void stop() {

System.out.println(“控制谷歌汽车停止”);

}

}

package com.itzheng.test06;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.Arrays;

public class TestCar {

public static void main(String[] args) {

// TestCar.class.getClassLoader()将下面获取到的字节码对应的接口加载到本类的字节码当中

// GoogleCar.class.getInterfaces(),告诉虚拟机创建并获取GoogleCar字节码文件当中的所有接口

// new InvocationHandler()从接口当中获取那个方法,如何获取方法,复制那个方法,并执行新增的方法和特性

// 最后通过上方一系列操作创建了一个对象ICar car = (ICar)需要强转

ICar car = (ICar) Proxy.newProxyInstance(TestCar.class.getClassLoader(), GoogleCar.class.getInterfaces(),

new InvocationHandler() {

//method代表正在执行的方法

//args:代表正在执行的方法的参数

//Object:代表方法执行完毕之后的返回值

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// 经过测试得知:method代表当前正在执行每个方法

// System.out.println(method.getName());//获取到是是字节码文件GoogleCar当中的所有方法名称

// 执行当前的方法

// method.invoke(new GoogleCar(), args);

// 代表每个方法执行完毕之后返回的对象

Object obj = null;

if (method.getName().equalsIgnoreCase(“start”)) {// equalsIgnoreCase忽略大小写比较

// 执行当前method对应的方法

System.out.println(“判断天气是否良好”);

// 打印args里面的内容

System.out.println(Arrays.toString(args));

System.out.println(“路况是否良好”);

obj = method.invoke(new GoogleCar(), args);

} else {

// 获取接口当中的方法

obj = method.invoke(new GoogleCar(), args);

}

return obj;

}

});

String cc = car.start(1, 4);

System.out.println(cc);

car.run();

car.stop();

}

}

//也可以实现该接口然后将MyCC传入到第三个参数当中

class MyCC implements InvocationHandler {

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// TODO Auto-generated method stub

return null;

}

}

执行结果

判断天气是否良好

[1, 4]

路况是否良好

控制谷歌的汽车启动

start…1 4

控制谷歌的汽车运行

控制谷歌汽车停止

字节码加载器:3种

1、系统引导加载器:.class.getClassLoader() java当中不存在由其他语言来实现的

public class TestClassLoader {

public static void main(String[] args) {

//系统引导的类加载器

//获取String类的加载器

ClassLoader classLoader = String.class.getClassLoader();//String类的字节码加载器

System.out.println(classLoader);

//由于String.class,int.class等字节码文件需要频繁的被加载到内存速度必须块,底层用其他语言来实现

}

}

在这里插入图片描述

2、ExtClassLoader扩展类加载器

public class TestClassLoader {

public static void main(String[] args) {

//获取ext(extendtion)包下的某个类下的字节码加载器

//ExtClassLoader扩展类加载器

ClassLoader classLoader2 = sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader();

System.out.println(classLoader2);

}

}

输出结果:

在这里插入图片描述

3、应用类加载器 AppClassLoader应用类内存当中实际存在的类

应用类:一般实现的所有类都是属于应用类(自己创建的类)

public class TestClassLoader {

public static void main(String[] args) {

//应用类:一般实现的所有类都是属于应用类(自己创建的类)

//获取应用类加载器 AppClassLoader

ClassLoader classLoader3 = TestClassLoader.class.getClassLoader();

System.out.println(classLoader3);

}

}

在这里插入图片描述

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
classLoader3 = TestClassLoader.class.getClassLoader();

System.out.println(classLoader3);

}

}

在这里插入图片描述

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-9ocJFvhF-1714817701589)]

[外链图片转存中…(img-ExlsCLlO-1714817701589)]

[外链图片转存中…(img-z9sVP4vL-1714817701589)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值