Spring:代理模式

8.代理模式

为什么要学习代理模式?

因为这是SpringAop的底层。

代理模式:

  • 代理类
  • 委托类
  • 调用者
  • 接口类

未使用代理模式:

当调用者要去调用委托类的方法时,直接通过委托类对象进行调用。

使用代理模式:

当调用者要去调用委托类的方法时,首先需要代理类委托类实现同一个接口,然后通过调用代理类的方法,去间接调用委托类的方法。
在这里插入图片描述

例子:

  • 租房人(调用者)—中介(代理类)-----房东(委托类) 接口:出租房子

  • 结婚的人(调用者)—婚庆公司(代理类)----结婚举办(委托类) 接口:布置结婚场地

代理类和委托类都要实现同一个接口

代理模式:

  • 静态代理
  • 动态代理

下面我们将会用房子租赁这个例子。去实现静态代理和动态代理。

8.1静态代理

分析:

  • 接口抽象类:房子出租Rent
  • 被代理的类(委托类):房东Host
  • 代理类:中介Proxy
  • 调用类:客户Client

8.1.1静态代理实现:

接口:Rent

//出租房子接口
public interface Rent {
   //出租房子
    void rent();
}

委托类:Host

//委托类:房东
public class Host implements Rent {
    //出租房子
    public void rent() {
        System.out.println("房东出租房子");
    }
}

代理类:Proxy

//代理类:中介
public class Proxy implements Rent{
    //代理对象
    private Rent host;

    //设置代理对象
    public void setHost(Rent host) {
        this.host = host;
    }

    //出租房子
    public void rent() {
        host.rent();
    }
}

调用类:Client

//调用者:客户
public class Client {
    public static void main(String[] args) {
        //联系中介
        Proxy proxy = new Proxy();
        //中介代理的房东
        proxy.setHost(new Host());
        //签订合同,完成房子出租
        proxy.rent();
    }
}

分析:中介类代理房东类,当客户需要租赁房子时,间接用过中介类租赁房东的房子。

8.1.2静态代理实现面向切面编程:

面向切面编程的一些基本概念:

  • 目标对象target:被增强的对象。

  • 代理类:增强后的对象。

  • 通知Advice:就是增强类,增强代码所在的类。

  • 织入:是个动词,就是把增强的代码织入到被代理对象的过程

  • 连接点:目标对象中的每一个方法都是连接点。

  • 切入点:目标对象中被增强的方法是切入点。

  • 切面:切面就是切入点和通知的组合。

业务接口:

//业务接口
public interface UserDao {
    //添加用户
    void addUser();
    //删除用户
    void deleteUser();
    //查询用户
    void searchUser();
    //更新用户
    void UpdateUser();
}

业务类:

//业务实现:目标类,目标类的每个方法都可以时连接点,当被增强后的方法被称为切入点
public class UserDaoImpl implements UserDao {
    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
    }

    public void searchUser() {
        System.out.println("查询用户");
    }

    public void UpdateUser() {
        System.out.println("更新用户");
    }
}

业务代理类:

//业务代理:代理类,代理可以增加代理对象的方法
public class UserDaoProxy implements UserDao {
    //代理对象
    private UserDao userDao;
    //切面
    private MyAspect myAspect;
    //设置切面
    public void setMyAspect(MyAspect myAspect) {
        this.myAspect = myAspect;
    }

    //设置代理对象
    public void setUserDao(UserDao userDao) {

        this.userDao = userDao;
    }

    public void addUser() {
        myAspect.beforeLog();
        userDao.addUser();
        myAspect.afterLog();
    }

    public void deleteUser() {
        myAspect.beforeLog();
        userDao.deleteUser();
        myAspect.afterLog();
    }

    public void searchUser() {
        myAspect.beforeLog();
        userDao.searchUser();
        myAspect.afterLog();
    }

    public void UpdateUser() {
        myAspect.beforeLog();
        userDao.UpdateUser();
        myAspect.afterLog();
    }
}

切面类:

//切面
public class MyAspect {
    //切入的方法,即通知
    public void beforeLog(){
        System.out.println("前置日志");
    }
    //切入的方法,即通知
    public void afterLog(){
        System.out.println("后置日子");
    }
}

调用类:

//调用者
public class UserService {
    public static void main(String[] args) {
        //获得代理类
        UserDaoProxy userDaoProxy = new UserDaoProxy();
        //设置代理对象
        userDaoProxy.setUserDao(new UserDaoImpl());
        //设置切面
        userDaoProxy.setMyAspect(new MyAspect());
        //调用方法
        //添加用户
        System.out.println("================");
        userDaoProxy.addUser();
        //删除用户
        System.out.println("================");
        userDaoProxy.deleteUser();
        //查询用户
        System.out.println("================");
        userDaoProxy.searchUser();
        //更新用户
        System.out.println("================");
        userDaoProxy.UpdateUser();
    }
}

在这里插入图片描述

