利用反射生成JDK动态代理
利用反射生成JDK动态代理
在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理类和动态代理对象
1.使用Proxy和InvocationHandler创建动态代理
Proxy提供了用于创建动态代理类和代理对象的静态方法,也是所有动态代理类的父亲。如果在程序中为一个或多个接口动态的生成实现类,就可以用proxy来创建动态代理类;如果需要为一或多个接口动态的创建实例,也可以使用Proxy来创建动态代理实例
Proxy提供了如下两个方法用于创建动态代理类和代理对象。
- static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces):创建一个动态代理类的所对应的Class对象,该代理类将实现interface所制定的多个接口。loader参数指定生成动态代理类的类加载器。
- static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h):直接创建一个动态代理对象。该对象的实现类实现了interfaces指定的系列接口,执行代理对象的每个方法时都会被替换执行InvocationHandler对象的invoke方法。
实际上,第一种方法生成动态代理之后,如果程序需要通过该代理类来创建对象,依然需要传入一个InvocationHandler对象。也就是说,系统生成的每个代理对象都有一个与之关联的InvocationHandler对象。
创建动态代理对象时需要实现一个或多个接口定义的方法,而InvocationHandler对象的作用是—当执行动态代理对象里的方法时,实际上会替换成调用InvocationHandler对象的invoke方法。
程序中可以采用先生成一个动态代理类,然后通过动态代理类来创建代理对象的方式生成一个动态代理对象,代码如下
package com.gdut.test0516; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; class MyInvocationHandler implements InvocationHandler{ @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
interface Foo{ } public class ProxyTest1 { public static void main(String[] args) throws Exception{
InvocationHandler handler = new MyInvocationHandler();
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(),new Class[]{Foo.class});
//获取ProxyClass中带一个InvocationHandler参数的实例
Constructor ctor = proxyClass.getConstructor(new Class[]{InvocationHandler.class});
//调用ctor的newInstance方法创建实例
Foo f = (Foo)ctor.newInstance(new Object[]{handler});
}
}
也可以简化成
package com.gdut.test0516; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; class MyInvocationHandler implements InvocationHandler{ @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
interface Foo{ } public class ProxyTest1 { public static void main(String[] args) throws Exception{
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{Foo.class},new MyInvocationHandler());
}
}
下面程序示范了使用Proxy和InvocationHandler来生成动态代理对象
package com.gdut.test0516; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; interface Person{
void walk();
void sayHello(String name);
} class MyInvocationHandler2 implements InvocationHandler{
/**
* 执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
* @param proxy 代表动态代理对象
* @param method 代表正在执行的方法
* @param args 代表调用目标方法时传入的实参
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----正在执行的方法:"+method);
if(args != null){
System.out.println("下面执行该方法时传入的实参为:");
for (Object val:args) {
System.out.println(val);
}
}else{
System.out.println("调用该方法没有实参!");
}
return null;
}
}
public class ProxyTest2 {
public static void main(String[] args) throws Exception {
InvocationHandler handler = new MyInvocationHandler();
Person p = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(),new Class[]{Person.class},new MyInvocationHandler2());
p.walk();
p.sayHello("孙悟空");
}
}

2. 动态代理和AOP
开发实际应用的软件系统时,通常会存在相同代码段重复出现的情况

我们大多数会将深色代码定义成一个方法,然后让另外三段代码段直接调用该方法即可。
但采用这种方式来实现代码复用仍存在一个重要问题,虽然代码段1,代码段2,代码段三和深色代码分开了,但是又和一个特定的方法耦合了!最理想的状态是代码块1,代码块2,代码块3能执行深色代码块部分,又无需以硬代码的方式直接调用深色代码的方法,这时可以通过动态代理达到这种效果。
由于JDK动态代理只能为接口创建代理,下面先提供一个Dog接口
interface Dog{
void info();
void run();
}
实际情况通常时,软件系统会为该接口提供一个或多个实现类,例如:GunDog
public class GunDog implements Dog{
@Override
public void info() {
System.out.println("我是一只猎狗");
}
@Override
public void run() {
System.out.println("我迅速奔跑");
}
}
此处假设info(),run()两个方法分别代表代码段1,代码段2,那么要求:程序执行info()、run()方法时能调用某个通用方法,但又不想以硬代码方式调用该方法。下面提供一个DogUtil类,该类里包含两个通用方法。
public class DogUtil {
public void method1(){
System.out.println("=====模拟第一个通用方法=====");
}
public void method2(){
System.out.println("=====模拟第一个通用方法=====");
}
}
借助动态代理,将method1(),method2()两个通用方法分别插入info(),run()方法中执行
这个程序的关键在于下面的MyInvocationHandler3类,该类是InvocationHandler实现类,该实现类的invoke()方法将会作为代理对象的方法实现
package com.gdut.test0516; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class MyInvocationHandler3 implements InvocationHandler {
private Object target;
public void setTarget(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
DogUtil du = new DogUtil();
du.method1();
Object result = method.invoke(target,args);
du.method2();
return result;
}
}
下面再提供MyProxyFactory类,该对象专为指定的target生成动态代理实例
public class MyProxyFactory {
public static Object getProxy(Object target)throws Exception{
MyInvocationHandler3 handler3 = new MyInvocationHandler3();
handler3.setTarget(target);
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler3);
}
}
上面的动态代理工厂类提供了一个getProxy()方法,该方法为target对象生成一个动态代理对象,这个动态代理对象与target实现了相同接口,所以具有相同的public方法——从这个意义上看,动态代理对象可以当成target对象使用。当程序调用动态代理对象的指定方法时,实际上将变为执行MyInvocationHandler3对象的invoke方法。
下面是测试效果

利用反射生成JDK动态代理的更多相关文章
- JavaSE---使用反射生成JDK动态代理
1.概述 1.1 在Java.lang.reflect包下,提供了Proxy类.InvocationHandler接口,使用它们可以生成JDK动态代理类或动态代理对象: 1.2 [Proxy类] 1. ...
- Java基础之反射生成JDK动态代理
在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口.通过这个类和接口可以生成JDK动态代理类或动态代理对象. JDK动态代理例子: / ...
- 静态代理和利用反射形成的动态代理(JDK动态代理)
代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...
- MyBatis之反射技术+JDK动态代理+cglib代理
一.反射 引用百度百科说明: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功 ...
- Java 反射之JDK动态代理
Proxy提供用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类.如果我们在程序中为一个或多个接口动态地生成实现类,就可以使用Proxy来创建动态代理类:如果需要为一个或多个接口动态的 ...
- MyBATIS插件原理第一篇——技术基础(反射和JDK动态代理)(转)
在介绍MyBATIS插件原理前我们需要先学习一下一些基础的知识,否则我们是很难理解MyBATIS的运行原理和插件原理的. MyBATIS最主要的是反射和动态代理技术,让我们首先先熟悉它们. 1:Jav ...
- 【Java入门提高篇】Day11 Java代理——JDK动态代理
今天来看看Java的另一种代理方式--JDK动态代理 我们之前所介绍的代理方式叫静态代理,也就是静态的生成代理对象,而动态代理则是在运行时创建代理对象.动态代理有更强大的拦截请求功能,因为可以获得类的 ...
- 利用JDK动态代理机制实现简单拦截器
利用JDK动态代理机制实现简单的多层拦截器 首先JDK动态代理是基于接口实现的,所以我们先定义一个接口 public interface Executer { public Object execut ...
- JDK动态代理[4]----ProxyGenerator生成代理类的字节码文件解析
通过前面几篇的分析,我们知道代理类是通过Proxy类的ProxyClassFactory工厂生成的,这个工厂类会去调用ProxyGenerator类的generateProxyClass()方法来生成 ...
随机推荐
- DNS服务器介绍及设置
DNS服务器是指“域名解析服务器”,而域名就是我们通常所说的“网址”.在互联网中识别和寻找不同的计算机,实际上是需要知道该计算机的IP地址才能进行访问.比如220.181.38.4,这个IP就是百度的 ...
- SpEL、PropertyPlaceholderConfigurer与@Value、#{}、${}
概念 SpEL:Spring EL表达式 PropertyPlaceholderConfigurer:即org.springframework.beans.factory.config.Propert ...
- feed流拉取,读扩散,究竟是啥?
from:https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651961214&idx=1&sn=5e80ad6f2 ...
- SpringMVC------pom.xml添加spring依赖,统一管理版本
如下: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.or ...
- VB2010新特性
1.取消了连接符(1)","之后(2)"()"前后(3)"{}"前后(4)XML(5)连接字符"&"后(6)赋值 ...
- 3D物体识别的如果检验
3D物体识别的如果验证 这次目的在于解释怎样做3D物体识别通过验证模型如果在聚类里面.在描写叙述器匹配后,这次我们将执行某个相关组算法在PCL里面为了聚类点对点相关性的集合,决定如果物体在场景里面的实 ...
- JS有趣的单线程
一.JS的执行特点 源于单线程的特性, JS在一段时间内只能执行一部分代码, 那么, 当有多块代码需要执行时, 就需要排队等候了. 二.单线程与异步事件 (1) 什么是异步事件? 异 ...
- HTML开发之(块级标签,行内标签,行内块标签)
显示模式的特性: 主要分为两大类: 块级元素:独占一行,对宽高的属性值生效:如果不给宽度,块级元素就默认为浏览器的宽度,即就是100%宽: 行内元素:可以多个标签存在一行,对宽高属性值不生效,完全靠内 ...
- 【数据分析】Superset 之一 准备
https://segmentfault.com/a/1190000005083953 http://blog.csdn.net/bingoxubin/article/details/78583165 ...
- 流媒体服务器+EasyDarwin+EasyPusher+VLC+Red5+OBS+Unity+RTSP+RTMP+FFMPEG
最近有个需求在Unity中直播桌面,着用到了视频流. ------------------------------ VLC自身有流服务器功能,但是非常慢非常慢,还是用VLC拉流吧,好像大家也是这么做的 ...