所谓代理模式就是不是自己执行自己的方法,而是找别的类来代替自己调用自己的方法,这就是静态代理:
下面是借鉴他人的例子,首先感谢大佬的深情讲解,就是说我是一个程序员(Programmer),但是我能够写代码,但是我写的代码是主要用于发布博客,那我写的博客没有人来看,我就想找大V来给我点赞,这样我就能引流过来一些用户,来看我的文章—这个过程中,是大V发布文章,我去写,最终是大V代表着我去发布,很像枪手对吧;
静态代理
//我需要别人代理的方法public interface Programmer {// 程序员每天都写代码发布文章void coding();}//我public class Java3y implements Programmer {@Overridepublic void coding() {System.out.println("我发布了最新文章:......给女朋友讲解什么是代理模式.......");}}//大Vpublic class ProgrammerBigV implements Programmer {// 指定程序员大V要让谁发文章(先发文章、后点赞)private Java3y java3y ;public ProgrammerBigV(Java3y java3y) {this.java3y = java3y;}// 程序员大V点赞评论收藏转发public void upvote() {System.out.println("程序员大V点赞评论收藏转发!");}@Overridepublic void coding() {// 让Java3y发文章java3y.coding();// 程序员大V点赞评论收藏转发!upvote();}}//运行public class Main {public static void main(String[] args) {// 想要发达的Java3yJava3y java3y = new Java3y();// 受委托程序员大VProgrammer 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点赞评论收藏转发!");}@Overridepublic void coding() {// 让Java3y发文章了java3y.coding();// 程序员大V点赞评论收藏转发!upvote();}}//程序员大V想要赚点零花钱的时候直接让Java3y发文章就好了。public class Main {public static void main(String[] args) {// 受委托程序员大VProgrammer programmer = new ProgrammerBigV();// 受委托程序员大V让Java3y发文章,大V来点赞programmer.coding();}}//此时,真实对象(Java3y)对外界来说是透明的。
这样就实现了我发文章,但是大V其实做了包装,让我有钱可赚了;但是时间一长,大V就觉得我的流量上去了有了利用价值;
PS:加钱感觉不好,毕竟这个操作需要原对象的参与,除非给原对象加一个金额数比如说—-一个亿;
这就是代理类添加的自定义方法
代理类自定义方法
public class ProgrammerBigV implements Programmer {// ..省略了上面的代码// 添加广告吧public void addAdvert() {System.out.println("这次我要加广告");}@Overridepublic 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: 代理方法*/@Overridepublic 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方式的代理其实就是通过反射鼓捣出了一个代理类,然后通过该代理类进行相关操作
