所谓代理模式就是不是自己执行自己的方法,而是找别的类来代替自己调用自己的方法,这就是静态代理:
下面是借鉴他人的例子,首先感谢大佬的深情讲解,就是说我是一个程序员(Programmer),但是我能够写代码,但是我写的代码是主要用于发布博客,那我写的博客没有人来看,我就想找大V来给我点赞,这样我就能引流过来一些用户,来看我的文章—这个过程中,是大V发布文章,我去写,最终是大V代表着我去发布,很像枪手对吧;
静态代理
//我需要别人代理的方法
public interface Programmer {
// 程序员每天都写代码发布文章
void coding();
}
//我
public class Java3y implements Programmer {
@Override
public void coding() {
System.out.println("我发布了最新文章:......给女朋友讲解什么是代理模式.......");
}
}
//大V
public class ProgrammerBigV implements Programmer {
// 指定程序员大V要让谁发文章(先发文章、后点赞)
private Java3y java3y ;
public ProgrammerBigV(Java3y java3y) {
this.java3y = java3y;
}
// 程序员大V点赞评论收藏转发
public void upvote() {
System.out.println("程序员大V点赞评论收藏转发!");
}
@Override
public void coding() {
// 让Java3y发文章
java3y.coding();
// 程序员大V点赞评论收藏转发!
upvote();
}
}
//运行
public class Main {
public static void main(String[] args) {
// 想要发达的Java3y
Java3y java3y = new Java3y();
// 受委托程序员大V
Programmer programmer = new ProgrammerBigV(java3y);
// 受委托程序员大V让Java3y发文章,大V(自己)来点赞
programmer.coding();
}
}
经过一段时间后,得这是一条财路。于是就给足了程序员大V钱,让程序员大V只做他的生意,不能做其他人的生意(断了其他人的财路)。
于是乎,程序员大V只做Java3y一个人的生意:
透明代理(普通代理)
public class ProgrammerBigV implements Programmer {
// 指定程序员大V要给Java3y点赞
private Java3y java3y ;
// 只做Java3y的生意了
public ProgrammerBigV() {
this.java3y = new Java3y();
}
// 程序员大V点赞评论收藏转发
public void upvote() {
System.out.println("程序员大V点赞评论收藏转发!");
}
@Override
public void coding() {
// 让Java3y发文章了
java3y.coding();
// 程序员大V点赞评论收藏转发!
upvote();
}
}
//程序员大V想要赚点零花钱的时候直接让Java3y发文章就好了。
public class Main {
public static void main(String[] args) {
// 受委托程序员大V
Programmer programmer = new ProgrammerBigV();
// 受委托程序员大V让Java3y发文章,大V来点赞
programmer.coding();
}
}
//此时,真实对象(Java3y)对外界来说是透明的。
这样就实现了我发文章,但是大V其实做了包装,让我有钱可赚了;但是时间一长,大V就觉得我的流量上去了有了利用价值;
PS:加钱感觉不好,毕竟这个操作需要原对象的参与,除非给原对象加一个金额数比如说—-一个亿;
这就是代理类添加的自定义方法
代理类自定义方法
public class ProgrammerBigV implements Programmer {
// ..省略了上面的代码
// 添加广告吧
public void addAdvert() {
System.out.println("这次我要加广告");
}
@Override
public void coding() {
// 让Java3y发文章了
java3y.coding();
// 程序员大V点赞评论收藏转发!
upvote();
// 加广告
addAdvert();
}
}
这里可以说是对代理对象的附能,让原本只能写代码的程序员java3y能,附带广告,从而大家一起赚钱;
动态代理
随着找时间的推移,程序员感觉自己的知识和本事都被大V砍掉了一部分,所以程序员觉得有必要改变方式了,于是就开始请水军来点赞支持;
如果是水军的话就不能自己去构建代理对象了,这个时候JDK的Proxy对象,这个类可以使用反射来构建代理对象;
public class Main {
public static void main(String[] args1) {
// Java3y请水军
Java3y java3y = new Java3y();
Programmer programmerWaterArmy = (Programmer) Proxy.newProxyInstance(
java3y.getClass().getClassLoader(),
java3y.getClass().getInterfaces(),
(proxy, method, args) -> {
// 如果是调用coding方法,那么水军就要点赞了
if (method.getName().equals("coding")) {
method.invoke(java3y, args);
System.out.println("我是水军,我来点赞了!");
} else {
// 如果不是调用coding方法,那么调用原对象的方法
return method.invoke(java3y, args);
}
return null;
});
// 每当Java3y写完文章,水军都会点赞
programmerWaterArmy.coding();
}
}
这样写真实方便
接下来看看这个Proxy类,
loader:就是被代理的对象的classoader,
interfaces:就是被代理的对象实现的接口,表示我需要代理这对象的哪个部分;
h:你要做什么事情,当然这里肯定是拦截的接口interfaces里面所有的方法,你需要通过method去区分;
注意!!!!:总结一下代理模式必须要有的几个因素
1)代理对象有跟目标对象相同的方法,
2)使用代理必须要有接口,
3)动态代理是通过反射调用invoke方法来实现代理,且肯定会用到Proxy对象;
区别!!!!:静态代理需要自己写代理类(代理类需要实现与目标对象相同的接口),动态代理不需要自己编写代理类;
静态代理的弊端(动态代理的好处):
静态代理时如果目标对象有多个方法,我们的代理类必须一一实现,这样需要改动代码;动态代理是使用jdk的Proxy类实例化代理对象,通过反射机制默认就实现了接口的全部方法;
其他方式的动态代理
目前动态代理也可以不实现接口,这样的代理方式称为——cglib代理:
忽略导包,版本3.2.5
直接上代码:
public class HelloService {
public HelloService() {
System.out.println("HelloService构造");
}
/**
* 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
*/
final public String sayOthers(String name) {
System.out.println("HelloService:sayOthers>>"+name);
return null;
}
public void sayHello() {
System.out.println("HelloService:sayHello");
}
}
//自定义MethodInterceptor:主要是为类添加“======插入前置通知======”
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyMethodInterceptor implements MethodInterceptor{
/**
* sub:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后者通知======");
return object;
}
}
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
public class Client {
public static void main(String[] args) {
// 代理类class文件存入本地磁盘方便我们反编译查看源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(HelloService.class);
// 设置enhancer的回调对象
enhancer.setCallback(new MyMethodInterceptor());
// 创建代理对象
HelloService proxy= (HelloService)enhancer.create();
// 通过代理对象调用目标方法
proxy.sayHello();
}
}
运行结果:
以上代码和图片转自:CGLIB动态代理实现原理
感谢大佬!!
然后大佬后面还跟了源码分析,如果想看的话还是去那边看吧,这里就不再啰嗦了;
总结归纳:
cglib方式的代理其实就是通过反射鼓捣出了一个代理类,然后通过该代理类进行相关操作