Spring框架详解(三)

2023-11-05

一、代理模式

  • 代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象,这样做的好处就是,可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能
  • 被代理对象可以是远程对象,创建开销大的对象或者是需要安全控制的对象
  • 代理模式有不同的形式,主要形式包括:静态代理,JDK动态代理,Cglib动态代理
  • 代理模式示意图:

1. 静态代理

静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者继承相同父类。

应用步骤:

  • 定义一个接口:ITeacherDao
  • 被代理对象/目标对象TeacherDao实现接口ITeacherDao
  • 使用静态代理方式,就需要在代理对象TeacherDaoProxy中实现接口ITeacherDao
  • 调用的时候通过调用代理对象的方法来调用被代理对象/目标对象

注意:代理对象与被代理对象/目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法。

类图:

定义一个接口:ITeacherDao

package com.csu.marden.staticproxy;

public interface ITeacherDao {
	public void teach();
}

被代理对象/目标对象TeacherDao实现接口ITeacherDao

package com.csu.marden.staticproxy;

public class TeacherDao implements ITeacherDao{

	@Override
	public void teach() {
		System.out.println(" 老师授课中... ");
		
	}
}

使用静态代理方式,就需要在代理对象TeacherDaoProxy中实现接口ITeacherDao

package com.csu.marden.staticproxy;

public class TeacherDaoProxy implements ITeacherDao{
	
	//目标对象,通过接口来聚合
	private ITeacherDao target;
	
	//构造器,将目标对象传入到代理对象
	public TeacherDaoProxy(ITeacherDao target) {
		this.target = target;
	}
	
	
	@Override
	public void teach() {
		System.out.println(" 代理开始... ");
		target.teach();
		System.out.println(" 代理结束... ");
	}

}

调用的时候通过调用代理对象的方法来调用被代理对象/目标对象

package com.csu.marden.staticproxy;

public class Client {
	public static void main(String[] args) {
		//创建被代理对象/目标对象
		ITeacherDao target=new TeacherDao();
		//创建代理对象,同时将被代理对象传入到代理对象中
		ITeacherDao proxy=new TeacherDaoProxy(target);
		//通过代理对象,调用被代理对象的方法
		proxy.teach();
	}
}

静态代理优缺点:

优点:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展

缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类;而且一旦接口增加新的方法,目标对象与代理对象都要维护


2. JDK动态代理

动态代理中的代理对象不需要实现接口,但是目标对象需要实现接口,否则无法使用动态代理。

代理对象的生成,是利用JDK的API,动态地在内存中构建代理对象

JDK动态代理也叫接口代理

JDK中生成代理对象的API:(一个Proxy类和一个InvocationHandler接口)

(1)Proxy类:代理类所在的包:java.lang.reflect.Proxy,该类用于动态生成代理对象,只需要传入目标接口目标接口的类加载器以及InvocationHandler,便可为目标接口生成代理类以及代理对象

(2)Proxy中的newProxyInstance方法,该方法需要接收三个参数:

static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
//第一个参数:用哪个类加载器去加载代理对象,定义了由哪个classloader对象对生成的代理类进行加载
//第二个参数:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法
//第三个参数:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用

(3)InvocationHandler接口:是proxy代理对象的调用处理程序实现的一个接口,每一个proxy代理对象都有一个关联的调用处理程序;在代理对象调用方法时,方法调用被编码分派到调用处理程序的invoke方法。每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的对象都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法的时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用
(4)InvocationHandler接口中的invoke方法,该方法需要接收三个参数:

public Object invoke(Object proxy, Method method, Object[] args)
//第一个参数:代理类代理的目标对象
//第二个参数:我们所要调用某个对象真实的方法的Method对象
//第三个参数:指代代理对象方法传递的参数

实例:将上述静态代理改写为JDK动态代理

类图:

定义一个接口:ITeacherDao

package com.csu.marden.jdkdynamicproxy;

public interface ITeacherDao {
	public void teach();

}

