1、代理模式
-
定义:
给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
就好像房东想要出租房子,他让中介帮忙找租客,带看,签合同,房东只需要把房子挂出去表示出租就行了
-
为什么要使用代理模式?
-
中介隔离作用:
-
在某些情况下,一个客户不想或者不能去直接访问真实角色,代理角色就能在中间起到一个桥梁连接的作用,前提条件是真实角色委托了代理角色,他们实现相同的接口,有共同的目标。
-
-
开闭原则:
-
代理角色还可以增加额外的功能,这样做我们只需要修改代理角色类而不需要再修改真实角色类,符合代码设计的开闭原则
-
代理角色类主要负责为真实角色类【预处理消息、过滤消息、把消息转发给真实角色,以及事后对返回结果的处理等】
-
代理角色类本身并不真正实现服务,而是同过调用真实角色类的相关方法,来提供特定的服务。真正的业务功能还是由真实角色类来实现,但是可以在业务功能执行的前后加入一些公共的服务,如:缓存、日志这些功能,在代理角色类中编写,不用打开封装好的真实角色类。
-
-
2、静态代理
-
定义:
静态代理是由程序员创建或特定工具自动生成源代码,在对其编译。在程序员运行之前,代理类.class文件就已经被创建了
-
示例一:租房
-
Rent(租房事件)
public interface Rent {
public void rent();
} -
Host(房东:出租房子)
public class Host implements Rent {
public void rent() {
System.out.println("房东出租房子!");
}
} -
HousingAgency(房产中介:代理房东租房子)
public class HousingAgency implements Rent {
public Host host;
////通过构造方法实现房东与中介的委托代理
public HousingAgency(Host host) {
this.host = host;
}
public void rent() {
host.rent();
signContract();
seeHouse();
agencyFee();
}
public void signContract() {
System.out.println("签合同");
}
public void seeHouse() {
System.out.println("中介带看");
}
public void agencyFee() {
System.out.println("中介收取中介费");
}
} -
Tenant(租客:租房子)
public class Tenant {
public static void main(String[] args) {
//实例化一个房东,生成委托对象
Host host = new Host();
//房产中介代理房东出租房子
HousingAgency agency = new HousingAgency(host);
/*
租客通过中介租房子,中介也可以实现其他的功能
输出结果:
房东出租房子!
签合同
中介带看
中介收取中介费
*/
agency.rent();
}
}
-
-
示例二:使用静态代理实现日志功能
-
UserService
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
} -
UserServiceImpl
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 query() {
System.out.println("实现了query方法");
}
} -
UserServiceProxy
public class UserServiceProxy implements UserService {
private UserServiceImpl userService;
//通过set方法实现userServiceImpl的委托代理
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add() {
log("add");
userService.add();
}
public void delete() {
log("delete");
userService.delete();
}
public void update() {
log("update");
userService.update();
}
public void query() {
log("query");
userService.query();
}
public void log(String msg) {
System.out.println("[DEBUG] 调用了" + msg + "方法");
}
} -
Client
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);
/*
输出结果:
[DEBUG] 调用了add方法
实现了add方法
*/
proxy.add();
/*
输出结果:
[DEBUG] 调用了query方法
实现了query方法
*/
proxy.query();
}
}
-
-
优点:
-
可以使真实角色的操作更加纯粹,不用去关注公共业务
-
代理角色负责公共业务,分工更加明确
-
公共业务发生扩展的时候,方便集中管理
-
-
缺点:
-
一个真实角色就会产生一个代理角色,代码量会增加,开发效率降低。
-
3、动态代理
-
定义:
动态代理是在程序运行时通过反射机制动态创建的
-
类别:
-
基于接口的,JDK动态代理
-
Proxy
-
InvocationHandler
-
-
基于类的
-
cglib
-
-
Java字节码实现
-
javaSsist
-
-
-
示例一:租房
-
Rent
public interface Rent {
public void rent();
} -
Host
public class Host implements Rent {
public void rent() {
System.out.println("房东出租房子!");
}
} -
ProxyInvocationHandler(代理调用处理程序)
//这是个可以自动生成代理类的类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的类
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类
//第一个参数获得类加载器,
//第二个参数获得被代理类的接口
//第三个参数是InvocationHandler,因为这个类实现了InvocationHandler,所以可以是它本身
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//用反射机制来实现动态代理的本质
Object result = method.invoke(rent, args);
signContract();
seeHouse();
agencyFee();
return result;
}
public void signContract() {
System.out.println("签合同");
}
public void seeHouse() {
System.out.println("中介带看");
}
public void agencyFee() {
System.out.println("中介收取中介费");
}
} -
Tenant
public class Tenant {
public static void main(String[] args) {
Host host = new Host();
ProxyInvocationHandler proxyIH = new ProxyInvocationHandler();
/*
每个代理实例都有一个关联的调用处理程序,
当在代理实例上调用方法时,方法调用将被编码并且分配到其调用处理程序的invoke方法。
通过调用处理程序来处理我们要调用的接口对象
*/
proxyIH.setRent(host);
//动态生成代理角色
Rent proxy = (Rent) proxyIH.getProxy();
//代理角色去做业务
proxy.rent();
}
}
-
-
示例二:使用动态代理实现日志功能
-
UserService
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
} -
UserServiceImpl
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 query() {
System.out.println("实现了query方法");
}
} -
ProxyInvocationHandler
//这是个可以自动生成代理类的工具类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的类
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成代理类
//第一个参数获得类加载器,
//第二个参数获得被代理类的接口
//第三个参数是InvocationHandler,因为这个类实现了InvocationHandler,所以可以是它本身
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//用反射来获取执行方法的名字
log(method.getName());
//用反射机制来实现动态代理的本质
Object result = method.invoke(target, args);
return result;
}
public void log(String msg) {
System.out.println("[DEBUG] 执行了" + msg + "方法!");
}
} -
Client
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
ProxyInvocationHandler proxyIHandler = new ProxyInvocationHandler();
//设置要代理的对象
proxyIHandler.setTarget(userService);
//动态生成代理类
UserService proxy = (UserService) proxyIHandler.getProxy();
proxy.delete();
}
}
-
-
优点:
-
可以使真实角色的操作更加纯粹,不用去关注公共业务
-
代理角色负责公共业务,分工更加明确
-
公共业务发生扩展的时候,方便集中管理
-
一个动态代理类代理的是一个接口,一般对应的就是一类业务
-
-