zoukankan      html  css  js  c++  java
  • 代理模式

    1.正常接口实现

    接口

    public interface IUserDao {
        public void save();
    }

    实现接口

    public class UserDao implements IUserDao{
    
        @Override
        public void save() {
            System.out.println("保存入数据库成功");
        }
    
    }

    调用使用

    //正常情况
            IUserDao userDao=new UserDao();
            userDao.save();

    结果:

    保存入数据库成功;

    2.静态代理模式

    接口一样:

    public interface IUserDao {
        public void save();
    }

    实现接口由代理类实现,初始化赋予权限,一样要实现接口

    public class StaticProxy implements IUserDao{
        private IUserDao userDao;
        public StaticProxy(IUserDao userDao) {
            this.userDao=userDao;
        }
        @Override
        public void save() {
            System.out.println("事务开始");
            userDao.save();
            System.out.println("事务结束");
        }
    
    }

    同样是调用实现

    IUserDao userDao=new UserDao();
    //静态代理
            StaticProxy staticProxy=new StaticProxy(userDao);
            staticProxy.save();

    结果:

    事务开始
    保存入数据库成功
    事务结束

    优点:可以对目标功能进行扩展,实现AOP切面编程,插入代码,不影响原有功能。

    缺点:要是接口有很多方法,会导致代理类很多,万一接口有变动(比如更改一个返回类型int),对应方法的代理类就要维护更新。下面的动态代理就可以解决这个问题。

    3、动态代理

    利用反射机制,代理类所在包:java.lang.reflect.Proxy

    核心方法

    static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

    第一个参数为类加载器,第二个为实现方法的接口,第三个是代理类

    同样,还是原来的接口

    public interface IUserDao {
        public void save();
    }

    原来的接口实现类

    public class UserDao implements IUserDao{
    
        @Override
        public void save() {
            System.out.println("保存入数据库成功");
        }
    
    }

    创建动态代理的类同时实现接口InvocationHandler,这个 是代理实例的调用处理程序 实现的接口,重写一下唯一的一个invoke方法。

    public class UserProxy implements InvocationHandler{
        private IUserDao userDao;
        public UserProxy(IUserDao userDao) {
            this.userDao=userDao;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("动态代理");
            System.out.println("开始事务");
            Object invoke = method.invoke(userDao, args);
            System.out.println("结束事务");
            return invoke;
        }
    
    }

    测试:

    public class Test {
        public static void main(String[] args) {
            IUserDao userDao=new UserDao();
    
            //代理情况(不用继承也可以调用接口的方法)
            ClassLoader classLoader = UserDao.class.getClassLoader();
            IUserDao Iproxy=(IUserDao) Proxy.newProxyInstance(classLoader, UserDao.class.getInterfaces(), new UserProxy(userDao));
            Iproxy.save();
    
        }
    }

    动态生成代理对象Iproxy,就可以调用相应的方法了。

    结果:

    动态代理
    开始事务
    保存入数据库成功
    结束事务


     

    如果改了接口返回类型为int,那么

    接口:

    public interface IUserDao {
        public int save();
    }

    接口实现类就这样:

    public class UserDao implements IUserDao{
        @Override
        public int save() {
            System.out.println("保存入数据库成功");
            return 110;
        }
    
    }

    动态代理类不变

    测试类:打印一下返回值

    public class Test {
        public static void main(String[] args) {
            IUserDao userDao=new UserDao();
            //代理情况(不用继承也可以调用接口的方法)
            ClassLoader classLoader = UserDao.class.getClassLoader();
            IUserDao Iproxy=(IUserDao) Proxy.newProxyInstance(classLoader, UserDao.class.getInterfaces(), new UserProxy(userDao));
            int save = Iproxy.save();
            System.out.println(save);
    
        }
    }

    结果:多了个110

    动态代理
    开始事务
    保存入数据库成功
    结束事务
    110

    可以发现不用改动态代理的类,省事。当然,大部分情况我们都会对这些进行封装,使用就更简单了。

  • 相关阅读:
    WebView自适应屏幕
    shell脚本:遍历删除
    查看Mysql执行计划
    Spring 源码学习(八) AOP 使用和实现原理
    Java:控制反转(IoC)与依赖注入(DI)
    浏览器-开发者工具
    查看kafka消息消费情况
    shell脚本:遍历删除文本内路径上文件
    聚簇索引与非聚簇索引(也叫二级索引)
    有关MySQL
  • 原文地址:https://www.cnblogs.com/lq625424841/p/7170775.html
Copyright © 2011-2022 走看看