简述

代理,是一种设计模式,主要作用是为其他对象提供一种代理,以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

主要分为两大代理:静态代理、动态代理(JDK动态代理、CGLIB动态代理)

以下面的例子为例,卖房人、代理方、买房人,买卖人双方不需要打交道,通过和代理方打交道,卖房人提供房子给代理方,不需要自己去找买方,代理方有一堆卖房信息,买方直接找代理方即可


代码实现

接口

public interface IHome {
void say();
}

被代理类

public class ForlanHome implements IHome{
@Override
public void say() {
System.out.println("卖程序员Forlan房子啦!!!");
}
}

1、静态代理

public class HomeProxy implements IHome {

	IHome home;

	public HomeProxy(IHome home) {
this.home = home;
} @Override
public void say() {
System.out.println("This is HomeProxy");
home.say();
}
}
	public static void main(String[] args) {
ForlanHome forlanHome = new ForlanHome();
HomeProxy homeProxy = new HomeProxy(forlanHome);
homeProxy.say();
}

2、动态代理

2.1、JDK动态代理

2.1.1、普通版

实现InvocationHandler接口重写invoke方法

public class HomeInvocationHandler implements InvocationHandler {

	IHome home;

	public HomeInvocationHandler(IHome home) {
this.home = home;
} /**
* 重写invoke方法
*
* @param proxy 生成的代理对象
* @param method 调用的方法
* @param args 方法入参
* @return
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method " + method.getName() + " start!");
Object o = method.invoke(home, args);
System.out.println("method " + method.getName() + " end!");
return o;
}
}

测试方法

public static void main(String[] args) {
IHome forlanHome = new ForlanHome();
IHome home = (IHome) Proxy.newProxyInstance(IHome.class.getClassLoader(),
new Class[]{IHome.class},
new HomeInvocationHandler(forlanHome)
);
home.say();
}

2.1.2、反射版

引入反射封装,方便调用

public class CommonInvocationHandler<T> implements InvocationHandler {

	T obj;

	public T getProxyObj(T t) {
obj = t;
T proxyInstance = (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
return proxyInstance;
} /**
* 重写invoke方法
*
* @param proxy 生成的代理对象
* @param method 调用的方法
* @param args 方法入参
* @return
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method " + method.getName() + " start..");
Object o = method.invoke(obj, args);
System.out.println("method " + method.getName() + " end!");
return o;
}
}

测试方法

public static void main(String[] args) {
IHome forlanHome = new ForlanHome();
CommonInvocationHandler<IHome> commonInvocationHandler = new CommonInvocationHandler<>();
IHome proxyObj = commonInvocationHandler.getProxyObj(forlanHome);
proxyObj.say();
}

2.2、CGLIB动态代理

第三方,需要导入jar包

 <dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>

2.2.1、普通版

实现MethodInterceptor,重写intercept方法

public class HomeMethodInterceptor implements MethodInterceptor {

	@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("method " + method.getName() + " start!");
Object result = null;
result = methodProxy.invokeSuper(o, objects);
System.out.println("method " + method.getName() + " end!");
return result;
}
}

测试方法

public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ForlanHome.class); // 被代理对象的class
enhancer.setCallback(new HomeMethodInterceptor()); // 设置回调,方法拦截器
ForlanHome forlanHome = (ForlanHome)enhancer.create(); // 生成动态代理类
forlanHome.say();
}

2.2.1、泛型版

使用泛型,封装Enhancer代码,方便调用

public class CommonMethodInterceptor<T> implements MethodInterceptor {

	public T getProxyObj(Class<T> tClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(tClass); // 被代理对象的class
enhancer.setCallback(this); // 设置回调,方法拦截器
return (T) enhancer.create(); // 生成动态代理类
} @Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("method " + method.getName() + " start!");
Object result = null;
result = methodProxy.invokeSuper(o, objects);
System.out.println("method " + method.getName() + " end!");
return result;
}
}

测试方法

public static void main(String[] args) {
CommonMethodInterceptor<ForlanHome> commonMethodInterceptor = new CommonMethodInterceptor<>();
ForlanHome proxyObj = commonMethodInterceptor.getProxyObj(ForlanHome.class);
proxyObj.say();
}

总结

1、静态代理

代理对象实现被代理对象的接口,通过调用代理接口的接口,实现代理功能

  • 代理对象/被代理对象共同实现接口
  • 多态的一种应用

2、动态代理

分离代理行为和被代理对象,替被代理对象干某件事

  • JDK动态代理
    面向接口的动态代理,代理一个对象去增强面向某个接口中定义的方法
    缺点:被代理对象必须实现接口

  • CGLIB动态代理
    面向类的动态代理,重写父类方法,增强使用
    缺点: final类不能被代理

3、区别

  • 静态代理
    a、自己写生成代理类
    b、代理类和委托类的关系在运行前就确定了
  • 动态代理
    a、在程序运行期间动态生成代理类
    b、代理类和委托类的关系是在程序运行时确定
 

Java的两大、三类代理模式的更多相关文章

  1. Java设计模式(10)代理模式(Proxy模式)

    理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼得水,享受游刃有余的乐趣. Proxy是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,P ...

  2. Java的两大数据类型

    Java的两大数据类型 基本数据类型 byte,short,int,long,float,double,boolean,char byte 类别 内容 类型 byte 简介 byte 数据类型是8位. ...

  3. JAVA设计模式——第 2 章 代理模式【Proxy Pattern】(转)

    什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人虽然不能干活,但是被代理的人能干活呀. ...

  4. 浅谈Java五大设计原则之代理模式

    我们来定义一下  AOP(面向切面编程) 它是面向对象的一种补充或者是一种增强,它在这基础上增加了一些 而外的功能增强. 它可以在原有的行为不改变的前提,在这之前或者之后完成一些而外 的事情. 而AO ...

  5. Java设计模式系列之动态代理模式(转载)

    代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 代理模式示例代码 public interface Sub ...

  6. Java设计模式---(动态)代理模式

    代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 之前虽然会用JDK的动态代理,但是有些问题却一直没有搞明白 ...

  7. Java设计模式(八)----代理模式

    代理模式 1.生活中: 代理就是一个人或者一个组织代表其它人去做一件事的现实生活中的. 在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象能够在client和目标对象之间起到中介的作用. ...

  8. Java内功修炼系列一代理模式

    代理模式是JAVA设计模式之一,网上设计模式相关的博文铺天盖地,参考它们有助于自己理解,但是所谓“尽信书不如无书”,在参考的同时也要思考其正确性,写博客也是为了记录自己理解知识点的思路历程和心路历程, ...

  9. Java学习笔记——设计模式之四.代理模式

    To be, or not to be: that is the question. --<哈姆雷特> 代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问. 上代码: p ...

  10. 详解 Java 中的三种代理模式

    代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用 ...

随机推荐

  1. 通过helm搭建Harbor

    文章转载自:http://www.mydlq.club/article/66/ 系统环境: kubernetes 版本:1.20.1 Traefik Ingress 版本:2.4.3 Harbor C ...

  2. Kubernetes 中部署 NFS-Subdir-External-Provisioner 为 NFS 提供动态分配卷

    文章转载自:http://www.mydlq.club/article/109/ 系统环境: 操作系统: CentOS 7.9 Docker 版本: 19.03.13 Kubernetes 版本: 1 ...

  3. Logstash & 索引生命周期管理(ILM)

    Grok语法 Grok是通过模式匹配的方式来识别日志中的数据,可以把Grok插件简单理解为升级版本的正则表达式.它拥有更多的模式,默认,Logstash拥有120个模式.如果这些模式不满足我们解析日志 ...

  4. 【微服务】- 服务调用 - OpenFeign

    服务调用 - OpenFeign 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! 介绍 O ...

  5. 如何0到1构建DevOps?

    从0到1构建DevOps,首先得弄清楚这个DevOps的受众群体,它的用途到底是什么,解决什么问题,比如Android Studio是为了解决Android应用的开发,3UCS xPlus是为了解决应 ...

  6. Django 之ModelAdmin对象

    一.后台管理系统配置 1 在该表对应的models类里面添加一个Meta类 class Meta: verbose_name_plural = '用户表' #指定该表在admin后台的名字为:用户表  ...

  7. 关于windows-server-下MySQL Community版本的的安装与配置

    在公司电脑或者服务器上安装软件,都是有要求的,要么购买license-(这个需要申请,难度较大),要么安装免费开源的软件 笔者最近想要安装mysql服务环境,用于数据存储及开发一些功能程序需要连接数据 ...

  8. 220722 T4 求和 /P4587 [FJOI2016]神秘数 (主席树)

    好久没打主席树了,都忘了怎么用了...... 假设我们选了一些数能构成[0,x]范围内的所有值,下一个要加的数是k(k<=x+1),那么可以取到[0,x+k]内的所有取值,所以有一种做法: 对于 ...

  9. UVA12186 工人的请愿书 Another Crisis (树形DP)

    dp[i]表示要让i向上级发请愿书,最少需要多少个工人递交请愿书,因为要取前T%最小的,所以还要将i的子节点排序(这里用vector实现),取前c个最小的作为dp[i]的值. 这里用dfs可以省去dp ...

  10. 重写 hashcode()真有那么简单嘛?

    万万没想到一个 hashcode() 方法,既然会引出一堆的知识盲区,简直了. 起因: 老八股:为什么重写Equals方法要重写HashCode方法. 大声告诉我为什么,闭着眼睛先把答案背出来,啥?这 ...