结果:image-20201128004620320

8.1.3总结

静态代理模式的优点:

  • 以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
  • 公共的业务由代理来完成 . 实现了业务的分工 ,
  • 公共业务发生扩展时变得更加集中和方便 .

缺点:

  • 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .

为了解决静态代理的缺点,我们可以通过动态代理实现。

下面对动态代理进行讲解。

8.2动态代理

  • 代理类动态生成
  • 动态代理分类:
    • 基于接口的动态代理:jdk代理
    • 基于类的动态代理: cglib
    • java字节码实现:javasist

8.2.1jdk代理

jdk需要两个类:

  • 代理创建类:java.lang.reflect.Proxy

    • 用于动态创建代理类,newProxyInstance()
  • 调用处理程序接口:java.lang.reflect.InvocationHandler

    • 所有动态创建的代理类调用方法时,都会交给指定实现该接口的类处理

用图理解:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e2137LaE-1612345680959)(Spring.assets/image-20201128023806966.png)]

动态代理实现:

Rent接口:

public interface Rent {
    void rent();
}

Host类:

public class Host implements Rent {
    public void rent() {
        System.out.println("房东出租房子");
    }
}

代理类:

public class JdkProxy implements InvocationHandler {
    private Rent rent;

    public Object createProxy(Rent rent){
        this.rent = rent;
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = method.invoke(rent, args);
        return  object;
    }
}

调用者:

public class Client {
    public static void main(String[] args) {
        JdkProxy jdkProxy = new JdkProxy();
        Rent proxy = (Rent)jdkProxy.createProxy(new Host());
        proxy.rent();
    }
}
动态代理实现面向切面编程:

接口:

//业务接口
public interface UserDao {
    //添加用户
    void addUser();
    //删除用户
    void deleteUser();
    //查询用户
    void searchUser();
    //更新用户
    void UpdateUser();
}

切面:

//切面
public class MyAspect {
    //切入的方法,即通知
    public void beforeLog(){
        System.out.println("前置日志");
    }
    //切入的方法,即通知
    public void afterLog(){
        System.out.println("后置日子");
    }
}

实现类:

//业务实现:目标类,目标类的每个方法都可以时连接点,当被增强后的方法被称为切入点
public class UserDaoImpl implements UserDao {
    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
    }

    public void searchUser() {
        System.out.println("查询用户");
    }

    public void UpdateUser() {
        System.out.println("更新用户");
    }
}

代理类:

public class UserDaoProxy implements InvocationHandler {
    private Object object;
    private MyAspect myAspect;

    public void setObject(Object object) {
        this.object = object;
    }

    public void setMyAspect(MyAspect myAspect) {
        this.myAspect = myAspect;
    }

    public Object createProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        myAspect.beforeLog();
        Object obj = method.invoke(object, args);
        myAspect.afterLog();
        return obj;
    }
}

调用类:

public class UserDaoService {
    public static void main(String[] args) {
        //动态代理创建类
        UserDaoProxy userDaoProxy = new UserDaoProxy();
        //设置切面
        userDaoProxy.setMyAspect(new MyAspect());
        //设置代理对象
        userDaoProxy.setObject(new UserDaoImpl());
        //增强类
        UserDao proxy = (UserDao) userDaoProxy.createProxy();
        //调用方法
        //添加用户
        System.out.println("================");
        proxy.addUser();
        //删除用户
        System.out.println("================");
        proxy.deleteUser();
        //查询用户
        System.out.println("================");
        proxy.searchUser();
        //更新用户
        System.out.println("================");
        proxy.UpdateUser();
    }
}

8.2.3cglib代理

动态代理实现:
//代理类
public class CglibProxy implements MethodInterceptor {
    //创建代理对象
    public Object createProxy(Rent rent){
        //创建一个动态类对象
        Enhancer enhancer = new Enhancer();
        //设置父类,即增强的类
        enhancer.setSuperclass(rent.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建代理对象
        return enhancer.create();
    }
    //回调函数
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object o1 = methodProxy.invokeSuper(o, objects);
        return o1;
    }
}
@Test
public void cglibProxy(){
    CglibProxy cglibProxy = new CglibProxy();
    Rent proxy = (Rent) cglibProxy.createProxy(new Host());
    proxy.rent();
}
动态代理实现面向切面编程:
public class UserDaoProxy1 implements MethodInterceptor {
    public Object createProxy(Object o){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(o.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        MyAspect myAspect = new MyAspect();
        myAspect.beforeLog();
        Object o1 = methodProxy.invokeSuper(o, objects);
        myAspect.afterLog();
        return o1;
    }
}

动态代理的优点:

静态代理有的它都有,静态代理没有的,它也有!

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
  • 公共的业务由代理来完成 . 实现了业务的分工 ,
  • 公共业务发生扩展时变得更加集中和方便 .
  • 一个动态代理 , 一般代理某一类业务
  • 一个动态代理可以代理多个类,代理的是接口
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值