java 代理模式

2023-11-14

1、静态代理

1.1 代码实现

// 接口
interface Hello{
    String sayHello(String str);
}
// 实现
class HelloImp implements Hello{
    @Override
    public String sayHello(String str) {
        return "HelloImp: " + str;
    }
}

// 静态代理方式
class StaticProxiedHello implements Hello{
    private Hello hello = new HelloImp();
    @Override
    public String sayHello(String str) {
        logger.info("You said: " + str);
        return hello.sayHello(str);
    }
}

上例中静态代理类StaticProxiedHello作为HelloImp的代理,实现了相同的Hello接口。

1.2 总结

由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 

2、动态代理

2.1 代理

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * jdk代理方式
 * @Title: DynamicProxy.java
 * @Package com.spring.pro.jdk.proxy
 * @Description:
 * @author ybwei
 * @date 2018年11月8日 下午6:10:57
 * @version V1.0
 */
public class DynamicProxy implements InvocationHandler {
	private Object target;

	public DynamicProxy(Object target) {
		this.target = target;
	}

	@SuppressWarnings("unchecked")
	public <T> T getProxy() {
		return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		sayBefore();
		Object result = method.invoke(target, args);
		sayAfter();
		return result;
	}

	private void sayBefore() {
		System.out.println("before...");
	}

	private void sayAfter() {
		System.out.println("after...");
	}
}

2.2 测试

import com.spring.pro.jdk.proxy.DynamicProxy;
import com.spring.pro.service.Hello;
import com.spring.pro.service.HelloImpl;

/**   
 * @Title: Test.java 
 * @Package com.spring.pro.jdk.test 
 * @Description:  
 * @author ybwei  
 * @date 2018年11月8日 下午6:12:10 
 * @version V1.0   
 */
public class Test {
    public static void main(String[] args) {
        DynamicProxy dynamicProxy = new DynamicProxy(new HelloImpl());
        Hello hello = dynamicProxy.getProxy();
        hello.sayHello("JDK");
    }
}

结果:

before...
Hello by JDK
after...

2.3 总结

在程序运行时,运用反射机制动态创建而成。 动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 

缺点:

只能对实现了接口的类进行,没有实现接口的类不能使用JDK动态代理。

如果对象没有实现接口我们该如何代理呢?答案是CGLIB。

3、CGLIB

3.1 代码实现

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**
 * cglib代理方式
 * @Title: CGLibProxy.java
 * @Package com.spring.pro.proxy
 * @Description:
 * @author ybwei
 * @date 2018年11月8日 下午5:43:24
 * @version V1.0
 */
public class CGLibProxy implements MethodInterceptor {
	// 单例模式
	private static CGLibProxy instance = new CGLibProxy();

	private CGLibProxy() {
	}

	public static CGLibProxy getInstance() {
		return instance;
	}

	public <T> T getProxy(Class<T> cls) {
		return (T) Enhancer.create(cls, this);
	}

	public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		sayBefore();
		Object result = methodProxy.invokeSuper(obj, objects);
		sayAfter();
		return result;
	}

	private void sayBefore() {
		System.out.println("before...");
	}

	private void sayAfter() {
		System.out.println("after...");
	}
}

3.2 测试

import com.spring.pro.cglib.proxy.CGLibProxy;
import com.spring.pro.service.Hello;
import com.spring.pro.service.HelloImpl;

/**
 * @Title: Test.java
 * @Package com.spring.pro.proxy.test
 * @Description:
 * @author ybwei
 * @date 2018年11月8日 下午5:45:11
 * @version V1.0
 */
public class Test {
	public static void main(String[] args) {
		Hello helloCGLib = CGLibProxy.getInstance().getProxy(HelloImpl.class);
		helloCGLib.sayHello("CGLib");
	}
}

3.3 总结

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

4、spring aop

SpringAOP动态代理策略

  • 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 。
  • 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换。
  • 如果目标对象实现了接口,可以强制使用CGLIB实现AOP。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java 代理模式 的相关文章

