Java设计模式--代理模式+动态代理+CGLib代理
静态代理
抽象主题角色:声明真实主题和代理主题的共同接口。
代理主题角色:代理主题内部含有对真实主题的引用,从而在任何时候操作真实主题对象;代理主题提供一个与真实主题相同的接口,以便在任何时候都可以代替真实主题。代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作,而不是单纯的传递调用。
真实主题角色:定义代理角色所代表的的真实对象。
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代理的更多相关文章
- Java设计模式系列之动态代理模式(转载)
代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 代理模式示例代码 public interface Sub ...
- java设计模式中的动态代理
Java的三种代理模式 1.代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩 ...
- 代理模式详解:静态代理、JDK动态代理与Cglib动态代理
代理模式简介分类 概念 代理,是为了在不修改目标对象的基础上,增强目标方法的业务逻辑. 客户类需要执行的是目标对象的目标方法,但是真正执行的是代理对象的代理方法,客户类对目标对象的访问是通过代 ...
- 黑马程序员:Java基础总结----静态代理模式&动态代理
黑马程序员:Java基础总结 静态代理模式&动态代理 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 静态代理模式 public class Ts { ...
- java 代理模式一: 静态代理
代理模式: 代理模式的作用:为其他对象提供一种代理以控制对 特定对象 的访问. 某种情况下,一个客户不想或者直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用:通过代理对象引用. ...
- 总结两种动态代理jdk代理和cglib代理
动态代理 上篇文章讲了什么是代理模式,为什么用代理模式,从静态代理过渡到动态代理. 这里再简单总结一下 什么是代理模式,给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原 ...
- java 设计模式 --委派模式
委派模式(Delegate)原理: 类B和类A是两个互相没有任何关系的类,但是B具有和A一模一样的方法和属性:并且调用B中的方法/属性就是调用A中同名的方法和属性. B好像就是一个受A授权委托的中介, ...
- 3.java设计模式-建造者模式
Java设计模式-建造者模式 在<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal repr ...
- Java设计模式——组合模式
JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...
- java设计模式--单列模式
java设计模式--单列模式 单列模式定义:确保一个类只有一个实例,并提供一个全局访问点. 下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点: Demo1: /** * 单列模式需要满足 ...
随机推荐
- Java 内部类和Lambda
Java内部类 内部类又称为嵌套类,是在类中定义另外一个类.内部类可以处于方法内/外,内部类的成员变量/方法名可以和外部类的相同.内部类编译后会成为完全不同的两个类,分别为outer.class和ou ...
- Spring Security 认证执行流程
本文基于 Spring Security 5.x 推荐阅读: 项目集成Spring Security SpringSecurity 整合 JWT 一.外层-正常登陆调用 项目启动后会自动寻找 User ...
- 【洛谷P4585】 [FJOI2015]火星商店问题 线段树分治+可持久化trie
感觉这个线段树分治和整体二分几乎相同啊~ code: #include <bits/stdc++.h> #define MAX 100300 #define ll long long #d ...
- learning scala zipAll
If two Iterables aren't the same size, then zipAll can provide fillers for what it couldn't find a c ...
- THUWC2020 划船记
PS:THUWC2020在2019年 Day 1 考场外的太懒了不写了. 三题题目大意: T1: T2: 给定一个\(n(\leq 10^5)\)个结点的有向图,每条边有个limit,表示经过这条边l ...
- Pytest权威教程(官方教程翻译)
Pytest权威教程01-安装及入门 Pytest权威教程02-Pytest 使用及调用方法 Pytest权威教程03-原有TestSuite的执行方法 Pytest权威教程04-断言的编写和报告 P ...
- mysql right() 函数
mysql> ); +---------------------+ | right() | +---------------------+ | dedede | +--------------- ...
- mysql ,limit 的使用
//offset参数指定要返回的第一行的偏移量.第一行的偏移量为0,第二行的偏移量为1.count指定要返回的最大行数.LIMIT offset,count; mysql> select * f ...
- SQL学习回顾
--本文源自<黑马程序员>
- 团队作业-Beta版本演示
组长博客链接 https://www.cnblogs.com/cmlei/p/12063671.html 本组成员 031702431 陈明磊 组长 031702227 林镕炜 031702413 韩 ...