静态代理

抽象主题角色:声明真实主题和代理主题的共同接口。

代理主题角色:代理主题内部含有对真实主题的引用,从而在任何时候操作真实主题对象;代理主题提供一个与真实主题相同的接口,以便在任何时候都可以代替真实主题。代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作,而不是单纯的传递调用。

真实主题角色:定义代理角色所代表的的真实对象。

UML图:

抽象主题

public interface Subject {
void request();
}

真实主题

public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("真实对象的方法");
}
}

代理主题

public class ProxySubject implements Subject {

    private RealSubject subject;

    public ProxySubject() {
} @Override
public void request() {
pre();
if (subject == null){
subject = new RealSubject();
}
subject.request();
post();
} private void pre(){
System.out.println("方法执行之前");
} private void post(){
System.out.println("方法执行之后");
}
}

执行:

    public static void main(String[] args) throws Exception {
ProxySubject subject = new ProxySubject();
subject.request();
}

输出:

方法执行之前
真实对象的方法
方法执行之后 

动态代理

JDK自带的动态代理,实现InvocationHandler接口。

声明接口

public interface MyConnection extends AutoCloseable {

    void createStatement() throws Exception;

    @Override
void close() throws Exception;
}

真实主题

public class MyDefaultConnection implements MyConnection {
@Override
public void createStatement() throws Exception {
System.out.println("Create Statement ...");
} @Override
public void close() throws Exception {
System.out.println("Close Connection ...");
}
}

代理主题

public class MyConnectionProxy implements InvocationHandler {

    private MyConnection conn;
private MyConnection proxyConn; public MyConnectionProxy(MyConnection conn) {
this.conn = conn;
this.proxyConn = (MyConnection) Proxy.newProxyInstance(MyConnection.class.getClassLoader(), new Class<?>[] {MyConnection.class}, this);
} public MyConnection getConn() {
return conn;
} public MyConnection getProxyConn() {
return proxyConn;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println("==代理方法:" + methodName);
if("close".equals(methodName)){
System.out.println("**不执行close方法");
}else{
return method.invoke(conn, args);
}
return null;
}
}

执行:

    public static void main(String[] args) throws Exception {
MyConnection connection = new MyDefaultConnection();
MyConnectionProxy proxy = new MyConnectionProxy(connection);
proxy.getProxyConn().createStatement();
proxy.getProxyConn().close();
}

你会发现我的代理对象去哪里了?实际上我放在InvocationHandler的实现类里面了,这里参考的是mybatis源码的设计。

输出:

==代理方法:createStatement
Create Statement ...
==代理方法:close
**不执行close方法

CGLib

CGLib不需要接口就能实现动态代理。

CGLIB 原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

CGLIB 底层:使用字节码处理框架ASM,来转换字节码并生成新的类。

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

需要代理的对象

public class Programmer {

    public void work(){
System.out.println("程序员正在敲代码...");
} public final void finalCannotOverride(){
System.out.println("final方法不能被生成的子类覆盖");
} private void privateCannotOverride(){
System.out.println("private方法不能被生成的子类覆盖");
}
}

代理类

public class ProgrammerProxy implements MethodInterceptor {

    // 真实对象
private Object realObject;
// 代理对象
private Object proxyObject; public ProgrammerProxy(Object realObject) {
this.realObject = realObject;
Enhancer enhancer = new Enhancer();
// 设置需要代理的对象
enhancer.setSuperclass(realObject.getClass());
// 设置代理人
enhancer.setCallback(this);
this.proxyObject = enhancer.create();
} public Programmer getProxyObject() {
return (Programmer) proxyObject;
} @Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
pre();
Object result = method.invoke(realObject, objects);
post();
return result;
} private void pre(){
System.out.println("==先吃早餐");
} private void post(){
System.out.println("==下班打卡");
}
}

执行:

    public static void main(String[] args) throws Exception {
Programmer programmer = new Programmer();
ProgrammerProxy proxy = new ProgrammerProxy(programmer);
proxy.getProxyObject().finalCannotOverride();
proxy.getProxyObject().work();
}

输出:

final方法不能被生成的子类覆盖
==先吃早餐
程序员正在敲代码...
==下班打卡

