为什么要学习代理模式?因为这就是Spring AOP的底层机制!【Spring AOP 和 Spring MVC】
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
通俗的来讲代理模式就是我们生活中常见的中介。
代理模式的分类:
在学习AOP之前 , 我们要先了解代理模式!
真实案例:租房
静态代理角色分析:
静态代理具体实现步骤:
抽象的接口
// 租房的接口
public interface Rent {
// 房屋出租的方法
void rent();
}
真实对象
// 房东是真实的对象
public class Landlord implements Rent {
@Override
public void rent() {
// 房东需要出租房子
System.out.println("房东要出租房子");
}
}
代理对象
// 房屋中介就是代理对象
public class Proxy implements Rent {
// 中介可以找到房东
private Landlord landlord;
public Proxy() {
}
public Proxy(Landlord landlord) {
this.landlord = landlord;
}
// 代理对象提供出租房屋的方法
@Override
public void rent() {
// 在出租房屋时,添加一些自己的方法
this.seeHouse();
// 代理调用房东的出租房屋方法
landlord.rent();
this.fare();
}
//看房
private void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
private void fare(){
System.out.println("收中介费");
}
}
客户端
public class Client {
public static void main(String[] args) {
// 房东要出租房屋
Landlord landlord = new Landlord();
// 房屋中介帮房东出租房屋
Proxy proxy = new Proxy(landlord);
// 客户找到房屋中介租房
proxy.rent();
// 整个过程,客户不用接触房东,而是房屋中介找到房东
}
}
分析:在这个过程中,你直接接触的就是中介,就如同现实生活中的样子,你看不到房东,但是你依旧租到了房东的房子通过代理,这就是所谓的代理模式。程序源自于生活,所以学编程的人,一般能够更加抽象的看待生活中发生的事情。
静态代理模式的优点:
缺点:
使用代理,实现我们平时写的增删改查。
编写的一个抽象角色UserService
// 抽象角色,增删改查
public interface UserService {
void insert();
void delete();
void update();
void query();
}
编写一个真实的对象UserServiceImpl实现UserService
// 真实的对象,实现了增删改查方法
public class UserServiceImpl implements UserService {
@Override
public void insert() {
System.out.println("新增一个用户");
}
@Override
public void delete() {
System.out.println("删除一个用户");
}
@Override
public void update() {
System.out.println("更新一个用户");
}
@Override
public void query() {
System.out.println("查询一个用户");
}
}
添加一个需求,为每个方法添加一个日志功能,如何实现?
编写一个UserServiceProxy代理类
// 代理对象,在这里面增加日志的实现
public class UserServiceProxy implements UserService {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
public void insert() {
userService.insert();
this.log("新增");
}
@Override
public void delete() {
userService.delete();
this.log("删除");
}
@Override
public void update() {
userService.update();
this.log("更新");
}
@Override
public void query() {
userService.query();
this.log("查询");
}
// 日志功能的额外方法
private void log(String msg) {
System.out.println("[Debug] 这是" + msg + "的日志");
}
}
测试结果
public class Client {
public static void main(String[] args) {
// 真实的对象
UserService service = new UserServiceImpl();
// 代理对象
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(service);
// 通过代理对象实现了日志功能
proxy.insert();
proxy.delete();
proxy.update();
proxy.query();
}
}
通过上面的例子,我们已经基本了解了静态代理模式,就是:
我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想
AOP:纵向开发,横向开发
了解完静态代理后,你会发现每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类
所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理。
动态代理的概念
javasist
来生成动态代理,可以百度一下javasistJDK的动态代理需要了解两个类
核心:InvocationHandler
和Proxy
, 可以打开JDK帮助文档看看
【InvocationHandler:调用处理程序】
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
// proxy - 调用该方法的代理实例
// method -所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
// args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。
【Proxy : 代理】
// 生成代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
具体代码实现:房屋出租
抽象的接口
public interface Rent {
void rent();
}
真实的角色
public class Host implements Rent {
@Override
public void rent() {
System.out.println("出租房屋");
}
}
代理的角色
public class ProxyInvocationHandler implements InvocationHandler {
// 被代理的接口
private Object target;
public void setRent(Object target) {
this.target = target;
}
// proxy: 代理类。
// method: 代理类的调用处理程序的方法对象。
// 处理代理实例上的方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 核心:本质利用反射实现!
Object invoke = method.invoke(target, args);
return invoke;
}
// 生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
客户
public class Client {
public static void main(String[] args) {
// 真实的角色
Rent rent = new Host();
// 代理实例的调用处理程序
ProxyInvocationHandler handler = new ProxyInvocationHandler();
// 将真实角色放置进去!
handler.setRent(rent);
// 动态生成对应的代理类!
Rent proxy = (Rent) handler.getProxy();
proxy.rent();
}
}
使用动态代理的方式实现增删改查
因为我们自己编写的ProxyInvocationHandler.java
是一个通用的代理类
我们使用它实现代理之前的UserService就非常简单!
抽象的对象
// 抽象角色,增删改查
public interface UserService {
void insert();
void delete();
void update();
void query();
}
真实的对象
public class UserServiceImpl implements UserService {
@Override
public void insert() {
System.out.println("新增一个用户");
}
@Override
public void delete() {
System.out.println("删除一个用户");
}
@Override
public void update() {
System.out.println("更新一个用户");
}
@Override
public void query() {
System.out.println("查询一个用户");
}
}
代理的对象
public class UserServiceProxy implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(target, args);
// 执行后设置 log
this.log(method.getName());
return invoke;
}
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
// 添加一个log方法
private void log(String msg) {
System.out.println("[Debug] 这是" + msg + "的日志");
}
}
客户
public class Client {
public static void main(String[] args) {
// 真实的对象
UserService service = new UserServiceImpl();
// 代理对象
UserServiceProxy userServiceProxy = new UserServiceProxy();
userServiceProxy.setTarget(service);
UserService proxy = (UserService) userServiceProxy.getProxy();
// 通过代理对象实现了日志功能
proxy.insert();
proxy.delete();
proxy.update();
proxy.query();
}
}
我们可以发现,代理的对象类基本不用改变,只是添加了我们自己的log方法,就可以代理房屋出租,也可以代理UserService。这样我们只需要一个代理对象,就可以代理多个对象
动态代理的好处
静态代理有的它都有,静态代理没有的,它也有!
原文:https://www.cnblogs.com/paidaxing0623/p/14312602.html