【Java】Proxy JDK动态代理

Proxy JDK动态代理

萌妹子_liu发布于 今天 03:46

简介:

【Java】Proxy JDK动态代理

他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式,在jdk的动态代理中,B往往实现了一些接口,A也会去实现接口,但是实际上B是真正的接口的实现类,而A是通过B和接口等等一些参数生成的一个类(也就是代理类),它不仅具有与B同样的行为,它还可以增强B,在调用B的方法前后都做些其他的事情,实际上可以理解为把自己交给别人,让别人来控制自己的行为。最伟大的应用应该就是spring的aop了,而代理又分为动态代理和静态代理,下面我们便一一来介绍。

使用场景:

这玩意儿的应用已经很广泛了,比如aop是吧 :),当你想在调用一个方法的前后干点啥的时候,比如记录日志等,使用代理总比改每个方法的代码来的方便一些

静态代理:

事先由码农编写好代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成

模式实例:

写一个简单的静态代理的例子。我这儿举一个比较粗糙的例子,一个不完善的坦克大战小游戏,假如我要在测试的时候记录一下坦克什么时候开动、什么时候停止,但是我不能再回过头去源代码里面添加这些代码。那该怎么办呢,如果我们使用代理,该怎么操作呢,请听如下讲解。

1、Movable 接口

interface Movable{

void move();

}

2、Tank 坦克类

由于坦克类代码过多,我们就简单模拟一下坦克的移动,Tank类实现Movable接口。Tank可以具体实现移动的动作。

public class Tank implements Movable {

/**

* 模拟坦克移动了一段时间

*/

@Override

public void move() {

System.out.println("Tank moving claclacla......");

try{

Thread.sleep(new Random().nextInt(10000));

}catch (Exception e){

e.printStackTrace();

}

}

public static void main(String[] args) {

new TankTimeProxy(new TankLogProxy(new Tank())).move();

}

}

3、TankLogProxy 代理类

TankLogProxy,这个类也实现了Movable接口,但是还另外持有一个Movable(持有Movable的原因是可以对实现了Movable的一系列类做代理操作,比如Tank)。

/** * 坦克代理类,也实现了Movable接口,保存一个Tank实体,这样既可以代理坦克产生行为

* */

class TankLogProxy implements Movable {

Tank t;

public TankLogProxy(Tank t) {

this.t = t;

}

@Override

public void move() {

System.out.println("start moving......");

t.move();

System.out.println("stopped");

}

}

4、测试

public static void main(String[] args) {

new TankLogProxy(new Tank()).move();

}

这里并没有直接调用Tank(被代理对象)来执行移动的行为,而是通过代理对象来代理执行。这就是代理模式。

在jdk中,代理模式最主要的就是有一个公共接口(Movable),一个具体的类(Tank),一个代理类(TankLogProxy),代理类持有具体类的实例,代为执行具体类实例方法。那么我们在代理过程中就可以加上一些其他用途。就这个例子来说,我们可以在坦克开动之前和结束之后进行一系列的日志记录,通过代理模式很轻松就能办到

优点

1、 协调调用者和被调用者,在一定程度上降低了系统的耦合度。
2、 在代理的过程中我们可以对被代理对象做一些增强

缺点

1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
2、静态代理对一些复杂的类可能显得不是很灵活

动态代理:

前面介绍了静态代理,虽然静态代理模式很好用,但是静态代理还是存在一些局限性的,比如使用静态代理模式需要程序员手写很多代码。一旦需要代理的类中方法比较多,或者需要同时代理多个对象的时候,这无疑会增加很大的复杂度。

代理类在程序运行时创建的代理方式被成为动态代理。 我们上面静态代理的例子中,代理类(TankLogProxy)是事先定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法

模式实例:

在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象

1、Movable 接口

interface Movable{

void move();

}

2、Tank 坦克类

由于坦克类代码过多,我们就简单模拟一下坦克的移动,Tank类实现Movable接口。Tank可以具体实现移动的动作。

public class Tank implements Movable {

/**

* 模拟坦克移动了一段时间

*/

@Override

public void move() {

System.out.println("Tank moving claclacla......");

try{

Thread.sleep(new Random().nextInt(10000));

}catch (Exception e){

e.printStackTrace();

}

}

public static void main(String[] args) {

new TankTimeProxy(new TankLogProxy(new Tank())).move();

}

}

3、TimeProxy 实现InvocationHandler接口

class TimeProxy implements InvocationHandler{

Movable m;

public TimeProxy(Movable m) {

this.m = m;

}

public void before(){

System.out.println("method start..");

}

public void after(){

System.out.println("method stop..");

}

/** *Object proxy是生成的代理对象, Method method是Movable接口的move,通过反射获取, Object[] args是真实对象中调用方法的参数 */

@Override

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

before();

Object o = method.invoke(m,args);

after();

return o;

}

}