随机推荐

  • 前端性能优化:7.页面渲染优化

    本文将主要关注浏览器获取到资源后 进行渲染部分的相关优化内容 7 1 页面渲染性能 页面渲染阶段对性能体验的应i昂与资源加载阶段同样重要 而对于设计高交互频次的应用来说可能更加重要 本节将整个渲染过程划分为五个串行阶段进行概述 优化渲染的实
  • 大众点评校招助理产品经理-笔试题分析(下)

    针对大众点评网的任何一个产品的一个需要改进的点 信息 数据或功能体验都行 给出你的分析和改进规划 希望尽可能的全面 深入 详细 1 改进产品版本与使用机型 使用版本 大众点评Android客户端V5 2版本 机型 HTC Desire HD
  • memset in C++ and C

    definition memset是计算机中C C 语言函数 将s所指向的某一块内存中的前n个 字节的内容全部设置为ch指定的ASCII值 第一个值为指定的内存地址 块的大小由第三个参数指定 这个函数通常为新申请的内存做初始化工作 其返回值
  • Failed to execute goal org.apache.maven.plugins:maven-checkstyle-plugin

    idea编译项目时 出现如下报错 ERROR Failed to execute goal org apache maven plugins maven checkstyle plugin 3 0 0 check validate on p
  • k8s学习笔记(二):k8s的组件介绍

    文章目录 k8s组件介绍 架构图 角色 控制平面组件 Control Plane Components kube apiserver 端口 容器 etcd 端口 容器 kube scheduler 容器 端口 kube controller
  • Postman脚本——断言测试

    pm对象提供了测试相关功能 pm test testName String specFunction Function Function 测试函数 pm expect assertion Function Assertion 允许在响应数据
  • [552]python实现聚类算法(6种算法)

    1 Mean shift 1 概述 Mean shift 即 均值迁移 的基本思想 在数据集中选定一个点 然后以这个点为圆心 r为半径 画一个圆 二维下是圆 求出这个点到所有点的向量的平均值 而圆心与向量均值的和为新的圆心 然后迭代此过程
  • AI炼丹技巧

    目录 样本不平衡 1 什么是样本不平衡问题 2 样本不平衡会对我们模型的训练带来哪些影响呢 3 在机器学习中解决样本不平衡问题有哪些通用的解决策略 4 在深度学习中 有哪些解决样本不平衡的方法 5 从模型评价指标的角度 重新审视训练好的模型
  • 计算机中丢失msvcp140.dll怎么解决?分享三个解决方法

    当我们在运行某些应用程序时 可能会遇到 缺少msvcp140 dll 或 找不到msvcp140 dll 的错误提示 这意味着我们的系统缺少这个重要的动态链接库文件 msvcp140 dll丢失会造成很多软件无法正常启动运行 下面小编就分享
  • 全网最全!Python爬虫requests库教程(附案例)

    1 requests 库简介 Requests 是一个为人类设计的简单而优雅的 HTTP 库 requests 库是一个原生的 HTTP 库 比 urllib3 库更为容易使用 requests 库发送原生的 HTTP 1 1 请求 无需手
  • 【MySQL高级篇笔记-性能分析工具的使用 (中) 】

    此笔记为尚硅谷MySQL高级篇部分内容 目录 一 数据库服务器的优化步骤 二 查看系统性能参数 三 统计SQL的查询成本 last query cost 四 定位执行慢的 SQL 慢查询日志 1 开启慢查询日志参数 2 查看慢查询数目 3
  • 常见的排序算法及其复杂度分析

    1 常见算法分类 十种常见排序算法一般分为以下几种 非线性时间比较类排序 交换类排序 快速排序和冒泡排序 插入类排序 简单插入排序和希尔排序 选择类排序 简单选择排序和堆排序 归并排序 二路归并排序和多路归并排序 线性时间非比较类排序 计数
  • 黑盒测试与白盒测试的区別

    黑盒测试与白盒测试是软件测试中两种不同的测试方法 它们的主要区别在于测试者对被测试软件的了解程度 下面 我们将详细介绍这两种测试方法的特点和适用场景 一 黑盒测试 黑盒测试又称为功能测试 是针对被测试软件的功能进行测试的一种测试方法 测试者
  • linux 进程几种状态,linux进程状态

    linux系统最常用的命令莫过于ps 经常要用其查看linux的进程和线程情况 此文我们着重来看进程 进程又分为以下几种状态 1 运行 正在运行或在运行队列中等待 2 中断 休眠中 受阻 在等待某个条件的形成或接受到信号 3 不可中断 收到
  • Kotlin Coroutines Flow 系列(一) Flow 基本使用

    一 Kotlin Flow 介绍 Flow 库是在 Kotlin Coroutines 1 3 2 发布之后新增的库 官方文档给予了一句话简单的介绍 Flow cold asynchronous stream with flow build
  • C# socket异步通信服务器和客户端

    本文章向大家介绍C socket异步通信服务器和客户端 主要包括C socket异步通信服务器和客户端使用实例 应用技巧 基本知识点总结和需要注意事项 具有一定的参考价值 需要的朋友可以参考一下 服务器代码 只要客户端连接进来就会接收到Se
  • Qt之QTableView 保持滚动条自动滚动到底部

    在使用QTableView添加数据时 当数据量超出显示范围时会自动的打开滚动条 如果设置了在需要时打开滚动条属性 而默认的是滚动条一直是保持在最顶部 但是有些时候我们添加数据时是需要查看添加的最新结果的 所以一般都会把滚动条滚动到最新数据那
  • 【scrapy】scrapy爬取数据指南

    scrapy是爬虫界常用的基于Python爬虫框架 但是网上找了很多这类的文章 发现有多处错误 故为了让刚想尝试爬虫的蜘蛛们少走点坑 故把最新的方法奉上 在此之前 请先更新你的pip版本 并安装scrapy pymysql pip inst
  • kernelbase.dll崩溃的处理_kernelbase.dll故障教程

    kernelbase dll是存放在windows系统下的一个非常重要的dll文件 DLL英文全称Dynamic Link Library 中文意思是 动态链接库 DLL是一个作为共享函数库的可执行文件 它使进程可以调用不属于本身可执行代码
  • java 代理模式

    1 静态代理 1 1 代码实现 接口 interface Hello String sayHello String str 实现 class HelloImp implements Hello Override public String