【Spring】008-代理模式

tech2025-10-07  2

一、概述

1、重要性

为什么要学习代理模式?因为这就是SpringAOP的底层原理!

面试必问:Spring AOP 与 Spring MVC;

 

2、代理模式的分类

静态代理;

动态代理;

 

3、什么是代理模式

参考:【Java设计模式】001-代理模式

 

二、静态代理

1、角色分析

抽象角色:

一般会使用接口或抽象类来解决(比如:租房);

 

真实角色:

被代理的角色(比如:房东);

 

代理角色:

代理角色,代理真是角色后,一般会做一些附属操作(比如:租房中介);

 

客户:

访问代理对象的人(比如:租客);

 

2、代码实现

第一步:新建一个Moudle,创建房东与中介的公共租房接口

package com.zibo.demo01; //代理角色和被代理角色的公共接口,因为代理角色要帮被代理角色完成其需要做的事情 //出租接口,房东要出租房子,中介就要帮房东出租房子,所以出租房子这个事情是二者都要做的 //写一个公共接口使其二者都实现改接口,即可达到约束二者都做同一件事情的目的 public interface Rent { void rent(); }

第二步:创建房东类,实现租房接口

package com.zibo.demo01; //被代理对象——房东,房东只做一件事情,就是出租房子,其他啥都不想干 //房东实现出租接口 public class Landlord implements Rent { @Override public void rent() { System.out.println("房东将房子出租!"); } }

第三步:创建中介代理类,实现租房接口

package com.zibo.demo01; //代理角色,需要帮助被代理角色完成出租房子的事情 //中介肯定是要为房东出租房子的,所以必须和房东一起实现出租接口 //但是代理对象往往还有做一些其他附属操作,中介要做一些其他工作来完成房子出租的整个流程 public class Agent implements Rent { private Landlord landlord; public Agent() { } public Agent(Landlord landlord) { this.landlord = landlord; } @Override public void rent() { seeHouse(); landlord.rent(); signAContract(); charge(); } private void seeHouse(){ System.out.println("中介带租客看房子!"); } private void signAContract(){ System.out.println("中介与租户签合同!"); } private void charge(){ System.out.println("中介向租户收取中介费!"); } public Landlord getLandlord() { return landlord; } public void setLandlord(Landlord landlord) { this.landlord = landlord; } }

第四步:创建客户租房测试类

package com.zibo.demo01; //客户类,租户租房子去找中介租 public class User { public static void main(String[] args) { //实例化房东 Landlord landlord = new Landlord(); //实例化中介 Agent agent = new Agent(landlord); //通过中介租房子 agent.rent(); } }

测试结果:

中介带租客看房子! 房东将房子出租! 中介与租户签合同! 中介向租户收取中介费!

 

3、代理模式的好处

可以使真实角色(被代理角色)的业务更加纯粹;

公共业务交给代理代理角色,实现了业务分工;

公共业务发生扩展的时候,方便集中管理;

 

4、代理模式的缺点

一个真实角色(被代理角色)就会产生一个代理角色,代码量会翻倍!

 

三、深入静态代理

1、搭建环境

第一步:写一个UserService接口

package com.zibo.demo02; public interface UserService { void save(); void delete(); void update(); void query(); }

第二步:写一个UserService接口的实现类

package com.zibo.demo02; public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("保存了一个用户!"); } @Override public void delete() { System.out.println("删除了一个用户!"); } @Override public void update() { System.out.println("更新了一个用户!"); } @Override public void query() { System.out.println("查询了一个用户!"); } }

第三步:写客户端类进行测试

package com.zibo.demo02; public class Client { public static void main(String[] args) { UserService userService = new UserServiceImpl(); userService.save(); } }

测试结果:

保存了一个用户!

 

2、问个问题

假如我们要在各个方法执行的前后做一些事情,我们该怎么办?难道要在所有方法前后修改代码?如此:

package com.zibo.demo02; public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("保存用户前要做的事情"); System.out.println("保存了一个用户!"); System.out.println("保存用户后要做的事情"); } @Override public void delete() { System.out.println("删除用户前要做的事情"); System.out.println("删除了一个用户!"); System.out.println("删除用户后要做的事情"); } @Override public void update() { System.out.println("更新用户前要做的事情"); System.out.println("更新了一个用户!"); System.out.println("更新用户后要做的事情"); } @Override public void query() { System.out.println("查询用户前要做的事情"); System.out.println("查询了一个用户!"); System.out.println("查询用户后要做的事情"); } }