Java设计模式--代理模式+动态代理+CGLib代理的更多相关文章

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

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

  2. java设计模式中的动态代理

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

  3. 代理模式详解:静态代理、JDK动态代理与Cglib动态代理

    代理模式简介分类 概念 ​ 代理,是为了在不修改目标对象的基础上,增强目标方法的业务逻辑. ​ 客户类需要执行的是目标对象的目标方法,但是真正执行的是代理对象的代理方法,客户类对目标对象的访问是通过代 ...

  4. 黑马程序员:Java基础总结----静态代理模式&动态代理

    黑马程序员:Java基础总结 静态代理模式&动态代理   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 静态代理模式 public  class  Ts {   ...

  5. java 代理模式一: 静态代理

    代理模式: 代理模式的作用:为其他对象提供一种代理以控制对 特定对象  的访问. 某种情况下,一个客户不想或者直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用:通过代理对象引用. ...

  6. 总结两种动态代理jdk代理和cglib代理

    动态代理 上篇文章讲了什么是代理模式,为什么用代理模式,从静态代理过渡到动态代理. 这里再简单总结一下 什么是代理模式,给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原 ...

  7. java 设计模式 --委派模式

    委派模式(Delegate)原理: 类B和类A是两个互相没有任何关系的类,但是B具有和A一模一样的方法和属性:并且调用B中的方法/属性就是调用A中同名的方法和属性. B好像就是一个受A授权委托的中介, ...

  8. 3.java设计模式-建造者模式

    Java设计模式-建造者模式 在<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal repr ...

  9. Java设计模式——组合模式

    JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...

  10. java设计模式--单列模式

    java设计模式--单列模式 单列模式定义:确保一个类只有一个实例,并提供一个全局访问点. 下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点: Demo1: /** * 单列模式需要满足 ...

随机推荐

  1. django-发送文件

    客户端授权密码”,勾选“开启”,弹出新窗口填写手机验证码. settings.py配置 EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBac ...

  2. mybatis框架-查询用户表中的记录数

    之前已经搭建过mybatis框架了,现在我们要用mybatis框架真正的干点事情了. 这是这个简单web项目的整体架构. 我们使用mybatis框架查询用户表中的记录数: 这是用户类: package ...

  3. Comet OJ - Contest #14 转转的数据结构题 珂朵莉树+树状数组

    题目链接: 题意:有两个操作 操作1:给出n个操作,将区间为l到r的数字改为x 操作2:给出q个操作,输出进行了操作1中的第x到x+y-1操作后的结果 解法: 把询问离线,按照r从小到大排序 每次询问 ...

  4. GitLab : Omnibus Installer

    转自:https://www.ibm.com/developerworks/community/blogs/2280dc86-a78a-441b-89d7-5b4c41595852/entry/Git ...

  5. pip包管理工具 基本使用

    # 简介 pip是一款包管理工具, 和apt, yum, brew功能类似 # 安装 wget --no-check-certificate https://bootstrap.pypa.io/get ...

  6. vue中前端弹窗队列展示

    在前端写一个弹窗可能很简单,那如果同时有多个弹窗呢 这样的话就要考虑弹窗的展示问题,肯定是不能叠加在一起的,这时候就要通过队列(先进先出)来展示 思路就是根据队列来实现,至于具体的实现方式,可以在项目 ...

  7. 洛谷 P1351 联合权值 题解

    P1351 联合权值 题目描述 无向连通图 \(G\) 有 \(n\) 个点,\(n-1\) 条边.点从 \(1\) 到 \(n\) 依次编号,编号为 \(i\) 的点的权值为 \(W_i\)​,每条 ...

  8. vsftp 匿名访问设置设置

    本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/vsftpd_configuration vsftpd (very ...

  9. 利用C++ STL的vector模拟邻接表的代码

    关于vector的介绍请看 https://www.cnblogs.com/zsq1993/p/5929806.html https://zh.cppreference.com/w/cpp/conta ...

  10. pip install --upgrade urllib3==1.25.2

    pip install --upgrade urllib3==1.25.2 pip 安装,更新模块   moudle_name:是对应的模块名:请自行更换为自己需要更新的模块名 查看所有可更新的模块: ...