代理模式

  • AOP的实现机制利用代理实现业务拓展
  • 代码:Spring-08-demo2-demo4

image-20230414152026957


静态代理

角色分析:

  • 抽象角色:一般使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操纵
  • 客户:访问代理对象的人


代理步骤:

1.接口

//租房
public interface Rent {
public void rent();
}

//2
public interface UserService {
public void add();
public void delete();
public void update();
public void query();

}

2.真实角色

//房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租");
}
}

//2
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加了一个用户");
}

@Override
public void delete() {
System.out.println("删除了一个用户");
}

@Override
public void update() {
System.out.println("修改了一个用户");
}

@Override
public void query() {
System.out.println("查询了一个用户");
}

}

3.代理角色

//1
public class Proxy implements Rent{
private Host host;

public Proxy() {
}

public Proxy(Host host) {
this.host = host;
}

@Override
public void rent() {
host.rent();
seeHouse;
fare;
hetong;
}

//看房
public void seeHouse(){
System.out.println("中介带你看房");
}

//收中介费
public void fare(){
System.out.println("收中介费");
}

//签租赁合同
public void hetong(){
System.out.println("签租赁合同");
}
}



//2
public class UserServiceProxy implements UserService{

private UserServiceImpl userService;

public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}

@Override
public void add() {
log("add");
userService.add();


}

@Override
public void delete() {
log("delete");
userService.delete();
}

@Override
public void update() {
log("update");
userService.update();
}

@Override
public void query() {
log("query");
userService.query();
}

//日志方法
public void log(String msg){
System.out.println("使用了"+msg+"方法");
}
}

4.客户端访问代理角色

//1
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色。会有附属操作
Proxy proxy = new Proxy(host);

//找代理角色
proxy.rent();
}
}


//2
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();

UserServiceProxy proxy =new UserServiceProxy();
proxy.setUserService(userService);
proxy.add();
}
}


代理模式的好处:

  • 可以使真实角色的操作更加纯粹! 不用去关注一些公共的业务
  • 公共业务就交给角色! 实现业务分工
  • 公共业务发生拓展的时候,方便集中管理

缺点:

  • 一个真实角色就会产生一个代理角色; 代码量翻倍 ~ 开发效率会变低





动态代理 – (底层:反射)

  • 动态代理角色和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的!
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口 – JDK 代理 [使用]
    • 基于类:cglib
    • java字节码实现:JAVAssist

需要了解两个类: Proxy 代理 , InvocationHdandler


动态代理的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
  • 公共也就就交给代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务

image-20231008195249580


复用静态代理代码2

  • 动态代理类
//使用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {

//被代理的接口
private Object target;

public void setTarget(Object target) {
this.target = target;
}

//生成得到代理类
public Object getProxy(){
// (类的位置、 哪个接口, InvocationHandler:会自己调用invoke方法);
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}

//处理代理实例,返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是使用反射机制
Object result = method.invoke(target, args);//调用被代理类的方法
logcc(method.getName());//代理角色的附加方法,反射获取被代理角色的方法名称
return result;
}

public void logcc(String msg){
System.out.println("执行了"+msg+"方法");
}

}

  • 实现类
public class Client {
public static void main(String[] args) {

//真实角色
UserServiceImpl userService=new UserServiceImpl();

//代理角色,当前不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();

//通过调用程序处理角色来处理我们要调用的接口对象!
pih.setTarget(userService);//设置要代理的对象

//动态生成代理类
UserService proxy = (UserService) pih.getProxy();

proxy.add();//调用真实角色的方法,代理角色附加的方法自动运行
}

}


例子

  • 接口
public interface Start {

String sing(String name);
void dance();
}

  • 被代理角色
package com.chen.Proxy;

public class BigStart implements Start{

private String name;

public BigStart() {
}

public BigStart(String name) {
this.name = name;
}

@Override
public String sing(String name) {
System.out.println(this.name + " 正在唱 "+name);
return "执行跳舞";
}

@Override
public void dance() {
System.out.println(this.name + " 正在跳舞");
}


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}

  • 代理角色
//创建一个代理
public class ProxyUtil {
/**
* 方法的作用:
* 给一个明星的对象,创建一个代理
* 形参:被代理的明星对象
* 返回值:给明星创建的代理
*/
public static Start createProxy(BigStart bigStart){

/**
* 参数一:用于指定用哪个类加载器,去加载生成的代理类
* 参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法 (代理的接口,被代理的对象也要实现这个接口)
* 参数三:用来指定生成的代理对象要干什么事情
*/
Start start = (Start) Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(),
new Class[]{Start.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* 参数一:代理的对象
* 参数二:要运行的方法
* 参数三:调用方法时,传递的实参
*/

//==============代理角色的附加动作
if (method.getName().equals("sing")){
System.out.println("代理角色的附加操作:准备话筒");

}else if (method.getName().equals("dance")){
System.out.println("代理角色的附加操作:准备舞台");

}

//============调用被代理角色
return method.invoke(bigStart,args); //根据方法,进入对象查找,传递参数
}
}
);
return start;
}
}


  • Test
BigStart bigStart = new BigStart("坤坤");
Start proxy = ProxyUtil.createProxy(bigStart);
String singing = proxy.sing("太美");
proxy.dance();
System.out.println(singing);


image-20231008201810501