代理在我们生活中并不陌生,假如我现在饿了,我可以选择直接去饭店吃,也可以通过外卖平台下单,比如百度外卖、美团外卖、饿了么这些平台本身不生产产品,他们只是商家的搬运工,可以理解成外卖平台就是各种商家的代理。
外卖平台帮我买份饭并送货上门,不仅节约了我去饭店排队的麻烦,可以节约自已很多时间,排队这些细节的问题我不需要关心,目的就是吃上我想吃的饭就ok。我不想自已亲自做的事或着做不到的事(比如中午我需要开个会,没时间去出去),就可以找个代理帮我去做。
现在各大平台都在搞活动,只要下单就可以打折,“打折”算是代理的一个活动,除了给了我想吃的饭还帮我省了部分钱(有的平台送优惠劵)。代理可以帮我完成要做的事情,还可以附加一些代理想做的事情
那我们在开发中什么时候用代理模式呢?
1、自已不想做或着做不到的事
2、需要在现有方法基础上扩展些功能,比如在谋方法执行前后非侵入式打印log
静态代理
public class ProxyDemo {
public static void main(String args[]){
RealSubject subject = new RealSubject();
ProxySubject p = new ProxySubject(subject);
p.request();
}
}
interface Subject{
void request();
}
class RealSubject implements Subject{
public void request(){
System.out.println("request");
}
}
class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("调用前");
subject.request();
System.out.println("调用后");
}
}
其实代理还有一个作用就是隐藏真正实现细节,做为代理类不需要关心执行的方法是怎么实现的。
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
上边的实现就是一种静态代理的实现方式,那啥是动态代理呢,说白了Proxy类是通过反射生成的,AOP (面向切面编程)主要是利用动态代理模式的技术来实现的。
动态代理有2种实现方式:
1、使用JDK的Proxy实现的动态代理
2、使用CGlib实现的动态代理
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉 ProxySubject。
Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成 实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
实现方式:
public class DynamicProxyDemo01 {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject(); //1.创建委托对象
ProxyHandler handler = new ProxyHandler(realSubject); //2.创建调用处理器对象
Subject proxySubject = (Subject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
RealSubject.class.getInterfaces(), handler); //3.动态生成代理对象
proxySubject.request(); //4.通过代理对象调用方法
}
}
/**
* 接口
*/
interface Subject{
void request();
}
/**
* 委托类
*/
class RealSubject implements Subject{
public void request(){
System.out.println("====RealSubject Request====");
}
}
/**
* 代理类的调用处理器
*/
class ProxyHandler implements InvocationHandler{
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("调用前");
Object result = method.invoke(subject, args);
System.out.println("调用后");
return result;
}
}
使用CGlib实现的动态代理
public class DynamicProxyDemo02 {
public static void main(String[] args) {
RealSubjectCglib cglib=new RealSubjectCglib();
RealSubject realSubject=(RealSubject)cglib.getInstance(new RealSubject());
realSubject.request();
}
/**
*没有实现接口的委拖类
*/
class RealSubject {
public void request(){
System.out.println("====RealSubject Request====");
}
}
public class RealSubjectCglib implements MethodInterceptor {
private Object target;
/**
* 创建代理对象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
@Override
// 回调方法
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("调用前");
proxy.invokeSuper(obj, args);
System.out.println("调用后");
return null;
}
}
}
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。