代理模式

通过代理控制对象的访问,可以在这个对象调用方法之前、调用方法之后去处理/添加新的功能。(也就是AOP的实现)

代理在原有代码乃至原业务流程都不修改的情况下,直接在业务流程中切入新代码,增加新功能,这也和Spring的(面向切面编程)很相似

应用场景:SpringAOP、日志打印、异常处理、事务控制、权限控制等

  • 静态代理 简单代理模式,是动态代理的理论基础。常见使用在代理模式

    /* 接口类 */
    public class UserDao {
        public void Save(){
            System.out.println("Save User Data");
        }
    }
    
    /* 代理类 */
    public class UserProxy extends UserDao{
        private UserDao user;
        public UserProxy(UserDao user){
            this.user = user;
        }
        public void Save(){
            System.out.println("Open transaction");
            this.user.Save();
            System.out.println("close transaction");
        }
    }
    
    /* 调用 */
    public class Demo {
        public static void main(String[] args){
            UserDao u = new UserDao();
            UserProxy userProxy = new UserProxy(u);
            userProxy.Save();
        }
    }
    
    • 缺点:每个需要代理的对象都需要自己重复编写代理
    • 优点:但是可以面相实际对象或者是接口的方式实现代理
  • JKD动态代理 基于接口的动态代理技术·:利用拦截器(必须实现invocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,从而实现方法增强

    /* 接口 */
    public interface IUserDao {
        void save();
    }
    
    /* 接口实现类 */
    public class UserDaoImpl implements IUserDao {
        @Override
        public void save() {
            System.out.println("Save User Data");
        }
    }
    
    /* 代理类 */
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    //每次生成动态代理类对象时实现InvocationHandler接口的调用处理器对象
    public class InvocationHandlerImpl implements InvocationHandler{
        //业务类实现类对象,用来调用具体的方法
        private Object target;
        //通过构造传入目标对象
        public InvocationHandlerImpl(Object target){
            this.target = target;
        }
        //动态代理实际运行得方法
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("调用开始处理");
            /* method.invoke(obj, args)方法是以反射的方式来创建对象的,
            第一个参数obj是要创建的对象,
            第二个args是构成方法的参数,决定创建对象使用哪个构造函数 */        
            Object result = method.invoke(target, args);        
            System.out.println("调用结束处理");
            return result;
        }
    }
    
    /* 调用 */
    public class Test {
        public static void main(String[] args){
            //被代理对象
            IUserDao uerDaoImpl = new UserDaoImpl();
            InvocationHandlerImpl invocationHandlerImpl 
                =  new InvocationHandlerImpl(uerDaoImpl);
            //类加载器
            ClassLoader loader = uerDaoImpl.getClass().getClassLoader();
            Class<?>[] interfaces = uerDaoImpl.getClass().getInterfaces();
            //主要装载器、一组接口及调用处理动态代理实例
            IUserDao newProxyInstance = (IUserDao)Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl);
            newProxyInstance.save();
        }
    }
    
    • 缺点:必须是面向接口,目标业务类必须实现接口
    • 优点:不用关心代理类,只需要在运行阶段才指定代理哪一个对象
posted @   WiThYouMr  阅读(12)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示