什么是 代理模式 ?
代理模式就是为对象提供一种代理,以控制外部对这个对象的访问。
通俗地讲,代理就是二手房中介:
买房 ↔ 代理(拿提成)↔ 买房
什么是静态代理?
// 接口
public interface Movie {
void play();
}
// 实现类
public class RealMovie implements Movie {
@ Override
public void play() {
System.out.println("您正在观看电影 《肖申克的救赎》");
}
}
// 代理类
public class Cinema implements Movie {
RealMovie movie;
public Cinema(RealMovie movie) {
super();
this.movie = movie;
}
@Override
public void play() {
guanggao();
movie.play();
guanggao();
}
public void guanggao(){
System.out.println("瓜子二手车");
}
}
Cinema影院是Movie的代理类,在执行放电影核心操作的同时,也实现了自己的需求。
代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。
代理类和被代理类应共同实现一个接口,或共同继承某个类。
什么是动态代理?
在 JDK 的java.lang.reflect包下,提供了一个Proxy类和一个Invocation handler 接口,通过他们俩可以实现JDK下的动态代理。
InvocationHandler的核心是invoke()方法,用于在调用真实对象方法时,加入扩展功能,如日志、监控等。
Proxy的核心是newInstance()方法,用于生成代理类。
二者通过Proxy.newInstance()方法关联,invocationHandler会作为参数传入Proxy,Proxy在编译时自动生成代理类。
demo:
// 接口
public interface Subject {
public String SayHello(String name);
public String SayGoodBye();
}
// 需要代理的类RealSubject
public class RealSubject implements Subject {
public String SayHello(String name) {
return "hello " + name;
}
public String SayGoodBye() {
return " good bye ";
}
}
// 创建调用处理器
public class InvocationHandlerImpl implements InvocationHandler {
// 需要代理的对象
private Object subject;
// 构造函数
public InvocationHandlerImpl(Object subject) {
this.subject = subject;
}
// invoke()方法负责处理动态代理类上的所有方法调用
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在调用真实对象方法前添加一些扩展功能
System.out.println("在调用之前,我要干点啥呢?");
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
Object returnValue = method.invoke(subject, args);
// 在调用真实对象方法后添加一些扩展功能
System.out.println("在调用之后,我要干点啥呢?");
return returnValue;
}
}
// 实现动态代理
public class DynamicProxyDemonstration {
public static void main(String[] args) {
// 需要被代理的对象
Subject realSubject = new RealSubject();
// 代理对象
Subject subject = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new InvocationHandlerImpl(realSubject));
// 通过代理对象调用真实对象的方法
String hello = subject.SayHello("jiankunking");
}
}
为什么需要动态代理?
如果我们想扩展类的功能,且不能修改类,那么静态代理可以实现。
如果我们要对很多的类扩展功能,如加日志、监控等,静态代理就需要一一创建代理类,而动态代理只需要定义好InvocationHandler的实现类逻辑即可。
动态代理和反射的关系?
1、动态代理核心类:InvocationHandler、Method、Proxy,都在java.lang.reflect反射包内。
2、通过InvocationHandler的invoke()方法调用真实对象的方法时,需要传入Method对象,这里使用的就是 反射机制 。
3、Proxy.newProxyInstance()传入ClassLoader对象来动态创建代理类,使用的是反射机制。
cglib和jdk动态代理区别?
JDK动态代理是通过反射类Proxy、InvocationHandler 回调 接口实现的,所以只能对该类所实现接口中定义的方法进行代理,有一定的局限性。
cglib 动态代理,不受代理类必须实现接口的限制,原理是动态生成被代理类的子类。