代理模式和JDK的动态代理技术学习笔记 01
一直对jdk的动态代理技术认识很模糊,花了几天时间研究它的实现原理。本文章涉及到累的加载以及java反射机制方面的知识。如果对这两方面有一定的理解
的话会更加容易明白。
代理模式:如果你学过或者知道装饰者模式,那么可以说你很容易就会掌握代理模式。
这两个模式很相似(个人的见解),都是通过传递一个需要被代理的对象(target)来
增强该类的功能。
代理模式的的本质就是传递一个目标对象(target)的引用来进行目标对象的本身具有的操作,但是同时
代理类会在执行目标对象(target)本身具有的方法之前和之后添加一些额外的操作,以达到增强目标对象
(target)功能的目的。
对于java语言来说,代理模式分为两种:1、静态代理;2、动态代理(目前主要包括JDK自身具备的动
态代理技术和cglib技术)
静态代理很好理解,下面结合代码来讲述:
先定义一个简单的接口:
代理模式:如果你学过或者知道装饰者模式,那么可以说你很容易就会掌握代理模式。
这两个模式很相似(个人的见解),都是通过传递一个需要被代理的对象(target)来
增强该类的功能。
代理模式的的本质就是传递一个目标对象(target)的引用来进行目标对象的本身具有的操作,但是同时
代理类会在执行目标对象(target)本身具有的方法之前和之后添加一些额外的操作,以达到增强目标对象
(target)功能的目的。
对于java语言来说,代理模式分为两种:1、静态代理;2、动态代理(目前主要包括JDK自身具备的动
态代理技术和cglib技术)
静态代理很好理解,下面结合代码来讲述:
先定义一个简单的接口:
package test.proxy;
public interface BookFacade {
//添加书本的方法
void addBook();
}
然后就是这个接口的实现类:
package test.proxy;
public class BookFacadeImpl implements BookFacade{
@Override
public void addBook() {
System.out.println("添加书本");
}
}
然后就是这个接口某个实现类的代理类:
package test.proxy;
public class BookFacadeProxy {
//目标类的一个引用
private BookFacade target;
public BookFacadeProxy(BookFacade target){
this.target=target;
}
public void addBook(){
System.out.println("==========添加操作之前=========");
this.target.add();
System.out.println("==========添加操作之后=========");
}
}
然后就是测试了:
<pre name="code" class="java"><span style="font-size:18px;"> package test.proxy;
public class Main{
BookFacade target=new BookFacadeImpl();
BookFacadeProxy proxy=new BookFacadeProxy(target);
proxy.addBook();
}
}</span>
执行测试之后的结果是:
==========添加操作之前=========
添加操作
==========添加操作之后=========
好了,这就是静态代理的一个基本应用。
接下来就是讲JDK的动态代理技术了。
动态代理技术主要是利用java.lang.reflect这个包的InvocationHandler接口和Proxy这两个类
先通过一个例子来演示动态代理的用法和效果
先定义一个接口:
动态代理技术主要是利用java.lang.reflect这个包的InvocationHandler接口和Proxy这两个类
先通过一个例子来演示动态代理的用法和效果
先定义一个接口:
package dynamic.proxy;
/**
* 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口
* @author zyb
* @since 2012-8-9
*
*/
public interface UserService {
/**
* 目标方法
*/
public abstract void add();
}
然后就是实现类:
package dynamic.proxy;
/**
* 目标对象
* @author zyb
* @since 2012-8-9
*
*/
public class UserServiceImpl implements UserService {
/* (non-Javadoc)
* @see dynamic.proxy.UserService#add()
*/
public void add() {
System.out.println("--------------------add---------------");
}
}
接下来就是定义一个代理类:
package dynamic.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyProxy implements InvocationHandler{
//目标对象的引用
private UserService target;
//构造方法传进一个UserService的实现类引用
public MyProxy(UserService target){
this.target=target;
}
//取得代理对象
public Object getMyProxy(){
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),
this.target.getClass().getInterfaces(),this);
}
@Override
/*
proxy:代理类对象
method:就是在这个参数所表示的方法的位置增强,和AOP思想中的横切点很相似(个人理解),
通过反射执行这个方法
args:method执行所需要的参数。
*/
public Object invoke(Object proxy,Method method,Object[] args) throws Exception{
//用于封装返回结果
Object result;
System.out.println("======执行add方法之前============");
result = method.invoke(target,args);
System.out.println("======执行add方法之后============");
return result;
}
}
然后就是测试了:
package dynamic.proxy;
public class Main{
public static void main(String[] args) throws Exception{
//先声明一个目标对象
UserService target=new UserServiceImpl();
//取得代理对象
UserService proxy = (UserService)new MyProxy(target).getMyProxy();
//使用代理对象执行添加操作
proxy.add();
}
}
输出结果如下:
======执行add方法之前============
--------------------add---------------
======执行add方法之后============
好了,通过上面的例子可以知道动态代理对目标对象的add方法进行了增强操作。
但是从上面的例子也可以看出动态代理的局限性:需要和一个接口绑定在一起,只能针对
一类接口增强
其实可以将这个例子理解为一个简单的AOP实现。
值得注意的是proxy并没有显示的执行MyProxy类的invoke()方法。但是达到了增强操作。
了解下它背后进行的操作有助于我们更加好的动态代理技术,更好的运用它。
现在通过代码来探究这个过程:
将测试类Main改变下:
但是从上面的例子也可以看出动态代理的局限性:需要和一个接口绑定在一起,只能针对
一类接口增强
其实可以将这个例子理解为一个简单的AOP实现。
值得注意的是proxy并没有显示的执行MyProxy类的invoke()方法。但是达到了增强操作。
了解下它背后进行的操作有助于我们更加好的动态代理技术,更好的运用它。
现在通过代码来探究这个过程:
将测试类Main改变下:
package dynamic.proxy;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main{
public static void main(String[] args) throws Exception{
//制定被代理的对象
UserService target=new UserServiceImpl();
//取得代理对象
UserService proxy=(UserService) new MyProxy(target).getMyProxy();
//根据这里可以判断proxy是Proxy的子类,同时实现了UserService接口
System.out.println(proxy instanceof Proxy);
System.out.println(proxy instanceof UserService);
System.out.println("==================================");
//这里打印出这样的结果:proxy的类型是: class com.sun.proxy.$Proxy0
System.out.println("proxy的类型是: "+proxy.getClass().toString());
System.out.println("===================================");
//这里通过反射技术取得proxy这个对象的信息来分析下proxy的结构
Class clazz=proxy.getClass();
//属性
Field[] fields=clazz.getDeclaredFields();
System.out.println("proxy对象的属性有:");
for(Field f:fields){
System.out.println(f.getName()+" , ");
}
System.out.println("==================================");
//方法
Method[] method=clazz.getMethods();
System.out.println("proxy对象的方法有: ");
for(Method m:method){
System.out.println(m.getName()+" , ");
}
System.out.println("===================================");
//父类
System.out.println("proxy的父类: "+clazz.getSuperclass());
System.out.println("====================================");
//接口
Class<?> interfaces[]=clazz.getInterfaces();
System.out.println("proxy实现的接口有: ");
for(Class<?> i:interfaces){
System.out.println(i.getName()+" , ");
}
System.out.println("====================================");
//运行结果
System.out.println("运行结果: ");
proxy.add();
}
}
接下来是控制台输出的结果:
true
true
==================================
proxy的类型是: class com.sun.proxy.$Proxy0
===================================
proxy对象的属性有:
m1 ,
m3 ,
m0 ,
m2 ,
==================================
proxy对象的方法有:
add ,
equals ,
toString ,
hashCode ,
isProxyClass ,
getInvocationHandler ,
getProxyClass ,
newProxyInstance ,
wait ,
wait ,
wait ,
getClass ,
notify ,
notifyAll ,
===================================
proxy的父类: class java.lang.reflect.Proxy
====================================
proxy实现的接口有:
dynamic.proxy.UserService ,
====================================
运行结果:
======执行add方法之前============
--------------------add---------------
======执行add方法之后============
true
true
==================================
proxy的类型是: class com.sun.proxy.$Proxy0
===================================
proxy对象的属性有:
m1 ,
m3 ,
m0 ,
m2 ,
==================================
proxy对象的方法有:
add ,
equals ,
toString ,
hashCode ,
isProxyClass ,
getInvocationHandler ,
getProxyClass ,
newProxyInstance ,
wait ,
wait ,
wait ,
getClass ,
notify ,
notifyAll ,
===================================
proxy的父类: class java.lang.reflect.Proxy
====================================
proxy实现的接口有:
dynamic.proxy.UserService ,
====================================
运行结果:
======执行add方法之前============
--------------------add---------------
======执行add方法之后============
从上面的输出结果我们可以得出下面的结论:
1、proxy这个对象所对应的那个类的定义如下:
public class $Proxy0 extends Proxy implements Uservice{
//...............
}
2、$Proxy0这个类并没有保存在我们的磁盘中。这个类是java虚拟机在执行代码
期间根据需求动态创建出来的。java虚拟机创建$Proxy0这个类是直接生成字
节码文件并且执行$Proxy0的对象proxy的相关方法来“隐式”执行了“增强操作”。
1、proxy这个对象所对应的那个类的定义如下:
public class $Proxy0 extends Proxy implements Uservice{
//...............
}
2、$Proxy0这个类并没有保存在我们的磁盘中。这个类是java虚拟机在执行代码
期间根据需求动态创建出来的。java虚拟机创建$Proxy0这个类是直接生成字
节码文件并且执行$Proxy0的对象proxy的相关方法来“隐式”执行了“增强操作”。
分析到这里,可能还是会对动态代理的“隐式”执行操作是怎样进行的理解的不够清楚。
接下来的第二篇来通过分析Proxy这个类和$Proxy0这个类的大概的源码来进一步讲解。
接下来的第二篇来通过分析Proxy这个类和$Proxy0这个类的大概的源码来进一步讲解。
从更底层来理解jdk动态代理技术的实现。