一:代理模式
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
二:应用场景
如果需要在已有代码的基础上扩展功能,比如日志记录,性能统计,事务管理,直接在现有代码中添加代码, 会导致职责不够单一, 代码复用性不好,不方便后期维护,此时需要考虑采用代理模式
三:jdk静态代理(继承的方式)
- 核心作用:
通过代理,控制对对象的访问可以在调用目标标方法之前做一些其他的事情,增强目标类的业务方法。
- 原则:
- 代理类和委托类实现同一个接口,并且代理类继承自委托类
- 代理类增强委托类的行为
- 缺点:
代理类和委托类都实现同一接口,如果增加接口方法,委托类和代理礼物i都要维护
- 创建一个接口及委托类
public interface Moveable {
void move();
}
public class Car implements Moveable{
@Override
public void move() {
try {
System.out.println("汽车在移动中...");
Thread.sleep(new Random().nextInt(2000));
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.继承的方式创建一个代理类,增加日志的功能
public class CarTimeProxy extends Car{
@Override
public void move() {
//记录一个开始时间
long startTime=System.currentTimeMillis();
System.out.println("汽车开始移动...");
super.move();
//记录一个结束时间
long endTime=System.currentTimeMillis();
System.out.println("结束移动,总耗时:"+(endTime-startTime)+"毫秒!");
}
}
四:jdk静态代理(实现的方式)
- 创建一个接口
public interface Moveable {
void move();
}
- 创建实现该接口的委托类
public class Car implements Moveable{
@Override
public void move() {
try {
System.out.println("汽车在移动中...");
Thread.sleep(new Random().nextInt(2000));
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 通过实现的方式创建实现类
public class CarTimeProxy implements Moveable{
private Moveable moveable;
public CarTimeProxy(Moveable moveable){
this.moveable=moveable;
}
@Override
public void move() {
//记录一个开始时间
long startTime=System.currentTimeMillis();
System.out.println("汽车开始移动...");
moveable.move();
//记录一个结束时间
long endTime=System.currentTimeMillis();
System.out.println("结束移动,总耗时:"+(endTime-startTime)+"毫秒!");
}
}
- 缺点:不管是继承还是实现都需要一个明确的接口
五:Jdk动态代理(运行的时候,动态生成代理)
- 创建一个接口
public interface Flyable {
void fly();
}
- 创建该接口的实现类
public class Aircraft implements Flyable{
@Override
public void fly() {
System.out.println("飞机在飞...");
}
}
- 创建代理类,实现InvocationHandler接口,重写invoke方法;通过method参数.invoke() 可以执行到被代理类的本身方法
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LogProxy implements InvocationHandler{
/**
* 初始化被代理的对象
*/
private Object obj;
/**
* 通过构造器给被代理的对象赋值
* @param obj
*/
public LogProxy(Object obj){
this.obj=obj;
}
/**
* proxy 代理对象
* method 被代理的方法
* args 被调用方法的实参列表
* 返回 方法执行的结果
*
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("日志开始...");
method.invoke(obj, args);
System.out.println("日志结束...");
return null;
}
}
- 获取代理对象 Proxy.newProxyInstance(类加载器,类的接口集合,InvocationHandler的实现类对象)
import java.lang.reflect.Proxy;
/**
* jdk动态代理 限制 被代理的类必须是实现了接口的类,如果这个类没有实现接口,则这个类一定不能被代理
*
* 1)写一个普通的java类,实现InvocationHandler接口,重写invoke方法。
* 2)通过method参数.invoke() 可以执行到被代理类的本身方法。
* 3)获取代理对象 Proxy.newProxyInstance(类加载器,类的接口集合,InvocationHandler的实现类对象)
*
*
*
*
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) {
//代理飞机
Flyable aircraft=(Flyable) Proxy.newProxyInstance(Aircraft.class.getClassLoader(),
Aircraft.class.getInterfaces(), new LogProxy(new Aircraft()));
aircraft.fly();
}
}
六:Cglib实现动态代理
- Cglib功能更加强大,不必要求委托类必须有接口,创建一个普通类即可
public class Aircraft{
public void fly() {
System.out.println("飞机在飞...");
}
}
- 需要先倒入Cglib的jar
- 创建代理类实现methodInterceptor的接口,重写intercept方法,通过proxy.invokeSuper(obj, args)可以调用到被代理类的本身方法,还需要在代理类中写一个获取代理对象的方法
- Enhancer允许为非接口类型创建一个代理对象,Enhancer动态创建了给定类型的子类但是拦截了所有方法,和jdk的动态代理不同,不管目标类是否有接口都能正常工作,被代理对象不能有final修饰
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class LogProxy implements MethodInterceptor{
/**
* 获取一个代理对象
* @return
*/
public Object getProxy(Class clazz){
//产生代理对象的对象
Enhancer enhancer=new Enhancer();
//设置被代理类的反射模板
enhancer.setSuperclass(clazz);
//设置回滚函数
enhancer.setCallback(this);
//返回代理对象
return enhancer.create();
}
/**
* obj 被代理的对象
* method 被代理的方法
* args 调用方法的实参列表
* proxy 代理对象
*/
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("日志开始...");
// proxy.invokeSuper(被代理的对象,实参列表)
proxy.invokeSuper(obj, args);
System.out.println("日志结束...");
return null;
}
}
- 调用代理
public class Test {
public static void main(String[] args) {
Aircraft aircraft=(Aircraft) new LogProxy().getProxy(Aircraft.class);
aircraft.fly();
}
}