动态代理模式详解
代理模式
代理模式的好处
- 可以使真是角色的操作更加纯粹!不用去关注一些公共的业务
- 公共也就是交给代理角色,实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
缺点
- 一个真是的角色会产生一个代理觉得:代码量翻倍,开发效率降低
下面用房子出租案例说明代理模式
房东出租房子,真实角色比如(你)要租房子,房东出租房子要贴广告啊,发布信息啊,找到租户之后还要谈价格签合同啊,房东作为包租婆太懒了,这点小活都不愿意干,于是,她把这个任务交给你了中介,让中介来帮他寻找需要租房子的客户等等一些杂七杂八的活,而他只需要在家吃着西瓜追剧就行啦。而真实客户呢,要想要租房,那就必须得跟中介谈。
少废话直接上代码
先来一个Rent接口,因为各方都需要租房这个业务,面向接口编程啦
public interface Rent {
public void rent();
}
房东要出租了,中介你帮我骗几个大学生过来租房子
public class Host implements Rent {
public void rent(){
System.out.println("我要出租房子");
}
中介想要挣钱,必须要收中介费,不然我干嘛要帮你干活
public class Proxy implements Rent {
private Host host;
public Proxy(){
}
public Proxy(Host host){
this.host=host;
}
public void rent(){
host.rent();
seeHouse();
goodHouse();
heTong();
proxyMoney();
}
public void seeHouse(){
System.out.println("带你去看房子!");
}
public void goodHouse(){
System.out.println("这个房子好啊~");
}
public void heTong(){
System.out.println("签立合同!");
}
public void proxyMoney(){
System.out.println("你要交中介费");
}
}
你要租房
public class Client {
public static void main(String[] args) {
//代理模式
Host host=new Host();
Proxy proxy=new Proxy(host);
proxy.rent();
}
}
看到这里相信你对代理模式有点熟悉了吧,接下来用一个业务的代码带你再次了解静态代理的思路
- 假如有一个实现了增删改查的业务代码,现基础上要添加一个log4j的功能,要求不能改动原有的业务代码。这时候就能发挥到静态代理的功能性了
- 啥也别说了,上代码
老套路,来一个接口,然后实现它
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
实现增删改查的功能
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("add");
}
public void delete() {
System.out.println("delete");
}
public void update() {
System.out.println("update");
}
public void select() {
System.out.println("select");
}
}
重点来了,这时候要扩展一个新的功能,不能改变原来的业务代码,就得用代理
public class UserServicePrexy implements UserService{
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add() {
log4j("add");
userService.add();
}
public void delete() {
userService.delete();
}
public void update() {
userService.update();
}
public void select() {
userService.select();
}
public void log4j(String mes ){
System.out.println("使用了"+mes+"方法");
}
}
添加了一个log4j日志功能,原来的UserServiceImpl没有改动代码
实例
public class Client {
public static void main(String[] args) {
UserServiceImpl userService=new UserServiceImpl();
UserServicePrexy userServicePrexy=new UserServicePrexy();
userServicePrexy.setUserService(userService);
userServicePrexy.add();
}
}
到这里就很清楚的明白代理模式的思路了吧。
总结一下:
- 代理模式可以使真是角色的操作更加纯粹!不用去关注一些公共的业务
- 公共也就是交给代理角色,实现了业务的分工
- 代理是一种设计的思想,提供了间接对目标对象进行访问的方式;即通过代理访问目标对象,可以在目标对象中进行实现功能,增加额外的功能,扩展性高,符合了设计模式的开闭原则,即是在对原有的代码不改动下,进行功能扩展
说完了静态代理,我们来说说动态代理
*上面说了静态代理有一个缺点:
一个真是的角色会产生一个代理觉得:代码量翻倍,开发效率降低
能不能实现一个更好的代理模式呢?既能满足功能的扩展还能使得开发效率高效呢?这时候动态代理出现了~~~
动态代理
-
动态代理和静态代理角色是一样的
-
动态代理的代理类是动态生成的,不是我们自己写好的
-
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
-
基于接口-----jdk 动态代理
-
基于类:cglib
动态代理的实现有很多种 但是思想都是一样的,这里我们用的是基于接口实现的 ---jdk动态代理实现
-
基于接口实现代理,要用到两个核心类:Proxy : 代理类 InvocationHandler :调用处理程序
InvocationHandler 是java.lang.refect下的类。是由代理实例的,调用处理程序实现的接口。每个代理实例都有一个关联的调用处理程序,当代理实例上调用方法时,方法调用将编码并分派其调用处理程序的invoke方法。也就是说我们要实例一个代理类,要先实现这个接口,这接口能动态帮我们生成代理类
话不多说,上代码
老样子,接口
public interface Rent {
public void rent();
}
实现接口
public class Host implements Rent{
public void rent() {
System.out.println("我要出租房子");
}
}
实现InvocationHandler 类,用这个类能够帮我们动态生成代理
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
//处理代理类的实例,返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result= method.invoke(target,args);
return result;
}
}
测试
public class Client {
public static void main(String[] args) {
//被代理的类
Host host=new Host();
//ProxyInvocationHandler类并不是代理类,它只是一个能够动态生成代理类的工具
ProxyInvocationHandler proxyInvocationHandler=new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口
proxyInvocationHandler.setTarget(host);
//返回代理类,这里getProxy()才是真正的创建出代理类
Rent proxy =(Rent) proxyInvocationHandler.getProxy();
proxy.rent();
}
}
总结
-
动态代理是由jdk api帮我们动态实现代理类的
-
动态代理类可以使真是角色的操作更加纯粹,不用关注一些公共业务。
---来自B站狂神的学习---
https://www.bilibili.com/video/BV1mc411h719?p=11