4、测试

public static void main(String[] args) {

Tank tank = new Tank();

/**

生成代理对象

Tank.class.getClassLoader():使用哪个类加载器来加载生成的代理对象

new Class[]{Movable.class}:被代理类实现了哪些接口

new TimeProxy(tank):代理的具体逻辑处理

*/

Movable m = (Movable) Proxy.newProxyInstance(Tank.class.getClassLoader(),

new Class[]{Movable.class},

new TimeProxy(tank));

m.move();

}

动态代理的优势在于可以很方便的对代理类的方法进行统一的处理,而不用修改每个代理类中的方法。因为所有被代理执行的方法,都是通过在InvocationHandler中的invoke方法调用的,所以我们只要在invoke方法中统一处理,就可以对所有被代理的方法进行相同的操作了。
动态代理原理图:
【Java】Proxy JDK动态代理

cglib:生成代理

package com.mashibing.proxy.cglib;

import java.lang.reflect.Method;

import java.util.Random;

import net.sf.cglib.proxy.Enhancer;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

public class Main {

public static void main(String[] args) {

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(Tank.class);

enhancer.setCallback(new TimeMethodInterceptor());

Tank tank = (Tank)enhancer.create();

tank.move();

}

}

class TimeMethodInterceptor implements MethodInterceptor{

@Override

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

System.out.println(o.getClass().getSuperclass().getName());

System.out.println("before");

Object result = null;

result = methodProxy.invokeSuper(o,objects);

System.out.println("after");

return result;

}

}

class Tank{

public void move() {

System.out.println("Tank moving claclacla...");

try{

Thread.sleep(new Random().nextInt(10000));

} catch (Exception e){

e.printStackTrace();

}

}

}

总结:jdk的动态代理,总的来说
1、Proxy通过传递给它的参数(interfaces/invocationHandler)生成代理类$Proxy0
2、Proxy通过传递给它的参数(ClassLoader)来加载生成的代理类$Proxy0的字节码文件

参考大神之作:https://www.cnblogs.com/java-chen-hao/p/10643744.html

java

阅读 42更新于 今天 04:00

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议

avatar

萌妹子_liu

1 声望

2 粉丝

0 条评论

得票时间

avatar

萌妹子_liu

1 声望

2 粉丝

宣传栏

简介:

【Java】Proxy JDK动态代理

他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式,在jdk的动态代理中,B往往实现了一些接口,A也会去实现接口,但是实际上B是真正的接口的实现类,而A是通过B和接口等等一些参数生成的一个类(也就是代理类),它不仅具有与B同样的行为,它还可以增强B,在调用B的方法前后都做些其他的事情,实际上可以理解为把自己交给别人,让别人来控制自己的行为。最伟大的应用应该就是spring的aop了,而代理又分为动态代理和静态代理,下面我们便一一来介绍。

使用场景:

这玩意儿的应用已经很广泛了,比如aop是吧 :),当你想在调用一个方法的前后干点啥的时候,比如记录日志等,使用代理总比改每个方法的代码来的方便一些

静态代理:

事先由码农编写好代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成

模式实例:

写一个简单的静态代理的例子。我这儿举一个比较粗糙的例子,一个不完善的坦克大战小游戏,假如我要在测试的时候记录一下坦克什么时候开动、什么时候停止,但是我不能再回过头去源代码里面添加这些代码。那该怎么办呢,如果我们使用代理,该怎么操作呢,请听如下讲解。

1、Movable 接口

interface Movable{

void move();

}

2、Tank 坦克类

由于坦克类代码过多,我们就简单模拟一下坦克的移动,Tank类实现Movable接口。Tank可以具体实现移动的动作。

public class Tank implements Movable {

/**

* 模拟坦克移动了一段时间

*/

@Override

public void move() {

System.out.println("Tank moving claclacla......");

try{

Thread.sleep(new Random().nextInt(10000));

}catch (Exception e){

e.printStackTrace();

}

}

public static void main(String[] args) {

new TankTimeProxy(new TankLogProxy(new Tank())).move();

}

}

3、TankLogProxy 代理类

TankLogProxy,这个类也实现了Movable接口,但是还另外持有一个Movable(持有Movable的原因是可以对实现了Movable的一系列类做代理操作,比如Tank)。

/** * 坦克代理类,也实现了Movable接口,保存一个Tank实体,这样既可以代理坦克产生行为

* */

class TankLogProxy implements Movable {

Tank t;

public TankLogProxy(Tank t) {

this.t = t;

}

@Override

public void move() {

System.out.println("start moving......");

t.move();

System.out.println("stopped");

}

}