被代理对象/目标对象TeacherDao实现接口ITeacherDao

package com.csu.marden.jdkdynamicproxy;

public class TeacherDao implements ITeacherDao{

	@Override
	public void teach() {
		System.out.println(" 老师授课中... ");
	}

}

使用动态代理方式,生成目标对象的代理对象

package com.csu.marden.jdkdynamicproxy;

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

public class ProxyFactory {
	//维护一个目标对象target
	private Object target;
	
	//构造器,将目标对象传入
	public ProxyFactory(Object target) {
		super();
		this.target = target;
	}
	
	//给目标对象生成一个代理对象
	public Object getProxyInstance(){
		//public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
		//参数说明:
		//第一个参数:ClassLoader loader:指定当前目标对象使用的类加载器
		//第二个参数:Class<?>[] interfaces:目标对象实现的接口(数组形式)
		//第三个参数:InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器方法,会把当前执行的目标对象的方法作为参数传入
		return Proxy.newProxyInstance(target.getClass().getClassLoader(),
									target.getClass().getInterfaces(),
									new InvocationHandler() {
										@Override
										public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
											System.out.println(" JDK代理开始... ");
											//通过反射机制调用目标对象的方法
											Object returnValue =method.invoke(target, args);
											System.out.println(" JDK代理结束... ");
											return returnValue;
										}
									});
	}


}

调用的时候通过调用代理对象的方法来调用被代理对象/目标对象

package com.csu.marden.jdkdynamicproxy;

public class Client {
	public static void main(String[] args) {
		//创建目标对象
		ITeacherDao target=new TeacherDao();
		//给定目标对象,创建代理对象
		ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(target).getProxyInstance();
		
		//内存中动态生成了代理对象
		System.out.println(proxyInstance.getClass());
		
		//通过代理对象,调用目标对象的方法
		proxyInstance.teach();
	}

}

参考链接:

https://blog.csdn.net/yaomingyang/article/details/80981004

https://blog.csdn.net/yaomingyang/article/details/81040390


3. Cglib代理(可以在内存动态地创建对象,而不需要实现接口)

静态代理和JDK动态代理都要求目标对象实现一个接口,但是有的时候,目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可以使用目标对象子类来实现代理,这就是Cglib代理

Cglib代理也叫子类代理,它是在内存中构建一个子类对象,从而实现对目标对象功能扩展

Cglib是一个强大的高性能的代码生成包,其底层是通过使用字节码处理框架ASM来转换字节码并生成新的类,它可以在运行期扩展Java类,实现Java接口,它广泛的被许多AOP框架使用,例如Spring AOP,用以提供方法拦截操作

在AOP变成中如何选择代理模式:目标对象需要实现接口,用JDK代理;目标对象不需要实现接口,用Cglib代理

使用步骤:

引入Cglib的jar包

类图:

被代理对象/目标对象TeacherDao

package com.csu.marden.cglibdynamicproxy;

public class TeacherDao {
	public void teach(){
		System.out.println(" 老师授课中... ");
	}

}

使用Cglib动态代理方式,生成目标对象的代理对象

package com.csu.marden.cglibdynamicproxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class ProxyFactory implements MethodInterceptor{
	
	//维护一个目标对象
	private Object target;
	
	//构造器,将目标对象传入
	public ProxyFactory(Object target) {
		this.target = target;
	}
	
	//返回一个代理对象,即target对象的代理对象
	public Object getProxyInstance(){
		//1.创建一个工具类
		Enhancer enhancer=new Enhancer();
		//2.设置父类
		enhancer.setSuperclass(target.getClass());
		//3.设置回调函数
		enhancer.setCallback(this);
		//4.创建子类对象,即代理对象
		return enhancer.create();
	}
	
	
	//重写intercept方法,会调用目标对象的方法
	@Override
	public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
		System.out.println(" Cglib代理开始... ");
		Object returnValue=method.invoke(target, arg2);
		System.out.println(" Cglib代理结束... ");
		return returnValue;
	}

	

}

