可以参看往期博客:网页链接
代理模式,是SpringAOP的低层实现
角色分析:
抽象角色: 一般会使用接口或抽象类来解决(租房接口)
真实角色: 被代理的角色(房东)
代理角色: 代理真实角色,代理真实角色后,我们一般会做一些附属操作(中介)
客户: 访问代理对象的人(租户)
代码实现:
// ------- 租房接口。代理对象与被代理对象,都实现这个接口 -------
public interface Rent {
void rent();
}
// ------- 房东,实现租房接口 -------
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东出租房子");
}
}
/**
* 代理对象
* 使用组合将被代理的对象,集合进来(尽量不适用继承)
*/
public class Proxy implements Rent {
Host host; //房东:被代理的对象
public Proxy(Host host) { //构造方法中,传入房东
this.host = host;
}
//中介代理房东出租房子,执行一些额外的操作
@Override
public void rent() {
watchHouse(); //额外操作1.租房子
host.rent();
charge(); //额外操作2.收中介费
}
private void watchHouse(){
System.out.println("中介带你看房");
}
private void charge(){
System.out.println("中介带你看房");
}
}
// ------------ 测试 -----------------
public static void main(String[] args) {
Host host = new Host(); //房东要出租房子
Proxy proxy = new Proxy(host); //中介代理房东,与租户打交道
proxy.rent(); //租户找中介,租房子
}
输出结果:
中介带你看房
房东出租房子
中介带你看房
总结:
代理模式的好处:
缺点
静态代理加深理解:
//1. ---------- 业务层的接口,增删改查方法 ----------
public interface IUserService {
public void add();
public void delete();
public void modify();
public void search();
}
//2. ------- 被代理的类:业务层具体实现 --------
public class UserService implements IUserService {
@Override
public void add() { System.out.println("新增方法"); }
@Override
public void delete() { System.out.println("删除方法"); }
@Override
public void modify() { System.out.println("修改方法"); }
@Override
public void search() { System.out.println("查询方法"); }
}
//3.-----代理类(与被代理类,实现同一个接口),实现日志功能
public class UserServiceProxy implements IUserService{
//被代理的类私有化,使用set方法注入
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
/**
* 在执行原业务逻辑之前,给每个方法添加上日志
*/
@Override
public void add() {
log("add");
userService.add();
}
@Override
public void delete() {
log("delete");
userService.delete();
}
@Override
public void modify() {
log("modify");
userService.modify();
}
@Override
public void search() {
log("search");
userService.search();
}
private void log(String msg){
System.out.println("log日志:调用了"+msg+"方法");
}
}
//4. ------------ 测试 -----------
public static void main(String[] args) {
//具体业务的实现类
UserService userService = new UserService();
//将业务实现类,注入到代理类
UserServiceProxy userServiceProxy = new UserServiceProxy();
userServiceProxy.setUserService(userService);
/*
通过代理类,调用业务处理方法:
在不修改业务处理类的情况下,添加日志
*/
userServiceProxy.add();
}
动态代理与静态代理,角色组成一样(抽象角色、真实角色、代理角色)
动态代理的代理类是动态生成的,不是我们写好的
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
动态代理两个重要的类:
- Proxy:代理(生成动态代理实例)
- InvocationHandler:调用处理程序(调用处理程序,并返回结果)
jdk18官方文档地址:JDK18API
InvocationHandler
java.lang.reflect Interface InvocationHandler:是由代理实例的 调用处理程序 实现的接口。每个代理实例,都有一个关联的调用处理程序。在代理实例上调用方法时,方法调用将被 编码并分派 到其调用处理程序的invoke方法
只有一个方法: Object invoke(Object proxy, Method method , Object[] args ) 作用:处理代理实例上的方法调用,并返回结果
Proxy类的方法,只有以下四个:
动态代理用到的方法:
//1.------------- 租房接口。代理对象与被代理对象,都实现这个接口 ------------
public interface Rent {
void rent();
}
//2.------------- 房东,实现租房接口 -------------
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东出租房子");
}
}
/**
* MyInvocationHandler:代理实例的调用处理程序,继承了InvocationHandler接口
* 用这个类,自动生成代理类(上面的UserServiceProxy 也是代理类)
*/
public class MyInvocationHandler implements InvocationHandler {
//1.被代理的接口:
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//2.生成代理类
public Object getProxy(){
/**
* ClassLoader loader //定义 代理类 的类加载器
* Class<?>[] interfaces //代理类 实现的接口列表
* InvocationHandler h //将方法调用分派到的 调用处理程序
*/
return Proxy.newProxyInstance(rent.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//3.处理代理程序,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//动态代理的本质,就是利用反射机制实现
Object result = method.invoke(rent, args);
charge();
return result;
}
private void seeHouse(){
System.out.println("中介带你看房子");
}
private void charge(){
System.out.println("收取中介费");
}
}
// ---------------------- 测试 ---------------------------
public static void main(String[] args) {
//1.真实角色
Host host = new Host(); //房东
//2.调用处理程序
MyInvocationHandler mih = new MyInvocationHandler();
//3.通过调用处理程序,处理我们要调用的【接口实现类对象】
mih.setRent(host);
//4.动态得到代理类,并强转为 Rent 接口类型:
// 这里的rentProxy就是动态生成的,并没有定义这个类(不像之前的 UserServiceProxy )
Rent rentProxy = (Rent) mih.getProxy();
//5.1 调用代理实例的 rent() 方法,
//5.2 被编码并转发到 调用处理程序(mih)的invoke方法上
rentProxy.rent();
}
输出结果:
中介带你看房子
房东出租房子
收取中介费
下面是动态代理的工具类,将被代理的接口,换成Object
/**
* 将被代理的接口(上面的Rent),换成Object。可以代理所有的Object子类
* 用这个类,自动生成代理类(上面的UserServiceProxy 也是代理类)
*/
public class DynamicInvocationHandler implements InvocationHandler {
//1.被代理的接口:
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//2.生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//3.处理代理程序,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是利用反射机制实现
printLog(method.getName());
Object result = method.invoke(target, args);
return result;
}
//日志方法
private void printLog(String msg){
System.out.println("执行了 "+msg+" 方法");
}
}
// ---------------------- 测试 ---------------------------
public static void main(String[] args) {
//万能代理类:
//1.真实对象
UserService userService = new UserService();
//2.调用处理程序
DynamicInvocationHandler dih = new DynamicInvocationHandler();
//3.通过调用处理程序,处理我们要调用的【接口实现类对象】
dih.setTarget(userService);
//4.动态得到代理类,并强转类型
// 只能转换成接口,不能强转成 实现类
IUserService proxy = (IUserService) dih.getProxy();
//5.通过代理类,执行方法
proxy.add();
proxy.delete();
}
输出结果:
执行了 add 方法
新增方法
执行了 delete 方法
删除方法
动态代理的好处:
- 具有静态代理的所有好处
- 一个动态代理类,代理的是一个接口。一般就是对应一类业务
- 一个动态代理类,可以代理多个类,只要实现了同一个接口
评论
登录后才可以进行评论哦!