4、测试

public static void main(String[] args) {

new TankLogProxy(new Tank()).move();

}

这里并没有直接调用Tank(被代理对象)来执行移动的行为,而是通过代理对象来代理执行。这就是代理模式。

在jdk中,代理模式最主要的就是有一个公共接口(Movable),一个具体的类(Tank),一个代理类(TankLogProxy),代理类持有具体类的实例,代为执行具体类实例方法。那么我们在代理过程中就可以加上一些其他用途。就这个例子来说,我们可以在坦克开动之前和结束之后进行一系列的日志记录,通过代理模式很轻松就能办到

优点

1、 协调调用者和被调用者,在一定程度上降低了系统的耦合度。
2、 在代理的过程中我们可以对被代理对象做一些增强

缺点

1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
2、静态代理对一些复杂的类可能显得不是很灵活

动态代理:

前面介绍了静态代理,虽然静态代理模式很好用,但是静态代理还是存在一些局限性的,比如使用静态代理模式需要程序员手写很多代码。一旦需要代理的类中方法比较多,或者需要同时代理多个对象的时候,这无疑会增加很大的复杂度。

代理类在程序运行时创建的代理方式被成为动态代理。 我们上面静态代理的例子中,代理类(TankLogProxy)是事先定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法

模式实例:

在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象

1、Movable 接口

interface Movable{

void move();

}

2、Tank 坦克类

由于坦克类代码过多,我们就简单模拟一下坦克的移动,Tank类实现Movable接口。Tank可以具体实现移动的动作。

public class Tank implements Movable {

/**

* 模拟坦克移动了一段时间

*/

@Override

public void move() {

System.out.println("Tank moving claclacla......");

try{

Thread.sleep(new Random().nextInt(10000));

}catch (Exception e){

e.printStackTrace();

}

}

public static void main(String[] args) {

new TankTimeProxy(new TankLogProxy(new Tank())).move();

}

}

3、TimeProxy 实现InvocationHandler接口

class TimeProxy implements InvocationHandler{

Movable m;

public TimeProxy(Movable m) {

this.m = m;

}

public void before(){

System.out.println("method start..");

}

public void after(){

System.out.println("method stop..");

}

/** *Object proxy是生成的代理对象, Method method是Movable接口的move,通过反射获取, Object[] args是真实对象中调用方法的参数 */

@Override

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

before();

Object o = method.invoke(m,args);

after();

return o;

}

}

4、测试

public static void main(String[] args) {

Tank tank = new Tank();

/**

生成代理对象

Tank.class.getClassLoader():使用哪个类加载器来加载生成的代理对象

new Class[]{Movable.class}:被代理类实现了哪些接口

new TimeProxy(tank):代理的具体逻辑处理

*/

Movable m = (Movable) Proxy.newProxyInstance(Tank.class.getClassLoader(),

new Class[]{Movable.class},

new TimeProxy(tank));

m.move();

}

动态代理的优势在于可以很方便的对代理类的方法进行统一的处理,而不用修改每个代理类中的方法。因为所有被代理执行的方法,都是通过在InvocationHandler中的invoke方法调用的,所以我们只要在invoke方法中统一处理,就可以对所有被代理的方法进行相同的操作了。
动态代理原理图:
【Java】Proxy JDK动态代理

cglib:生成代理

package com.mashibing.proxy.cglib;

import java.lang.reflect.Method;

import java.util.Random;

import net.sf.cglib.proxy.Enhancer;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

public class Main {

public static void main(String[] args) {

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(Tank.class);

enhancer.setCallback(new TimeMethodInterceptor());

Tank tank = (Tank)enhancer.create();

tank.move();

}

}

class TimeMethodInterceptor implements MethodInterceptor{

@Override

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

System.out.println(o.getClass().getSuperclass().getName());

System.out.println("before");

Object result = null;

result = methodProxy.invokeSuper(o,objects);

System.out.println("after");

return result;

}

}

class Tank{

public void move() {

System.out.println("Tank moving claclacla...");

try{

Thread.sleep(new Random().nextInt(10000));

} catch (Exception e){

e.printStackTrace();

}

}

}

总结:jdk的动态代理,总的来说
1、Proxy通过传递给它的参数(interfaces/invocationHandler)生成代理类$Proxy0
2、Proxy通过传递给它的参数(ClassLoader)来加载生成的代理类$Proxy0的字节码文件

参考大神之作:https://www.cnblogs.com/java-chen-hao/p/10643744.html

以上是 【Java】Proxy JDK动态代理 的全部内容, 来源链接: utcz.com/a/114915.html

回到顶部