初识Spring(七) | 代理模式

代理模式

AOP面向切面编程的底层思想就是代理模式,理解代理模式对理解AOP模式很有帮助。

代理模式分为:

  • 静态代理
  • 动态代理

用UML图来简单描述一下

1620532272119

1 静态代理

静态代理角色分析

  • 抽象角色 : 一般使用接口或者抽象类来实现

  • 真实角色 : 被代理的角色

  • 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .

  • 客户 : 使用代理角色来进行一些操作 .

静态代理实例一:

  1. 抽象角色Rent

    public interface Rent {
        public void rent();
    }
    
  2. 真实角色Host

    public class Host implements Rent {
        public void rent() {
            System.out.println("房屋出租");
        }
    }
    
  3. 代理角色Proxy

    public class Proxy implements Rent {
        private Host host;
    
        public Proxy() {
        }
    
        public Proxy(Host host) {
            this.host = host;
        }
    
        @Override
        public void rent() {
            seeHouse();
            host.rent();
            fare();
        }
    
        //看房
        public void seeHouse() {
            System.out.println("带房客看房");
        }
    
        //收中介费
        public void fare() {
            System.out.println("收中介费");
        }
    }
    
  4. 客户client

    public class Client {
        public static void main(String[] args) {
            //房东要租房 
            Host host = new Host();
            //中介帮助房东 
            Proxy proxy = new Proxy(host); 
            //你去找中介! 
            proxy.rent(); 
        } 
    }
    

    **理解:**代理模式中,真实角色和代理角色共同实现租房这一抽象接口,真正拥有租房权限的是真实角色,因为代理角色找到了真实角色,真实角色将租房这一权限给代理。

    • **优点:**代理角色除了代理了租房这一功能还可以提供其他的一些附加功能,比如签合同,看房等,这是真实角色不想做的事情,但是却不会影响他本身的租房功能。

静态代理实例二:

  1. 抽象接口UserService

    public interface UserService {
        void add();
    
        void delete();
    
        void update();
    
        void query();
    }
    
  2. 真实角色UserServiceImpl

    public 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("查询了一个用户");
        }
    }
    
  3. 代理角色UserServiceImplProxy

    public class UserServiceImplProxy implements UserService{
        private UserServiceImpl userServiceImpl;
    
        public void setUserServiceImpl(UserServiceImpl userServiceImpl) {
            this.userServiceImpl = userServiceImpl;
        }
    
    
        @Override
        public void add() {
            log("add");
            userServiceImpl.add();
        }
    
        @Override
        public void delete() {
            log("delete");
            userServiceImpl.delete();
        }
    
        @Override
        public void update() {
            log("update");
            userServiceImpl.update();
        }
    
        @Override
        public void query() {
            log("query");
            userServiceImpl.query();
        }
    
        public void log(String message){
            System.out.println("执行了"+message);
        }
    }
    
    
  4. 客户端

    public static void main(String[] args) {
            //真实业务
            UserServiceImpl userService = new UserServiceImpl();
            //代理类
            UserServiceImplProxy proxy = new UserServiceImplProxy();
            //使用代理类实现日志功能!
            proxy.setUserServiceImpl(userService);
            proxy.add();
        }
    

**理解:**和之前的静态代理案例一一样,通过代理角色的方式,在实现真实角色功能的基础上,不影响的增加一些代理功能。

  • 这也是AOP底层的实现机制

2 动态代理

就和在mybatis时做分页一样,当分页的类型多的时候,我们不希望为每一种类型都增加一个分页类,这个时候我们使用泛型的方式来实现不同类型数据的返回匹配。

  • 动态代理的角色和静态代理的一样 .

  • 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的

  • 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理

    • 基于接口的动态代理----JDK动态代理

    • 基于类的动态代理–cglib

    • 现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist

JDK的动态代理需要了解两个类

核心 : InvocationHandlerProxy

使用方式:

//代理角色:中介
public class ProxyInvocationHandler 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 object = method.invoke(rent,args);
        fare();
        return object;
    }

    //看房
    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();
    }
}
  • 通过这样的方式,我们就可以动态的代理Rent这一类的对象了。

除了代理这一类的方法,有时候我们希望能够实现所有对象的代理,这个时候我们可以把Rent改为Object类型,这样就可以代理所有的对象类型了。

使用方法:

public class ProxyInvocationHandler 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);
    }

    // proxy : 代理类  method : 代理类的调用处理程序的方法对象. 
    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 methodName) {
        System.out.println("执行了" + methodName + "方法");
    }
}
public class Test {
    public static void main(String[] args) {
        //真实对象 
        UserServiceImpl userService = new UserServiceImpl();
        //代理对象的调用处理程序 
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(userService);
        //设置要代理的对象
        UserService proxy = (UserService)pih.getProxy();
        //动态生成代理类! 
        proxy.delete(); 
    } 
}

3 小结

就和工具类一样,动态代理可以很方便的动态完成一些有需求变更和频繁使用的工作。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值