动态代理实现思路
实现功能;通过Proxy的newProxyInstance返回代理对象
1.声明一段源码(动态产生代理)
2.编译源码(JDK Compiler API),产生新的类(代理类)
3.将这个类load到内存当中,产生一个新的对象(代理对象)
4.return 代理对象
设计模式——代理模式(具备面向对象的设计思维、了解多态、反射机制)
一、基本概念及分类
1、定义:为其他对象提供一种代理以控制对这个对象的访问(购买火车票去代售网点、找代理),代理对象起到中介作用,可去掉功能服务或增加额外服务。
2、常见的代理模式
(1)远程代理:为不同地理的对象提供局域网代表对象(客户端、服务器等)
例如:连锁店查看门店经营情况(通过远程代理可以监控各个店铺,使之能直观地了解店内信息)
(2)虚拟代理:格局需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建
例如:浏览网页中的图片时以默认图片显示,当图片加载完成后再查看
(3)智能引用代理:提供给目标对象一些额外的服务
例如:火车票代售处、日志处理、权限管理、事务处理...
(4)保护代理:控制对一个对象的访问权限
例如:浏览网页时,普通用户只有浏览权限,当用户注册登录后,才可以进行发帖、删除、评论等操作
二、开发中的应用场景
三、实现方式(以智能引用代理为例)
1、静态代理:代理和被代理对象在代理之前是确定的,它们都实现相同的接口或者继承相同的抽象类。
实现例子:车辆在公路上行驶,通过代理实现车辆行驶的方法,增加一个记录车辆行驶的方法
不使用代理正常实现:
public interface Moveable{
void move();
}
public class Car implements Moveable{
@Override
public void move(){
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶...");
//实现开车
try{
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中...");
}catch(InterruptedException e){
e.printStackTrace();
}
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
}
}
public class Client{
public static void main(String[] args){
Car car = new Car();
car.move();
}
}(1)通过继承的方式实现:
public interface Moveable{
void move();
}
public class Car implements Moveable{
@Override
public void move(){
//实现开车
try{
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中...");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public calss Car2 extends Car{
@Override
public void move(){
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶...");
super.move();
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
}
}
public class Client{
public static void main(String[] args){
Moveable m = new Car2();
m.move();
}
}(2)通过聚合(一个类当中调用另一个对象)的方式实现:
public interface Moveable{
void move();
}
public class Car implements Moveable{
@Override
public void move(){
//实现开车
try{
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中...");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public calss Car3 implements Moveable{
private Car car;
public Car3(Car car){
super();
this.car = car;
}
@Override
public void move(){
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶...");
car.move();
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
}
}
public class Client{
public static void main(String[] args){
Car car = new Car();
Moveable m = new Car3(car);
m.move();
}
}
思考:通过继承和聚合两种方式都能实现静态代理,但究竟哪种方式更好呢?
以上是在实现对象方法move()的外层添加方法运行时间处理功能,想要增加权限管理、增加日志处理实现功能的叠加,通过两种方式示例:
(1)通过继承方式实现(代理类会无限膨胀下去)
先记录日志,再记录时间:需要先创建类Car4继承Car2或者Car,在move()方法前后先记录日志,再记录时间;
先记录时间,再记录日志:需要先创建类Car5继承Car2或者Car,在move()方法前后先记录时间,再记录日志;
先处理权限,再记录日志,再记录时间:需要先创建类Car6继承Car2或者Car,先处理权限,再记录日志,再记录时间;
先处理权限,再记录时间,再记录日志:需要先创建类Car7继承Car2或者Car,先处理权限,再记录时间,再记录日志;
(2)通过聚合方式实现 (代理类实现相同的接口,且代理之间相互传递、组合)
public interface Moveable{
void move();
}
public class Car implements Moveable{
@Override
public void move(){
//实现开车
try{
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中...");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public calss CarTimeProxy implements Moveable{
private Moveable m;
public CarTimeProxy (Moveable m){
super();
this.m = m;
}
@Override
public void move(){
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶...");
m.move();
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
}
}
public calss CarLogProxy implements Moveable{
private Moveable m;
public CarLogProxy (Moveable m){
super();
this.m = m;
}
@Override
public void move(){
System.out.println("日志开始...");
m.move();
System.out.println("日志结束...");
}
}
public class Client{
public static void main(String[] args){
Car car = new Car();
//先记录日志,再记录时间
CarTimeProxy ctp = new CarTimeProxy (car);
CarLogProxy clp = new CarLogProxy (ctp);
clp.move();
//先记录时间,再记录日志
CarLogProxy clp = new CarLogProxy (car);
CarTimeProxy ctp = new CarTimeProxy (car);
ctp .move();
}
} 思考:不同的类(Car,Train)实现相同的代理(TimeProxy,LogProxy)怎样实现(如果用静态代理的聚合方式实现,每增加一个类就要新创建新类的TimeProxy,LogProxy代理类,造成类膨胀)?
有没有一种方法:能够动态产生代理,实现对不同类、不同方法的代理——动态代理
2、动态代理(在代理类与被代理类之间加入了实现InvocationHandler【事务处理器】类)
(一)JDK动态代理
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
(1)Interface Invocationhandler:该接口中仅定义了一个方法
public Object invoke(Object obj,Method method, Object[] args)
在实际使用中,参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。
(2)Proxy:该类即为动态代理类
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) :返回代理类的一个实例,返回后的代理类可以当做被代理类使用(可使用被代理类的在接口中声明过的方法)
JDK动态代理代码实现:
public interface Moveable{
void move();
}
public class Car implements Moveable{
@Override
public void move(){
//实现开车
try{
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中...");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public class TimeHandler implements InvocationHandler{
private Object target;
public TimeHandler(Object target){
super();
this.target = target;
}
/*
*参数:
*proxy:被代理的对象
*method:被代理对象的方法
*args:方法的参数
*返回值:
*Object:方法的返回值
*/
@Override
public Object invoke(Object proxy,Method method,Object[] args) throw Throwable{
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶...");
method.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
}
}
//JDK动态代理测试
public class Test{
public static void main(String[] args){
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class<?> cls = car.getClass();
/*
*参数:
*loader:类加载器
*interfaces:实现接口
*h:实现处理器InvocationHandler
*/
Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h);
m.move();
}
}所谓动态代理是在运行时生成的class,该class需要实现一组interface,使用动态代理类时,必须事先InvocationHandler接口。
JDK动态代理实现步骤:
1、创建一个实现皆苦InvocationHandler的类,它必须事先invoke()方法;
2、创建被代理的类及接口;
3、调用Proxy类的静态方法,创建一个代理类;
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
4、通过代理调用方法。
实现作业:实现Car类的多个动态代理类(记录日志、时间)
实现作业:实现Car类的多个动态代理类(记录日志、时间)
(二)CGLIB动态代理
JDK动态代理与CGLIB动态代理的区别:
JDK动态代理:
1、只能代理实现了接口的类;
2、没有实现接口的类不能实现JDK的动态代理。
CGLIB动态代理:
1、针对类来实现代理的;
2、对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用。
CGLIB动态代理实现代码示例(导包:cglib-nodep-2.2.jar):
public class Train{
public void move(){
System.out.println("火车行驶中......")
}
}
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//设置创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/*拦截所有目标类方法的调用
*参数:
*obj:目标类的实例
*m:目标方法的反射对象
*args:方法的参数
*proxy:代理类的实例
*/
@Override
public Object intercept(Object obj, Method m, Object[] args,MethodProxy proxy) throw Throwable{
System.out.println("日志开始...");
//代理类调用父类的方法
proxy.invoke(obj,args);
System.out.println("日志结束...");
return null;
}
}
public class Test{
public static void main(String[] args){
CglibProxy proxy = new CglibProxy();
Train t = proxy.getProxy(Train.class);
t.move();
}
}四、理解JDK动态代理的实现
动态代理实现思路(实现功能:通过Proxy的newProxyInstance返回代理对象)
1、声明一段源码(动态产生代理)
2、编译源码(JDKCompiler API),产生新的类(代理类)
3、将这个类load到内存当中,产生一个新的对象(代理对象)
4、return代理对象
代码实现:
public class Proxy{
public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{
String rt = "\r\t";
String methodStr = "";
for(Method m : infce.getMethods()){
methodStr +="@Override" + rt +
"public void "+m.getName()+"(){" + rt +
/*
"long starttime = System.currentTimeMillis();" + rt +
"System.out.println("汽车开始行驶...");" + rt +
"m."+m.getName()+"();" + rt +
"long endtime = System.currentTimeMillis();" + rt +
"System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");" + rt +
*/
"try{" + rt +
"Method md =" + infce.getName() +".class.getMethod(\""+m.getName()+"\");" + rt +
"h.invoke(this,md);" + rt +
"}catch(Exceotipn e){" + rt +
"e.printStackTrace();" + rt +
"}" + rt +
"}";
}
String str =
"public calss $Proxy0 implements" + infce.getName()+ "{" + rt +
"public $Proxy0 (InvocationHandler h){" + rt +
"super();" + rt +
"this.h = h;" + rt +
"}" + rt +
" private InvocationHandler h;" + rt +
methodStr + rt +
"}";
//String filename = System.getProperty("user.dir");
//System.out.println(filename);//C:/Proxy
//产生代理类的Java文件
String filename = System.getProperty("user.dir")+"/bin/com/imooc/proxy/$Proxy0.java";
File file = new File(filename);
//FileUtils(commons-io的jar包下的类)
FileUtils.writeStringToFile(file,str);
//编译
//拿到编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//文件管理者
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,null,null);
//获取文件
Iterable units = fileMgr.getJavaFileObjects(filename);
//编译任务
CompilationTask t = compiler.getTask(null,fileMgr,null,null,null,units);
//进行编译
t.call();
fileMgr.close();
//load到内存
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c = cl.loadClass("$Proxy0");
Constructor ctr = c.getConstructor(InvocationHandler.class);
System.out.println(c.getName());//$Proxy0
return ctr.newInstance(h);
}
}
/*测试类*/
public class Client{
public static void main(String[] args) throws Exception{
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class,h);
m.move();
}
}
public class Test{
public static void main(String[] args){
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class<?> cls = car.getClass();
/*
*参数:
*loader:类加载器
*interfaces:实现接口
*h:实现处理器InvocationHandler
*/
Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h);
System.out.println("代理类名字" + m.getClass().getName());//代理类名字$Proxy0
m.move();
}
}public class InvocationHandler{
public void invoke(Object o,Method m);
}
public class TimeHandler implements InvocationHandler{
private O bject target;
public TimeHandler(Object target){
this.target = target;
}
@Override
public void invoke(Object o,Method m){
try{
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶...");
m.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
}catch(Exception e){
e.printStackTrace();
}
}
}五、总结
2222222222222222222222222222
11111111111111111111111111111111
22222222222222222222222222222222
555555555555555555555555555
333333333333333333333333333333333
3333333333333333333333333333333333
222222222222222222222222222222222222222
实现静态代理的两种方式
静态代理的概念
智能引用代理的两种实现方式
常见代理模式
智能引用代理
保护代理应用
虚拟代理例子
虚拟代理概念
例 子 例 子
远 程 代 理
常用代理模式
代理模式基本概念
代理模式定义
JDK动态代理:
proxy.newProxcyInstance(class.getlClassLoder(),class.getinterface(),h);
他是在运行生成的class
该class需要实现一组interface
使用动态代理类时,必须实现InvaocationHandler接口
实现invocationHandler接口
invoke(Object proxy,Method method,Object[] args)
proxy:被代理对象
method:被代理对象的方法
args:方法的参数
ppt上关于proxy的注释写错了,写成了代理类。
动态代理实现思路 实现功能;通过Proxy的newProxyInstance返回代理对象 1.声明一段源码(动态产生代理) 2.编译源码(JDK Compiler API),产生新的类(代理类) 3.将这个类load到内存当中,产生一个新的对象(代理对象) 4.return 代理对象
测试 cglib
返回代理类
cglib动态代理实现
proxy.invokeSuper(obj,args)
cglib vs jdk
JDK动态代理机制:只能代理实现某些接口的类,如果没有实现接口的类则不能使用JDK动态代理。
cglib动态代理机制:针对类产生代理,原理就是为指定的目标类产生一个子类,子类通过方法拦截技术(覆盖父类的方法来实现功能的增强)拦截所有父类方法的调用(因为该种方式是使用继承方式,所以不能对final修饰的类进行代理)。