为其他对象提供一种代理以控制对这个对象的访问。
代理对象起到中介作用,可去掉功能服务或增加额外的服务。
远程代理:为不同地理的对象提供局域网代表对象。eg.分店和总店的管理
虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建。eg.浏览网站时图片加载
保护代理:控制对一个对象的访问的权限。eg.网站各用户的权限
智能引用代理:提供对目标对象额外的服。eg.火车站和其代售点
静态代理:继承方式,聚合方式
动态代理:JDK动态代理,CGLIB动态代理
静态代理:代理和被代理对象在代理之前是确定的。他们都实现相同的接口或者继承相同的抽象类。
eg:模拟汽车行驶
普通方式实现汽车行驶
public interface MoveAble {
public void move();
}
public class Car implements MoveAble{
@Override
public void move() {
System.out.println("汽车开始行驶...");
long starttime=System.currentTimeMillis();
try {
System.out.println("汽车行驶中...");
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long endtime=System.currentTimeMillis();
System.out.println("汽车结束行驶... 行驶时间: "+(endtime-starttime)+" 毫秒");
}
}
@Test
public void TestCarMove(){
Car car=new Car();
car.move();
}
结果:
汽车开始行驶...
汽车行驶中...
汽车结束行驶... 行驶时间: 5 毫秒
下面将通过继承和聚合两种方式来实现静态代理
更改Car类,去除时间管理
public class Car implements MoveAble{
@Override
public void move() {
try {
System.out.println("汽车行驶中...");
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
通过继承方式来实现静态代理
public class Car2 extends Car {
@Override
public void move() {
System.out.println("汽车开始行驶...");
long starttime = System.currentTimeMillis();
super.move();
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶... 行驶时间: " + (endtime - starttime) + " 毫秒");
}
}
@Test
public void TestCarMove2(){
MoveAble ma=new Car2();
ma.move();
}
结果:
汽车开始行驶...
汽车行驶中...
汽车结束行驶... 行驶时间: 34 毫秒
使用聚合的方式来实现静态代理
public class Car3 implements MoveAble {
private Car car;
public Car3(Car car) {
super();
this.car = car;
}
@Override
public void move() {
// TODO Auto-generated method stub
System.out.println("汽车开始行驶...");
long starttime = System.currentTimeMillis();
car.move();
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶... 行驶时间: " + (endtime - starttime) + " 毫秒");
}
}
@Test
public void TestCarMove3(){
Car c=new Car();
MoveAble ma=new Car3(c);
ma.move();
}
结果:
汽车开始行驶...
汽车行驶中...
汽车结束行驶... 行驶时间: 564 毫秒
聚合比继承更适合代理,进行功能叠加更方便
eg:汽车形式增加时间管理和日志管理
public class CarTimeProxy implements MoveAble{
private MoveAble ma;
public CarTimeProxy(MoveAble ma) {
super();
this.ma = ma;
}
@Override
public void move() {
System.out.println("汽车开始行驶...");
long starttime = System.currentTimeMillis();
ma.move();
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶... 行驶时间: " + (endtime - starttime) + " 毫秒");
}
}
public class CarLogProxy implements MoveAble{
private MoveAble ma;
public CarLogProxy(MoveAble ma) {
super();
this.ma = ma;
}
@Override
public void move() {
System.out.println("日志开始...");
ma.move();
System.out.println("日志结束...");
}
}
@Test
public void TestCarMove4(){
Car car=new Car();
CarTimeProxy ctp=new CarTimeProxy(car);
CarLogProxy clp=new CarLogProxy(ctp);
clp.move();
}
结果:也可更改组合顺序,先进行日志管理再进行时间管理
日志开始...
汽车开始行驶...
汽车行驶中...
汽车结束行驶... 行驶时间: 991 毫秒
日志结束...
动态代理
JDK动态代理:只能对实现了接口的类实现代理,没有接口就不能实现JDK动态代理
1. 目的:动态产生代理,实现对不同类、不同方法的代理
2. 运行时生成的class,该class需要实现一组interface,产生的代理类并不能做什么事情,必须实现InvocationHandler接口来接管实际的工作。想实现的功能是在handler中去实现的
3. 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):返回代理类的一个实例,返回后的代理类可以被当作代理类使用,可使用被代理类的在接口中声明过的方法。第一个参数loader为被代理类的加载器,通过被代理类.getClass().getClassLoader()得到、第二个参数interfaces为被代理类实现的所有接口,同样通过getClass().getInterfaces()得到、 第三个参数handler就是自己实现的InvocationHandler的实现类的对象
4.动态代理实现:
(1)声明一个代理h实现InvocationHandler接口,通过构造方法接受被代理类,并实现invoke方法,添加业务逻辑(实现原有功能并添加额外功能)
(2)在测试类中,通过共同实现接口的实例获得代理对象,并实现方法,如Interface1 i = (Interface1)Proxy.newProxyInstance(classLoader,classInterfaces,h);
(3)通过动态代理对象i,代用其方法i.fun();
eg:
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) throws Throwable {
// TODO Auto-generated method stub
System.out.println("汽车开始行驶...");
long starttime = System.currentTimeMillis();
method.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶... 行驶时间: " + (endtime - starttime) + " 毫秒");
return null;
}
}
@Test
public void TestCarMove(){
Car car=new Car();
TimeHandler handler=new TimeHandler(car);
Class<?> c=car.getClass();
/**
* loader 类加载器
* interfaces 实现接口
* h InvocationHandler
*/
MoveAble ma=(MoveAble)Proxy.newProxyInstance(c.getClassLoader(), c.getInterfaces(), handler);
ma.move();
}
结果:
汽车开始行驶...
汽车行驶中...
汽车结束行驶... 行驶时间: 785 毫秒
在原有基础上增加日志管理
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("汽车开始行驶...");
long starttime = System.currentTimeMillis();
method.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶... 行驶时间: " + (endtime - starttime) + " 毫秒");
return null;
}
}
@Test
public void TestCarMove2(){
Car car=new Car();
LogHandler log=new LogHandler(car);
Class<?> cls=car.getClass();
MoveAble logma=(MoveAble)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), log);
TimeHandler time=new TimeHandler(logma);
Class<?> logcls=logma.getClass();
MoveAble timema=(MoveAble)Proxy.newProxyInstance(logcls.getClassLoader(), logcls.getInterfaces(), time);
timema.move();
}
结果:
汽车开始行驶...
日志开始...
汽车行驶中...
日志结束...
汽车结束行驶... 行驶时间: 164 毫秒
Cglib代理:针对类来实现代理的,针对飙指定目标类产生一个子类,通过方法拦截技术拦截所有的父类方法的调用。
1. cblib是通过继承实现,所以final修饰的类不能被代理
2. CglibProxy要实现MethodInterceptor
eg:
public class Train {
public void move(){
System.out.println("火车行驶中...");
}
}
public class TimeCglib implements MethodInterceptor{
private Object target;
//两种构造方式,其intercept方法中对应不同的invoke方法
public Object getProxy(Class<?> cls){
//设置创建子类的类
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(this);
return enhancer.create();
}
public Object getProxy(Object target){
this.target=target;
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 拦截所有目标类方法的调用
* object 目标类的实例
* method 目标方法的反射对象
* objects 方法的参数
* methodProxy 代理类的实例
*/
@Override
public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("火车开始行驶...");
long starttime = System.currentTimeMillis();
//两种方式
//代理类调用父类的方法
methodProxy.invokeSuper(object, objects);
//目标对象调用其方法,需要传入目标对象target
// method.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("火车结束行驶... 行驶时间: " + (endtime - starttime) + " 毫秒");
return null;
}
}
@Test
public void TestTrainMove(){
TimeCglib time=new TimeCglib();
Train train=(Train)time.getProxy(Train.class);//传入的参数是类
train.move();
}
@Test
public void TestTrainMove2(){
Train train=new Train();
TimeCglib time=new TimeCglib();
Train t=(Train)time.getProxy(train);//传入的参数是对象
t.move();
}
结果:
火车开始行驶...
火车行驶中...
火车结束行驶... 行驶时间: 0 毫秒