Spring静态代理和动态代理代码详解
本节要点:
Java静态代理
Jdk动态代理
1 面向对象设计思想遇到的问题
在传统OOP编程里以对象为核心,并通过对象之间的协作来形成一个完整的软件功能,由于对象可以继承,因此我们可以把具有相同功能或相同特征的属性抽象到一个层次分明的类结构体系中。随着软件规范的不断扩大,专业化分工越来越系列,以及OOP应用实践的不断增多,随之也暴露了一些OOP无法很好解决的问题。
现在假设系统中有三段完全相似的代码,这些代码通常会采用“复制”、“粘贴”方式来完成,通过这种方式开发出来的软件如图所示:
可能读者已经发现了这种做法的不足之处,如果有一天,蓝色背景的代码需要修改,那是不是要同时修改三个地方?如果不仅仅是这三个地方包含这段代码,而是100个,甚至是1000个地方,那会是什么后果?
记录日志在代码中无处不在---先来看一个例子:
为了跟踪应用程序的运行过程,很多方法都需要记录日志信息。我们一般这样写:
//log4j的使用见文章“log4j介绍” import org.apache.log4j.Logger; public class Person { private Logger logger = Logger.getLogger(Person.class); public void sleep(){ logger.info(“开始执行时间:“ + new Date()); System.out.println("睡觉中"); logger.info(“执行结束时间:” + new Date()); } public void eating(){ logger.info("开始执行时间:“ + new Date()"); System.out.println("正在吃饭中"); logger.info("“执行结束时间:” + new Date()"); } }
提问:弊端在哪里?
l混淆了业务方法本身的职责
l维护工作量巨大
2解决方案1
静态代理:
1、需要知道核心类(被代理类)是哪一个类,并且有什么方法。
2、非核心的代码需要重复写多次,显得代码的结构臃肿,形成代码冗余。
3、非核心类(代理类)需要实现核心类(被代理类)实现的接口,也就是他们需要实现共同的接口,但是以核心类实现的接口(被代理类)为准。
l目地是将业务代码与日志代码完全分离,实现松散耦合.
l代理对象与被代理对象必须实现同一接口,在代理对象中实现与日志记录的相关服务,并在需要的时候呼叫被代理对象,而被代理对象只保留业务代码.
静态代理的实现
1)定义接口:
public interface IPerson { public abstract void sleep(); public abstract void eating(); }
2) 被代理类
public class Person implements IPerson { public void sleep(){ System.out.println("睡觉中"); } public void eating(){ System.out.println("正在吃饭中"); } }
3) 代理类
import org.apache.log4j.Logger; public class PersonProxy implements IPerson { private IPerson person; private Logger logger = Logger.getLogger(PersonProxy.class); public PersonProxy(IPerson person) { this.person = person; } public void eating() { logger.info("开始执行时间:“ + new Date()"); person.eating(); logger.info("“执行结束时间:” + new Date()"); } public void sleep() { logger.info("开始执行时间:“ + new Date()"); person.sleep(); logger.info("“执行结束时间:” + new Date()"); } }
4) 测试类
package com.aptech.aop2; public class PersonTest { public static void main(String[] args) { IPerson proxy = new PersonProxy(new Person()); proxy.eating(); proxy.sleep(); } }
静态代理的弊端:
一个代理接口只能服务于一种类型的对象.对于稍大点的项目根本无法胜任.
3 解决方案2-动态代理
InvocationHandler:每一个动态代理类都必须实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke方法来进行调用。
在JDK1.3之后加入了可协助开发的动态代理功能.不必为特定对象与方法编写特定的代理对象,使用动态代理,可以使得一个处理者(Handler)服务于各个对象.
一个处理者的类设计必须实现java.lang.reflect.InvocationHandler接口.
通过InvocationHandler接口实现的动态代理只能代理接口的实现类.
动态代理实现
1) 处理者(Handler)
public class DynaProxyHandler implements InvocationHandler { private Logger logger = Logger.getLogger(DynaProxyHandler.class); private Object target; //被代理对象 public void setTarget(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { logger.info("执行开始时间:" + new Date()); Object result = method.invoke(target, args); logger.info("执行结束时间:" + new Date()); return result; //返回method执行结果 } }
2) 生产代理对象的工厂
import java.lang.reflect.Proxy; public class DynaProxyFactory { //obj为被代理对象 public static Object getProxy(Object obj){ DynaProxyHandler handler = new DynaProxyHandler(); handler.setTarget(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler); } }
3) 测试类
public class PersonTest { public static void main(String[] args) { IPerson person = (IPerson) DynaProxyFactory.getProxy(new Person()); //返回代理类,代理类是JVM在内存中动态创建的,该类实现传入的接口数组的全部接口(的全部方法). person.eating(); person.sleep(); } }
总结
以上就是本文关于Spring静态代理和动态代理代码详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:
如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!
- 机器学习算法实现解析——libFM之libFM的模型处理部分
- Go语言使用protobuf数据通信--师出同门,懂的人理解吧
- 虚拟化平台cloudstack(6)——使用maven:jetty调试
- 虚拟化平台cloudstack(7)——新版本的调试
- 一行代码,Pandas秒变分布式,快速处理TB级数据
- 机器学习算法实现解析——word2vec源码解析
- 从零开始创建一个基于Go语言的web service
- 转--Golang项目邮件发送模块代码分享
- 虚拟化平台cloudstack(8)——从UI开始
- 使用oracle的大数据工具ODCH访问HDFS数据文件
- UWP基础教程 - XAML开篇
- UWP基础教程 - XAML依赖属性和附加属性
- GO语言学习:动态Web
- Golang 连接mssql sql server
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Chevereto——简介及安装
- Typecho开启伪静态并隐藏index.php
- Prism代码高亮Pjax重载函数
- Qt示例-AnalogClock-自定义窗体-使用QPainter的转换和缩放特性简化绘图
- 2019-12-27-traefik
- 2019-12-05-eck-qustion
- 聊聊dubbo-go的ConsumerSignFilter
- Javascript错误处理
- 程序员说模型过拟合的时候,说的是什么?
- 分分钟教会你搭建企业级的 npm 私有仓库
- Golang语言之字符串操作
- Go语言ORM-gorm学习笔记(二)
- TypeScript: 常用的高级类型
- TypeScript:得泛型者,得天下
- 微信PC端多开的秘密