调用的时候通过调用代理对象的方法来调用被代理对象/目标对象

package com.csu.marden.cglibdynamicproxy;

public class Client {
	public static void main(String[] args) {
		//创建目标对象
		TeacherDao target=new TeacherDao();
		//获取到代理对象,并且将目标对象传递给代理对象
		TeacherDao proxy = (TeacherDao) new ProxyFactory(target).getProxyInstance();
		//执行代理对象的方法,出发intecept方法,从而实现对目标对象的调用
		proxy.teach();
	} 
	

}

总结:JDK动态代理和Cglib代理的区别

(1)JDK动态代理只能够对接口进行代理,不能对普通的类进行代理;而Cglib动态代理可以代理普通类

(1)JDK动态代理使用Java原生的反射API进行操作,在生成类上比较高效;而Cglib动态代理使用ASM框架直接对字节码进行操作,在类的执行过程中比较高效


二、AOP

1.基本概念

AOP(Aspect Oriented Programming),面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP的通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

使用登陆案例说明AOP:原有的登陆流程通过获取用户输入的用户名和密码,与数据库中已有信息进行比对,如果比对结果不一致,则登陆失败,返回登陆页面;如果比对结果一致,则登陆成功,进入系统主页面。要想在原有的功能基础上添加权限判断功能,原始的方式是通过修改源代码实现。现在想要不修改源代码,并且添加新的功能,就使用AOP技术。

2.AOP底层原理

AOP底层使用动态代理,有两种情况的动态代理:

第一种:有接口的情况,使用JDK动态代理(创建接口实现类代理对象,增强类的方法

第二种情况:没有接口的情况,使用Cglib动态代理(创建子类的代理对象,增强类的方法)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring框架详解(三) 的相关文章

随机推荐

  • 那么多的数据可视化图表,你选对了吗?

    作者 邻川 程序员懂画图 一宝变三宝 本期 菜鸟国际物流技术部高级开发工程师邻川将分享他在数据可视化图标方面的积累 常听到一句话 能用图描述的就不用表 能用表就不用文字 这句话也直接的表明了 在认知上 大家对于图形的敏感度远比文字高 但同时
  • 自定义ViewGroup--浮动标签的实现

    前面在学习鸿洋大神的一些自定义的View文章 看到了自定义ViewGroup实现浮动标签 初步看了下他的思路以及结合自己的思路完成了自己的浮动标签的自定义ViewGroup 目前实现的可以动态添加标签 可点击 效果图如下 1 思路 首先在o
  • Spring AOP报错之通配符的匹配很全面, 但无法找到元素 'aop:config' 的声明

    问题 配置完aop后 运行时报错 如下 Library Java JavaVirtualMachines jdk1 8 0 111 jdk Contents Home bin java ea Didea launcher port 7534
  • 2021年网络空间安全学院预推免面试经验总结

    2021年网络空间安全学院预推免面试经验总结 建议 结合学科评估 跟着自己的判断走 https www dxsbb com news 1797 html https www zhihu com question 19825429 answe
  • 精品微信小程序ssm校友录网站+后台管理系统

    博主介绍 在职Java研发工程师 专注于程序设计 源码分享 技术交流 专注于Java技术领域和毕业设计 温馨提示 文末有 CSDN 平台官方提供的老师 Wechat QQ 名片 项目名称 精品微信小程序ssm校友录网站 后台管理系统 演示视
  • 【网络编程】传输层协议——UDP协议

    文章目录 一 传输层的意义 二 端口号 2 1 五元组标识一个通信 2 2 端口号范围划分 2 3 知名端口号 2 4 绑定端口号数目问题 2 5 pidof netstat命令 三 UDP协议 3 1 UDP协议格式 3 2 如何理解报头
  • TortoiseGit如何迁移项目地址

    大家工作中可能会遇到项目迁服务器 那么在以前老服务器上的git项目也需要迁到新服务器 如果大家使用TortoiseGit 那么该如何迁移呢 很简单 一 首先在新服务器git上建个项目 然后把项目地址复制下来 二 在本地项目里找到 git文件
  • 你需要知道的企业网页制作流程

    企业网页制作是企业建立线上形象和宣传的重要手段之一 它不仅可以提高企业的品牌知名度 还可以扩大企业的影响力和拓展客户群 下面 我们将介绍一些企业网页制作的基本流程和技巧 并结合一个案例来详细解析 企业网页制作的基本流程可以分为以下几个步骤
  • Android自定义View(三) Scroller与平滑滚动

    目录 一 什么是Scroller 二 认识scrollTo和scrollBy方法 2 1 scrollTo scrollBy对View内容的影响 2 2 思考为什么移动负数距离会向坐标正方向移动 2 3 scrollTo scrollBy对
  • 预训练网络的模型微调方法

    是什么 神经网络需要数据来训练 从数据中获得信息 进而转化成相应的权重 这些权重能够被提取出来 迁移到其他的神经网络中 迁移学习 通过使用之前在大数据集上经过训练的预训练模型 我们可以直接使用相应的结构和权重 将他们应用在我们正在面对的问题
  • python字符串去重_Python对字符串实现去重操作的方法示例

    前言 最近在工作经常会碰到对字符串进行去重操作 下面就给大家列出用Python如何处理的 话不多说了 来一起看看详细的介绍吧 比如说 要拿下面的字符传去掉重复的AA A B C S AA BB EE DD AA A B C CC A B C
  • chatgpt赋能python:用Python根据IP地址查找具体地址:一个实用的SEO技巧

    用Python根据IP地址查找具体地址 一个实用的SEO技巧 在数字化时代 IP地址是一个重要的数字标识符 使用IP地址来发现目标受众的位置是网络营销和搜索引擎优化策略的重要组成部分 在本文中 我们将介绍用Python编程语言根据IP地址查
  • 前端页面无法渲染两个Google Translate插件

    在w3c官方给出的demo里尝试了一下 无论添加几个Google Translate标签 始终只会渲染首个Google Translate标签 需要在script标签里添加一下代码 即可解决
  • python人工智能项目开发实例-人工智能学习路线图,整理近200个实战案例与项目...

    Created by 唐宇迪 人工智能实战就业 面试 学习路线图 这个项目是干什么的 整理这个项目的初衷是方便同学们快速开启人工智能自学计划 在学习过程中少走弯路用最快的效率入门Ai并开始实战项目 提供了近200个Ai实战案例和项目 这些并
  • geth指定版本安装

    下载源码 cd usr local git clone https github com ethereum go ethereum git 或者 mirror git clone https ghproxy com https github
  • TRC-20合约

    pragma solidity 0 5 0 import IERC20 sol import SafeMath sol dev Implementation of the IERC20 interface This implementati
  • List从服务器取文件名乱码,急用!!!为什么list程序输出会乱码??

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 window 15 2 78 23 textbackground LIGHTGREEN textcolor LIGHTMAGENTA clrscr gotoxy 1 3 printf Delet
  • Android学习笔记(一)——Activity基础知识

    Activity基础知识 Activity 活动 是一种可以包含用户界面的组件 一个应用程序可以包含多个活动 Android项目中逻辑和试图分离 每个活动最好对应一个布局 布局是用来显示界面内容的 Activity和布局文件如何关联起来 在
  • PyTorch基础-交叉熵函数mnist数据集识别-04

    交叉熵 代码 import numpy as np import torch from torch import nn optim from torch autograd import Variable from torchvision i
  • Spring框架详解(三)

    一 代理模式 代理模式 为一个对象提供一个替身 以控制对这个对象的访问 即通过代理对象访问目标对象 这样做的好处就是 可以在目标对象实现的基础上 增强额外的功能操作 即扩展目标对象的功能 被代理对象可以是远程对象 创建开销大的对象或者是需要