这岂不是很反人性!!!

忽然想起刚才演示的房东、中介和租客的代理模式,不由得我们心生一计!

 

3、正所谓:自己动手,丰衣足食

第一步:我们新建一个代理类UserAgent

package com.zibo.demo02; public class UserAgent implements UserService { private UserService userService; public UserAgent() { } public UserAgent(UserService userService) { this.userService = userService; } private void doSthBefore(){ System.out.println("在此之前做一些事情"); } private void doSthAfter(){ System.out.println("在此之后做一些事情"); } private void doSthAfter2(){ System.out.println("在此之后再做一些事情"); } @Override public void save() { doSthBefore(); userService.save(); doSthAfter(); doSthAfter2(); } @Override public void delete() { doSthBefore(); userService.delete(); doSthAfter(); doSthAfter2(); } @Override public void update() { doSthBefore(); userService.update(); doSthAfter(); doSthAfter2(); } @Override public void query() { doSthBefore(); userService.query(); doSthAfter(); doSthAfter2(); } }

第二步:将UserServiceImpl改回去

package com.zibo.demo02; public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("保存了一个用户!"); } @Override public void delete() { System.out.println("删除了一个用户!"); } @Override public void update() { System.out.println("更新了一个用户!"); } @Override public void query() { System.out.println("查询了一个用户!"); } }

第三步:修改测试类

package com.zibo.demo02; public class Client { public static void main(String[] args) { UserService service = new UserServiceImpl(); UserAgent agent = new UserAgent(service); agent.save(); } }

测试结果:

在此之前做一些事情 保存了一个用户! 在此之后做一些事情 在此之后再做一些事情

发生了什么:

我们在没有修改UserServiceImpl类的情况下,对UserServiceImpl类的功能进行了增强!

这就是AOP的底层原理!

 

四、动态代理

1、静态代理有一个很严重的缺点

一个真实角色(被代理角色)就会产生一个代理角色,代码量会翻倍!

 

怎么办:

既然静态代理一个真实角色都会产生一个代理角色,导致代码量翻倍,那么我们让每一个代理角色自动生成不就不会代码量翻倍了吗!

 

2、动态代理概述

①动态代理和静态代理角色一样;

②动态代理的代理类是动态生成的,不是直接写好的;

③动态代理分为两大类:基于接口的动态代理、基于类的动态代理;

基于接口:JDK动态代理(我们本次使用的); 基于类:cglib; java字节码:javasist;

 

3、需要了解两个类

Proxy类:

代理;

 

InvocationHandler类:

调用处理程序;

 

4、让我们来尝试一下实现动态代理

(我们在静态代理的代码上进行修改:租房案例)

第一步:写一个自动生成代理角色的类

package com.zibo.demo03; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; public class ProxyInvocationHandler implements InvocationHandler { //第一步:指定代理谁 private Object target; //无参构造 public ProxyInvocationHandler() { } //带参构造 public ProxyInvocationHandler(Object target) { this.target = target; } //第二步:生成代理对象 public Object getProxyObject(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } /** * 第三步:执行代理对象的方法 * @param proxy 代理对象(不可直接用没需用target) * @param method 所执行的方法 * @param args 给所执行的方法传的参数 * @return 返回执行结果 * @throws Throwable 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法执行之前可执行其他内容"); Object invoke = method.invoke(target, args); System.out.println("方法执行之后可执行其他内容"); return invoke; } }

第二步:修改User测试类

package com.zibo.demo03; //客户类,租户租房子去找中介租 public class User { public static void main(String[] args) { //实例化房东 Landlord landlord = new Landlord(); //生成代理对象:中介 ProxyInvocationHandler handler = new ProxyInvocationHandler(landlord); Rent rent = (Rent) handler.getProxyObject(); //使用代理对象 rent.rent(); } }

测试结果:

方法执行之前可执行其他内容 房东将房子出租! 方法执行之后可执行其他内容

备注:

自动生成代理角色的类不太好理解,可根据其中注释理解,另一方面,这个类的写法基本是固定的;

这就是AOP的底层原理!

 

 

 

 

 

 

 

 

最新回复(0)