何为代理模式?
代理模式是通过创建一个代理对象,用这个代理对象去代表真实的对象,客户端得到这个代理对象这个,对客户端并没有什么影响,就像得到真实的对象来使用
代理分为静态代理和动态代理,我们先来看看静态代理,来一个租房的案例
静态代理的角色分析:
- 抽象角色:一般用接口或者抽象类来扮演
- 真实角色:被代理的角色
- 代理角色:代理真实角色,一般会添加一些附属操作
- 客户:访问代理对象
//抽象的角色
public interface Rent{
void rent();
}
//真实角色
public class Host implements Rent{
public void rent(){
System.out.println("房东出租房子")
}
}
//代理角色
public class Proxy implements Rent{
private Host host;
public Proxy(Host host){
this.host=host;
}
public void rent(){
seeHouse();
host.rent();
fare();
}
//看房-----中介自有的方法,房东没有
public void seeHouse(){
System.out.println("中介带你看房");
}
//收中介费-----中介自有的方法,房东没有
public void fare(){
System.out.println("收中介费");
}
}
//客户
public class Client{
public static void main(String[] args){
Host host=new Host();
host.rent(); //传统情况下,我们直接找房东租房
}
}
//使用代理模式
public class Client{
public static void main(String[] args){
Host host=new Host();
//代理,中介帮房东出租房子,代理角色一般会有附属操作
Proxy proxy=new Proxy(host);
//你不用面对房东,直接找中介租房
proxy.rent();
}
}
使用代理模式有哪些好处呢?
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共交给代理角色,实现业务分工
- 公共业务发生扩展的时候,方便集中管理
使用代理模式缺点:
一个真实角色就需要代理对象,耗费资源
静态代理加深理解,用比较常见的Service层来讲解
//抽象角色
public interface UserService{
public void add();
public void delete();
public void update();
public void query();
}
//真实对象
publci class UserServiceImpl implements UserService{
public void add(){
System.out.println("增加了一个用户");
}
public void delete(){
System.out.println("删除了一个用户");
}
public void update(){
System.out.println("更新了一个用户");
}
public void query(){
System.out.println("查询了一个用户");
}
}
//代理类,在不改变原来的业务代码基础上,增加功能
public class UserServiceProxy implements UserService{
public void add(){
log("add");
System.out.println("增加了一个用户");
}
public void delete(){
log("delete");
System.out.println("删除了一个用户");
}
public void update(){
log("update");
System.out.println("更新了一个用户");
}
public void query(){
log("query");
System.out.println("查询了一个用户");
}
publci void log(String msg){
System.out.println(msg);
}
}
//客户
public class Client{
UserService userService=new UserServiceImpl();
userService.add(); //传统调用方法
}
public class Client{
UserService userService=new UserServiceProxy();
userService.add(); //代理对象调用方法
}
使用 代理模式后我们可以在不改变原有基础的逻辑上,增加了一个打印日志的功能
接下来说说动态代理,动态代理和静态代理中的角色是一样的,只不过区别是,动态代理中的代理类是动态生成的,而不是像静态代理中有开发人员自己编写。动态代理主要分为两大类,一个是基于接口的动态代理,也就是我们所说的JDK的动态代理;另一类是基于类的动态代理,也就是cglib。
我们都知道SpringAOP的底层就是动态代理,没有默认实现的方式,具体使用的那种动态代理方式,主要还是看代理的是类还是接口。是接口的话,使用的就是JDK的动态代理,是类的话,使用的就是cglib的动态代理
还是再来看看刚刚租房的案例,使用动态代理是如何实现的吧
//抽象的角色
public interface Rent{
void rent();
}
//真实角色
public class Host implements Rent{
public void rent(){
System.out.println("房东出租房子")
}
}
//代理处理器
public class ProxyInvocationHandle 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);
}
//处理代理实例,并且返回结果
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
//动态代理的本质,基于反射实现
seeHouse();
Object result=method.invoke(rent,args);
fare();
return result;
}
public void seeHouse(){
System.out.println("中介带看房子");
}
public void fare(){
System.out.println("收中介费");
}
}
//客户类
public class Client{
public static void main(String[] args){
//真实角色
Host host=new Host();
//代理处理器
ProxyInvocationHandler pih=new ProxyInvocationHandler();
//通过代理处理器处理要调用的接口对象
pih.setRent(host);
Rent proxy=(Rent) pih.getProxy();
proxy.rent();
}
}
自己写动态代理的话,我们需要去实现一个InvocationgHandler接口,动态代理的本质是反射。
//抽象角色
public interface UserService{
public void add();
public void delete();
public void update();
public void query();
}
//真实角色
public class Host implements Rent{
public void rent(){
System.out.println("房东出租房子")
}
}
//代理处理器
public class ProxyInvocationHandle implements InvocationHandler{
//被代理的接口,抽象角色
private Object target;
public void setTarget(Object target){
this.target=target;
}
//生成代理类
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(msg+"方法执行了");
}
}
public class Client{
public static void main(String[] args){
//真实角色
UserServiceImpl userServiceImpl=new UserServiceImpl();
//代理处理器
ProxyInvocationHandler pih=new ProxyInvocationHandler();
pih.setTarget(userServiceImpl);
UserService proxy=(UserService)pih.getProxy();
proxy.query();
}
}
动态代理的好处:
可以使真实对象的操作更加纯粹,不用去关注一些公共的业务
公共交给代理角色,实现业务分工
公共业务发生扩展的时候,方便集中管理
一个动态代理类代理一个接口,一般就是对应一类的业务
一个动态代理类可以代理多个类,不像静态代理那样,一个代理类代理一个角色