代理模式
即Proxy Pattern,23种java常用设计模式之一。代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问。
代理模式也是SpringAOP的底层
代理模式分类:
- 静态代理
- 动态代理
1、静态代理
角色分析:
- 抽象角色(Rent):一般使用接口或者抽象类
- 真实角色(Host):被代理的真实角色
- 代理角色(Proxy):中介,真实的代理的角色,且其一般还会添加一些附属操作
- 客户(User):访问代理对象的用户
-
新建一个抽象角色类:Rent.java
package pers.mobian.proxy.demo1; public interface Rent { public void rent(); }
-
新建一个真实角色类:Host.java
package pers.mobian.proxy.demo1; public class Host implements Rent { @Override public void rent() { System.out.println("我是房东,我有房子出租"); } }
-
新建一个代理角色类:Proxy.java
package pers.mobian.proxy.demo1; public class Proxy implements Rent{ private Host host = new Host(); @Override public void rent() { seeHouse(); host.rent(); signContract(); } private void seeHouse(){ System.out.println("中介带你看房子"); } private void signContract(){ System.out.println("中介帮忙签合同"); } }
-
新建一个用户测试类:User.java
package pers.mobian.proxy.demo1; public class User { public static void main(String[] args) { Proxy proxy = new Proxy(); proxy.rent(); } }
-
测试结果
中介带你看房子 我是房东,我有房子出租 中介帮忙签合同
代理模式的优点:
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共的业务交给了代理角色,实现了业务的分工
- 公共业务发生扩展的时候,方便进行集中管理
缺点:
- 一个真实角色会产生一个代理角色,开发效率变低
2、静态代理加强版
角色分析:
- 抽象角色(UserService):包含增删改查四个方法
- 真实角色(UserServiceImpl):增删改查的具体实现
- 代理角色(Proxy):中介,真实的代理的角色,添加打印功能
- 客户(User):访问代理对象的用户
-
抽象角色:UserService.java
package pers.mobian.proxy.demo2; public interface UserService { public void add(); public void delte(); public void update(); public void selet(); }
-
真实角色:UserServiceImpl.java
package pers.mobian.proxy.demo2; public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("使用了增加方法"); } @Override public void delte() { System.out.println("使用了删除方法"); } @Override public void update() { System.out.println("使用了修改方法"); } @Override public void selet() { System.out.println("使用了查找方法"); } }
-
代理角色:Proxy.java
package pers.mobian.proxy.demo2; public class Proxy implements UserService { private UserServiceImpl userServiceImpl; public void setUserServiceImpl(UserServiceImpl userServiceImpl) { this.userServiceImpl = userServiceImpl; } public Proxy(UserServiceImpl userServiceImpl) { this.userServiceImpl = userServiceImpl; } public Proxy() { } @Override public void add() { userServiceImpl.add(); show("add"); } @Override public void delte() { userServiceImpl.delte(); show("delte"); } @Override public void update() { userServiceImpl.update(); show("update"); } @Override public void selet() { userServiceImpl.selet(); show("selet"); } public void show(String method){ System.out.println(method+"方法使用成功"); } }
-
客户:User.java
package pers.mobian.proxy.demo2; public class User { public static void main(String[] args) { UserServiceImpl userServiceImpl = new UserServiceImpl(); Proxy proxy = new Proxy(userServiceImpl); proxy.add(); proxy.delte(); proxy.selet(); proxy.update(); } }
-
测试结果
使用了增加方法 add方法使用成功 使用了删除方法 delte方法使用成功 使用了查找方法 selet方法使用成功 使用了修改方法 update方法使用成功
实际开发中的模型(仅供参考)
3、动态代理
- 动态代理和静态代理角色相同
- 动态代理的代理是动态生成的,不是我们直接写出来的
- 动态代理分类:
- 基于接口的:JDK动态代理
- 基于类:cglib
- java字节码实现:javassist
需要了解两个类:Proxy:代理 , InvocationHandler:调用处理程序
动态代理的好处:
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共的业务交给了代理角色,实现了业务的分工
- 公共业务发生扩展的时候,方便进行集中管理
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要实现了同一个接口即可
角色分析:
- 抽象角色(Rent):一般使用接口或者抽象类
- 真实角色(Host):被代理的真实角色
- 动态代理角色(ProxyInvocationHander):可以动态代理一个接口下的所有操作
- 客户(User):访问代理对象的用户
-
抽象角色:Rent.java
package pers.mobian.proxy.demo3; public interface Rent { public void rent(); }
-
真实角色:Host.java
package pers.mobian.proxy.demo3; public class Host implements Rent { @Override public void rent() { System.out.println("我是房东,我有房子出租"); } }
-
动态代理角色:ProxyInvocationHander.java
package pers.mobian.proxy.demo3; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHander implements InvocationHandler { //被代理的接口 private Rent rent; public void setRent(Rent rent) { this.rent = rent; } //通过接口得到代理类 public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this); } //对代理实例添加附属操作,并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { seeHouse(); Object result = method.invoke(rent, args); signContract(); return result; } private void seeHouse(){ System.out.println("中介带你看房子"); } private void signContract(){ System.out.println("中介帮忙签合同"); } }
-
客户:User.java
package pers.mobian.proxy.demo3; public class User { public static void main(String[] args) { Rent rent = new Host(); ProxyInvocationHander pih = new ProxyInvocationHander(); pih.setRent(rent); Rent proxy = (Rent) pih.getProxy(); proxy.rent(); } }
-
测试结果
中介带你看房子 我是房东,我有房子出租 中介帮忙签合同
4、动态代理类加强版
角色分析:
- 抽象角色(UserService):包含增删改查四个方法
- 真实角色(UserServiceImpl):增删改查的具体实现
- 代理角色(Proxy):中介,真实的代理的角色,添加打印功能
- 客户(User):访问代理对象的用户
-
抽象角色:UserService.java
package pers.mobian.proxy.demo2; public interface UserService { public void add(); public void delte(); public void update(); public void selet(); }
-
真实角色:UserServiceImpl.java
package pers.mobian.proxy.demo2; public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("使用了增加方法"); } @Override public void delte() { System.out.println("使用了删除方法"); } @Override public void update() { System.out.println("使用了修改方法"); } @Override public void selet() { System.out.println("使用了查找方法"); } }
-
代理角色:Proxy.java
package pers.mobian.proxy.demo4; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHander implements InvocationHandler { //被代理的接口 private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } //通过接口得到代理类 public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), userService.getClass().getInterfaces(), this); } //对代理实例添加附属操作,并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(userService, args); //通过反射获得具体的方法名 log(method.getName()); return result; } public void log(String method) { System.out.println(method+"方法使用成功"); } }
-
客户:User.java
package pers.mobian.proxy.demo4; public class User { public static void main(String[] args) { UserService userServiceImpl = new UserServiceImpl(); ProxyInvocationHander pih = new ProxyInvocationHander(); pih.setUserService(userServiceImpl); UserService userService = (UserService)pih.getProxy(); userService.add(); userService.delte(); userService.update(); userService.selet(); } }
-
测试结果
使用了增加方法 add方法使用成功 使用了删除方法 delte方法使用成功 使用了修改方法 update方法使用成功 使用了查找方法 selet方法使用成功
总结:在静态代理的基础上,每次添加一个真实角色,就需要一个对应的代理类来执行相应的代理操作。当使用动态代理类以后,不再拥有实际的代理类,而是使用真实角色的功能,即抽象角色(也就是接口),最终使用户能够控制所有的继承了这个接口的真实类。解决了静态代理的缺点,避免了代码的臃肿。
5、改良版的动态代理类模板
将所有的接口变成Object类,继而达到复用的效果
package pers.mobian.proxy.demo4;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHander implements InvocationHandler {
//被代理的接口
private Object target;
public void setUserService(Object target) {
this.target = target;
}
//通过接口得到代理类
public Object getProxy() {
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);
return result;
}
}
标签:java,角色,void,代理,模式,proxy,public
From: https://blog.51cto.com/u_15942107/6017177