zoukankan      html  css  js  c++  java
  • spring学习9-代理模式

    代理模式

    静态代理

    场景:

    服务层有增删查改功能,现在需要对增删改添加事务的支持。

    如果在基础的代码上修改的话会很麻烦,所以使用代理的模式

    1.抽象角色

    创建一个抽象角色,比如咋们平时做的用户业务,抽象起来就是增删改查!

    //抽象角色:增删改查业务
    public interface UserService {
        void add();
        void delete();
        void update();
        void query();
    }
    

    2.真实对象

    我们需要一个真实对象来模拟完成这些增删改查操作

    //真实对象,完成增删改查操作的人
    public class UserServiceImpl implements UserService {
        @Override
        public void add() {
            System.out.println("增加一个用户");
        }
    
        @Override
        public void delete() {
            System.out.println("删除一个用户");
        }
    
        @Override
        public void update() {
            System.out.println("更新一个用户");
        }
    
        @Override
        public void query() {
            System.out.println("查找一个用户");
        }
    }
    

    3.模拟事务

    public class MyTransaction {
        public void starTranSaction(){
            System.out.println("开启事务...");
        }
        public void closeTranSaction(){
            System.out.println("关闭事务...");
        }
    }
    

    4.代理角色

    设置一个代理类来模拟处理事务

    /代理角色,在这里面增加事务的支持
    public class UserServiceProxy implements UserService {
        private MyTransaction transaction = new MyTransaction();
        private UserServiceImpl userService;
        public void setUserService(UserServiceImpl userService) {
            this.userService = userService;
        }
    
        @Override
        public void add() {
            transaction.starTranSaction();
            userService.add();
            transaction.closeTranSaction();
        }
    
        @Override
        public void delete() {
            transaction.starTranSaction();
            userService.delete();
            transaction.closeTranSaction();
        }
    
        @Override
        public void update() {
            transaction.starTranSaction();
            userService.update();
            transaction.closeTranSaction();
        }
    
        @Override
        public void query() {
            userService.query();
        }
    }
    

    5.测试

        @Test
        public void test1() {
            UserServiceImpl userService = new UserServiceImpl();
            UserServiceProxy proxy = new UserServiceProxy();
            proxy.setUserService(userService);
            proxy.query();
            proxy.add();
            proxy.delete();
            proxy.update();
        }
    

    6.结果

    可以看到,查找的时候没有事务,其它的都添加了事务的支持

    查找一个用户
    开启事务...
    增加一个用户
    关闭事务...
    开启事务...
    删除一个用户
    关闭事务...
    开启事务...
    更新一个用户
    关闭事务...
    

    代理模式的优缺点:

    优点:

    • 可以使真实角色的操作更加纯粹,不用去关心一些公共的业务
    • 公共的业务交给了代理角色,实现业务分工
    • 公共业务发生扩展的时候,方便集中管理

    缺点:

    • 一个真实角色就会产生一个代理角色,代码量翻倍,开发效率变低

    这时候就可以考虑动态代理了

    动态代理

    • 动态代理的角色和静态代理的一样 .
    • 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
    • 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
      • 基于接口的动态代理----JDK动态代理
      • 基于类的动态代理--cglib
      • 现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist
      • 我们这里使用JDK的原生代码来实现,其余的道理都是一样的!

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

    核心 : InvocationHandler 和 Proxy , 打开JDK帮助文档看看

    InvocationHandler:调用处理程序

    Object invoke(Object proxy, 方法 method, Object[] args);
    //参数 
    //proxy - 调用该方法的代理实例 
    //method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。 
    //args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。 
    

    Proxy : 代理

    //生成代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                                      rent.getClass().getInterfaces(),this);
    }
    

    代码实现

    动态代理处理程序

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    //这是处理程序,不是代理类,可以通过这个处理程序生成一个带类
    public class UserServiceInvocationHandler implements InvocationHandler {
        private MyTransaction transaction = new MyTransaction();
        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 {
            if(method.getName().equals("query")){
                Object result = method.invoke(userService,args);
                return result;
            }else {
                transaction.starTranSaction();
                Object result = method.invoke(userService,args);//核心:本质利用反射实现!
                transaction.closeTranSaction();
                return result;
            }
        }
    }
    

    测试

    //动态代理
    @Test
    public void test2() {
        UserServiceImpl userService = new UserServiceImpl();//真实角色
        UserServiceInvocationHandler pih = new UserServiceInvocationHandler();//处理程序
        pih.setUserService(userService); //设置代理的对象
        UserService proxy = (UserService) pih.getProxy(); //动态生成对应的代理类!
        proxy.query();
        proxy.add();
        proxy.delete();
        proxy.update();
    }
    

    结果

    查找一个用户
    开启事务...
    增加一个用户
    关闭事务...
    开启事务...
    删除一个用户
    关闭事务...
    开启事务...
    更新一个用户
    关闭事务...
    

    核心:一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类,代理的是接口!、

    动态代理程序模板

    我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为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);
        }
        //处理代理实例,并返回结果
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            doSomething();//在真实对象的方法执行之前执行额外业务
            Object result = method.invoke(target,args);//通过反射生成代理对象
            return result;
        }
        //额外的业务
        private void doSomething(){
            System.out.println("run...");
        }
    }
    

    动态代理的好处

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

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

    爱生活,爱码字

    我是匆匆、我曾喂自己半年酒。

    好好生活吧,有缘或许相见。

  • 相关阅读:
    SQL Server需要监控哪些计数器
    将表里的数据批量生成INSERT语句的存储过程 继续增强版
    [Java]
    [Linux] 安装JBoss
    [Spring]
    [Spring]
    [Maven]
    [Maven]
    [Spring MVC]
    [Spring MVC]
  • 原文地址:https://www.cnblogs.com/ccoonngg/p/12026765.html
Copyright © 2011-2022 走看看