基本概念:
代理模式定义:为其他对象提供一种代理以控制对这个对象的访问
(代理对象起到中介作用,可去掉功能服务或者增加额外的服务)
常见的几种代理模式:
- 远程代理:为不同地理的对象提供局域网代表对象 ( 客户端服务器模式 )
- 虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建
- 保护代理:控制用户的访问权限
- 智能引用代理:提供对目标对象额外的服务
实现方式
- 静态代理:代理和被代理对象在代理之前是确定的,它们的实现相同的接口或者继承相同的抽象类
(1) 代理对象和目标对象都要实现 公共接口
(2) 代理对象持有目标对象引用,重写构造方法
(3) 实现共同的方法,代理对象增强行为
(4) 代理角色固定,一次只能代理一个对象
两种实现:继承方式、聚合方式
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 Car2 extends Car{
//Car2 直接调用父类的move() 方法 即:Car2 对 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 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 CarTimeProxy implements Moveable{
public CarTimeProxy(Moveable m){
super();
this.m = m;
}
private Moveable m;
@Override
public void move(){
long startTime = System.currentTimeMillis();
System.out.println("汽车开始行驶------");
m.move();
long endTime = System.currentTimeMillis(); //汽车行驶的终止时间
System.out.println("汽车结束行驶------汽车行驶时间:" + (endTime - startTime)+"毫秒");
}
}
汽车日志代理
public class CarLogProxy implements Moveable{
public CarLogProxy (Moveable m){
super();
this.m = m;
}
private Moveable m;
@Override
public void move(){
System.out.println("日志开始------");
m.move();
System.out.println("日志结束------);
}
}
测试类
public class test{
public void main(String[] args){
test 1
Car car = new Car();
car.move();
test 2
Moveable m = new Car2();
m.move();
test 3
Car car = new Car();
Moveable m = new Car3(car);
m.move();
test 4
Car car = new Car();
//实现功能的叠加
CarTimeProxy ctp = new CarTimeProxy(car);
CarLogProxy clp = new CarLogProxy(ctp);
clp.move();
}
}
- 动态代理:根据需要通过反射机制在程序运行期动态的为目标对象创建代理对象,代理的行为可以代理多个方法,即满足生产需要的同时又达到代码的通用目的
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方式和CGLIB方式
(1) JDK动态代理:
优点:生成动态代理对象的速度快,适合频繁创建代理对象的程序
缺点:执行速度慢,且不能为未实现接口的类创建代理
- 目标对象要有接口,且最后创建的代理对象要转换成此接口类型,来调用方法
- 动态代理类实现InvocationHandler接口,持有目标对象引用,利用构造器动态传入目标对象
- 使用proxy.newProxyInstance()来动态地创建代理对象
- 代理对象重写invoke方法,利用反射调用目标对象的方法,同时增加行为
事务处理器
public class TimeHandler implements InvocationHandler{
private Object target;
private TimeHandler (Object target){
super();
this.target = target;
}
/*
* 加入具体逻辑
*参数:
* proxy 被代理的对象
* method 被代理对象的方法
* args 方法的参数
* return Object 方法的返回值
*/
@Override
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("汽车开始行驶------");
method.invoke(target)
long endTime = System.currentTimeMillis(); //汽车行驶的终止时间
System.out.println("汽车结束行驶------汽车行驶时间:" + (endTime - startTime)+"毫秒");
return null;
}
}
JDK动态代理测试类
public class test{
public void main(String[] args){
Car car = new Car();
Class<?> cls = car.getClass();
InvocationHandler h = new TimeHandler(car);
/**
* 生成动态代理类
* loader: 被代理类的类加载器
* interfaces: 实现接口
* h InvocationHandler
*/
Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h );//创建一个代理类
m.move();
}
}
模拟JDK动态代理实现
JDK动态代理实现思路:
实现功能:通过Proxy的newProxyInstance方法返回代理对象
1.声明一段源码 (动态生成代理类)
2.编译源码 (JDK Compiler API),产生新的类(代理类)
3.将这个类load到内存当中,产生一个新的对象(代理对象)
4.return 代理对象
public class Proxy{
public static Object newProxyInstance(Class interface,InvocationHandler h) throws Exception{
String rt = "\r\n";
String methodStr = "";
for(Method m:interface.getMethods()){
methodStr + = "@Override"+rt+
"public void "+ m.getName() +"(){"+rt+
"try{"+rt+
"Method md = "+interface.getName()+".class.getMethod(\""+m.getName()+"\");"+rt+
"h.invoke(this,md);"+rt+
"}catch(Exception e){ e.printStackTrace();}"+rt+
"}";
}
String str =
"package com.demo.proxy;"+rt+
"import package com.demo.proxy.InvocationHandler;"+rt+
"import java.lang.reflect;"+rt+
"public class $Proxy0 implements"+interface.getName()+ "{"+rt+
"public $Proxy0(InvocationHandler h){"+rt+
"this.h = h;"+rt+
"}"+rt+
"private InvocationHandler h;"+rt+
methodStr+rt+
"}";
//产生代理类的JAVA文件
String filename =System.getProperty("user.dir") +"/bin/com.demo/proxy/$Proxy.java";//当前所在路径
File file = new File(filename);
//引入jar commoms-io
FileUtils.writeStringToFile(file,str);
//编译
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//获得当前系统的编译器
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null); //创建文件的管理者
Interable units = fileManager.getJavaFileObjects(filename);//获取文件
CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);//编译任务
t.call();//进行编译
fileManager.close();
//编译好的文件load到内存中
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c = cl.loadClass("com.demo.proxy.$Proxy0");
Constructor ctr = c.getConstructor(InvocationHandler.class); //构造器
return ctr.newInstance(h);
}
}
创建事务处理器
public interface InvocationHandler{
public void invoke(Object obj,Method m);
}
public class TimeHandler implements InvocationHandler{
private Object target;
public TimeHandler (Object target){
super();
this.target = target;
}
@Override
public void invoke(Object obj,Method m){
try{
long startTime = System.currentTimeMillis();"+rt+
System.out.println("汽车开始行驶------");
m.invoke(target);
long endTime = System.currentTimeMillis(); //汽车行驶的终止时间
System.out.println("汽车结束行驶------汽车行驶时间:" + (endTime - startTime)+"毫秒");
}catch(Exception e){
e.printStackTrace();
}
}
}
public class Test{
public static void main(String[] args) throws Exception{
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Moveable m = (Moveable)Proxy.new ProxyInstance(Moveable.class,h);
m.move()
}
}
(2)CGLIB动态代理:以继承来实现,主要解决没有接口类的代理实现
(对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用)
优点:执行速度快,且能够为未实现接口的类创建代理
缺点:不能代理final修饰的方法,且生成代理对象的速度慢,不适合频繁创建代理对象的程序
- 目标对象无要求,实现MethodInterceptor接口,最后创建的动态代理会转换成此目标对象类型
- 重写intercept方法,实现行为增强
public class Train(){
public void move(){
System.out.println("火车行驶中--------");
}
}
public class CglibInterceptor implements MethodInterceptor(){
//第一种写法,引入目标对象利用构造器动态传入目标对象
private Object target; //目标对象
public CglibInterceptor (Object target){
this.target=target;
}
//动态创建代理对象
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
//第二种写法 引入目标的class对象
private Enhancer enhance = new Enhancer();
//创建代理类
public Object getProxy(Class clazz){
//设置创建子类的类
enhance.setSuperclass(clazz);
enhance.setCallback(this);
return enhance.create();//创建子类的实例
}
/**
* 拦截所有目标类方法的调用
* obj 目标类的实例
* m 目标类的反射对象
* args 方法的参数
* proxy 代理类的实例
*/
@Override
public Object intercept(Object obj,Method m,Object[] args,MethodProxy proxy) thorws Throwable{
System.out.println("日志开始--------");
//代理类调用父类的方法
proxy.invokeSuper(obj,args);
System.out.println("日志结束--------");
return null;
}
}
CGLIB动态代理测试类
public void main(String[] args){
//第一种写法 引入目标对象
CglibInterceptor cglibi= new CglibInterceptor (new Train());
//创建代理,且需要转换成目标对象类型
Train t = (Train) cglibi.getProxy();
//第二种写法 引入目标的class对象
CglibInterceptor cglibi= new CglibInterceptor ();
Train t = (Train) cglibi.getProxy(Train .class);
//代理对象调用方法,行为会得到增强
t.move();
}